将两个值相乘并将它们打印到屏幕上(NASM,Linux)

时间:2012-06-29 23:23:35

标签: assembly x86-64 nasm cpu-registers

我一直在阅读为了让寄存器执行整数/浮点除法,执行的寄存器实际上需要initialized。我很好奇正确的汇编程序指令是做什么的。我只是通过以下内容提供地址:

mov ecx, 0x65F ;0x65F represents an address for ecx to point to

然后及时(稍后在代码中)做类似的事情:

mov byte [ecx], 0xA ;move the value of 0xA into the contents of ecx, using only a byte's worth of data

这是执行此类操作的正确方法吗?如果没有,那是什么?

更新

好的,所以我要做的就是将两个值相乘并将它们打印到屏幕上。 代码如下,由于某种原因,每当我尝试划分edx时,我会得到分段错误或浮点算术异常。有人可以向我解释我做错了什么吗?

代码

section .data
    counter: db 0xA                         ;store value 10 in 'counter', while allocating only one byte. This will be used for decrementing purposes
section .bss
    valueToPrint: resb 4                    ;alloc 4 bytes of data in 'valueToPrint'

section .text

global _start

_print_char:                    
    add eax, '0'                ;convert to ascii
    mov [valueToPrint], eax     ;store contents of 'eax' in valueToPrint
    mov eax, 4                  ;syswrite
    mov ebx, 1                  ;stdout
    mov ecx, valueToPrint       ;machine will take whatever value exists in 'ecx' and print
    mov edx, 1                  ;print only a single byte's worth of data
    int 0x80                    ;invoke kernel to perfrom instruction
    ret                         

_convert_values:
    mov edx, 0xA                ;dividing eax by 10, which will lower its tens place
    div edx                     ;(**Program crash here**)do division: remainder SHOULD be stored in edx
    mov byte [edx], 0x0         ;zero out edx       
    call _print_char            ;do printing for latest character
    dec byte [counter]          ;decrement counter
    mov dword [eax], counter    ;store counter in eax
    jnz _convert_values         ;while eax > 0 continue process

_endl:
    mov eax, '\n'               ;store newline character in eax to be printed
    call _print_char            ;print value
    ret                 

_mul:
    mov eax, 0x2A ;store 42 in eax
    mov edx, 0x2B ;store 43 in edx
    mul edx       ;multiply [eax] * [edx]
    ret

_safe_exit:
    mov eax, 1  ;initiate 'exit' syscall
    mov ebx, 0  ;exit with error code 0
    int 0x80    ;invoke kernel to do its bidding 

_start:
    nop                             ;used to keep gdb from complaining

    call _mul                       ;multiply the values
    call _convert_values            ;do hex to ascii conversion

    jmp _safe_exit                  ;use jmp as opposed to call since it technically doesn't 'ret'

1 个答案:

答案 0 :(得分:4)

我们在聊天中分别发言....

这是一个可以使用的工作版本。

它有一个微妙的问题。你能找到吗? 你能解释它为什么做它的作用吗?

; Multiply two numbers, display in ascii/decimal
;
; (because I have a 64bit system, this forces 32bit code)
        bits    32
;
        section .text
;
; _start is the ONLY label you MUST prepend _
; others might be library functions (ex: _printf,_exit)
; pure assembly only needs _start, if linked with glibc
; typically need _main INSTEAD of _start
;
        global _start
;
;
_start:
        nop                             ;placeholder for gdb's debug interrupt
;
        call    mul                     ;multiply the values
        call    convert_values          ;do hex to ascii conversion
;
        jmp     safe_exit               ;use jmp as opposed to call since it technically doesn't 'ret'
;
;
; subroutines / functions follow
;
mul:
        mov     eax, 0x2A               ;store 42 in eax
        mov     edx, 0x2B               ;store 43 in edx (42*43=1806)
        mul     edx                     ;multiply eax*edx, result in edx:eax
        ret
;
; this routine doesn't handle BIG values from 'mul' which extend into edx
; we're learning, don't make things multiply out to more than 4.2 billion-ish
convert_values:
        mov     edx,0                   ;value actually edx:eax, zero edx
        mov     ecx,0x0A                ;divide edx:eax by 10
        idiv    ecx                     ;result in eax, remainder in edx
        push    eax                     ;save value on stack
        mov     eax,edx                 ;put remainder (0-9) in eax
        add     eax,'0'                 ;convert value to ascii character
        call    print_char              ;print the latest character
        pop     eax                     ;restore value
        or      eax,eax                 ;set flags based on eax value
        jnz     convert_values          ;while eax != 0 continue process
;
; nasm doesn't convert \n into LF... just use 10, equivalent
endl:
        mov     eax, 10                 ;store newline character in eax to be printed
        call    print_char              ;print value
        ret
;
print_char:
        mov     [valueToPrint], eax     ;store contents of 'eax' in [valueToPrint]
        mov     eax, 4                  ;syswrite
        mov     ebx, 1                  ;stdout
        mov     ecx, valueToPrint       ;machine will take whatever value exists in [ecx] and print
        mov     edx, 1                  ;print only a single byte's worth of data
        int     0x80                    ;invoke kernel to perfrom instruction
        ret
;
safe_exit:
        mov     eax,1                   ;initiate 'exit' syscall
        mov     ebx,0                   ;exit with error code 0
        int     0x80                    ;invoke kernel to do its bidding
;
; =====================================
        section .bss
; this section is not allocated, just reserved.
; Automatically set to zero when program starts
;
; alloc 4 bytes of data in 'valueToPrint'
valueToPrint:
        resd    1               ; 1 resd=4 resb (Dword/Byte)
;
;
  

扰流警报......

     
    

打印结果BACKWARDS!
 要解决这个问题,我们必须重新设计如何获得数字  并在打印前存储。

  

我正在通过电子邮件直接发送给您,以及一些其他说明。