【问题标题】:NASM 32-bit: printing content of register by printfNASM 32 位:printf 打印寄存器的内容
【发布时间】:2015-06-25 09:59:57
【问题描述】:

我是组装新手。对于遵循我所期望的简单代码,我有不同的输出。每次调用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

【问题讨论】:

  • 您的前四个字:“... 我是汇编新手 ...” 对于刚接触汇编的人来说,您确实编写了不错的源代码;整洁,乍一看很容易阅读,完全清晰易读,对于以前从未见过您或您的作品的陌生人来说是可以理解的。继续这样做,你会有一个光明的未来。
  • 感谢您的赞赏 :)

标签: c linux assembly printf nasm


【解决方案1】:

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


就像其他人所说,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 ...

【讨论】:

  • 感谢您的回复。我们可以使用add esp,4 代替第一个pop eax,而不是使用两次pop eax,对吧?应该首选哪一个?
  • 不,这行不通。它会增加堆栈边界上的堆栈指针,另一方面,它不会将正确的值复制到eax.. 使用pop 两次是可以的
  • 是的,我同意它会起作用。我的问题是将内容恢复到eax 的最佳方法是什么?使用pop eax 两次,还是使用add esp,4 代替pop eax
  • 是的,add esp,4 然后pop eax 而不是pop eax 两次有效。
  • @hek2mgl 这可能会让您感兴趣,保存所有通用寄存器的快速方法是使用pushad 将它们压入堆栈并使用popad 将它们弹出。
【解决方案2】:

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

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

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

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 感谢您的回复。删除了错字。
    • 看来printf 也改变了ecxedx 的内容。对吗?
    • @user148865:是的,它在大多数系统上都可以。您想研究 ABI 以了解您的环境的具体细节:注册程序、参数传递、系统调用约定……您可以通过搜索引擎轻松找到。
    【解决方案4】:

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

    call    printf      ; printf(str,content_of_eax)
    
    shr     eax, 2
    

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

    • “eax=7\n 中的内容”是 17 个字符,因此除以 2 得到:17 / 4 = 4

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

    【讨论】:

    • 愚蠢的问题:str 是 "eax=7 中的内容",10,0 。但是,printf 返回 16。为什么这里不计算换行符和空字符?
    • 他们被计算在内!我已经更正了;)但是即使17 >> 4 仍然是4,因为2 的其余部分被丢弃了。
    • @user148865 :是的,对不起,\n 应该计入输出中的字符总数(所以它是 17,而不是 16),但从 printf 的返回不包括空字节.
    猜你喜欢
    • 2015-06-09
    • 1970-01-01
    • 2021-03-29
    • 2014-12-17
    • 2015-12-26
    • 2020-06-07
    • 2015-06-29
    • 1970-01-01
    • 2014-11-18
    相关资源
    最近更新 更多