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

时间:2015-04-18 13:29:05

标签: c linux assembly printf nasm

我是装配新手。我有不同的输出来跟踪我预期的简单代码。每次调用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

4 个答案:

答案 0 :(得分:4)

printfeax中返回其结果,原始值将丢失。

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

答案 1 :(得分:3)

在您的数据部分中,您可以使用等同于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

然后记住,在你返回之前,当你释放堆栈帧时,你也恢复(弹出)基本指针。

mov esp, ebp
pop ebp

这应输出:

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

答案 2 :(得分:1)

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

call    printf      ; printf(str,content_of_eax)

shr     eax, 2

您实际上是从printf转移结果:

  • "内容在eax = 7 \ n"是17个字符,所以shitfting by 2给出:17/4 = 4

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

答案 3 :(得分:0)

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


与其他人一样,printf会将结果返回给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 ...