NASM 32位:printf打印寄存器内容

NASM 32-bit: printing content of register by printf

我是装配新手。对于遵循我预期的简单代码,我有不同的输出。每次调用 printf 之前,eax 的内容都会向右移动一些数字。我究竟做错了什么?谢谢。

代码:

;file name : testing.asm
;assemble and link with:
;nasm -f elf testing.asm && gcc -m32 -o testing testing.o
extern  printf      ; the C function, to be called

SECTION .data       ; Data section, initialized variables

    a:  dd  15  ; int a=15
    str:    db "content in eax=%d", 10, 0 

SECTION .text       ; Code section.

    global main     ; the standard gcc entry point
main:               ; the program label for the entry point
    mov     ebp, esp
    mov     eax, [a]    ; put a from store into register

    shr     eax, 1      ; eax content should be 15>>1 = 7
    push    eax     
    push    dword str   ; string to be printed
    call    printf      ; printf(str,content_of_eax)

    shr     eax, 2
    push    eax         ; eax content should be 7>>2 = 1
    push    dword str   
    call    printf      ; printf(str,content_of_eax)    

    shr     eax, 1  
    push    eax         ; eax content should be 1>>1 = 0
    push    dword str   
    call    printf      ; printf(str,content_of_eax)

    mov     esp, ebp    ; takedown stack frame
    mov     eax, 0      ; normal, no error, return value
    ret                 ; return

输出:

content in eax=7
content in eax=4
content in eax=8

预期输出:

content in eax=7
content in eax=1
content in eax=0

printf returns其结果在eax中,原来的值丢失了。

您应该从 [a] 重新加载它或使用跨函数调用保存的寄存器,例如 esi,但您也应该保存它并在返回给调用者之前恢复它。您应该在每次调用后使用 add esp,8 弹出传递给 printf 的参数,以保持堆栈帧一致。

请记住,printf 会将 return 传输到输出的字符数。所以当你这样做时:

call    printf      ; printf(str,content_of_eax)

shr     eax, 2

您实际上是在移动 printf 的结果:

  • "content in eax=7\n" 是 17 个字符,所以 shiftfting by 2 给出:17 / 4 = 4

您需要在移位之前保存该值(在保留的寄存器中、在堆栈中或在内存中)。

这个答案似乎不是一个好的解决方案,由于下面的讨论,我目前保留它


就像其他人所说的那样,printf 会 return 它是 eax 的结果。 printf的结果是写入的字节数。

由于您将 shr 操作的结果压入堆栈,您可以使用 pop 再次检索它们,如下所示:

shr     eax, 1      ; eax content should be 15>>1 = 7
push    eax    
push    dword str   ; string to be printed
call    printf      ; printf(str,content_of_eax)

pop     eax 
pop     eax 
shr     eax, 2
push    eax         ; eax content should be 7>>2 = 1
push    dword str   
call    printf      ; printf(str,content_of_eax)  

# and so on ...

在您的数据部分中,您可以只对 a 使用等式,因为您只使用该变量一次并且不会更改它(我将其称为 value)。

    fmt db "content in eax=%d",0xa,0
    value equ 15

在 main 函数中我很确定(如果我错了请纠正我)你应该在用堆栈指针更新它之前保存基指针。

main:
        push ebp
        mov ebp, esp

现在您可以创建一个局部变量来存储您正在处理的当前值。

sub esp, 4

从那里开始,您只需在每次调用 printf 之前继续获取、移动和存储堆栈中的值。

mov eax, value          ; move 15 into eax  
shr eax, 1              ; make first shift
mov dword[ebp-4], eax   ; store result in local variable

push eax                ; eax = 7
push fmt
call printf             
add esp, 8              ; clean eax & fmt off the stack

mov eax, [ebp-4]        ; fetch last shift result from variable
shr eax, 2              ; make second shift
mov dword[ebp-4], eax   ; store result back in variable

push eax                ; eax = 1
push fmt
call printf             
add esp, 8              

mov eax, [ebp-4]        ; fetch last shift result from variable
shr eax, 1              ; make last shift

push eax                ; eax = 0
push fmt
call printf             
add esp, 8

add esp, 4              ; clean local variable

然后请记住,在您 return 之前,当您释放堆栈帧时,您也会恢复(弹出)基指针。

mov esp, ebp
pop ebp

这应该输出:

content in eax=7
content in eax=1
content in eax=0