【发布时间】:2017-06-16 13:25:26
【问题描述】:
我正在尝试掌握 FreeBSD 中的汇编程序。在handbook's code example for a UNIX filter 中,寄存器 esp 在每次系统调用后都会重置。有问题的代码是:
%include 'system.inc'
section .data
hex db '0123456789ABCDEF'
buffer db 0, 0, ' '
section .text
global _start
_start:
; read a byte from stdin
push dword 1
push dword buffer
push dword stdin
sys.read
add esp, byte 12 ; <--------- Is this necessary?
or eax, eax
je .done
; convert it to hex
movzx eax, byte [buffer]
mov edx, eax
shr dl, 4
mov dl, [hex+edx]
mov [buffer], dl
and al, 0Fh
mov al, [hex+eax]
mov [buffer+1], al
; print it
push dword 3
push dword buffer
push dword stdout
sys.write
add esp, byte 12 ; <--------- Is this necessary?
jmp short _start
.done:
push dword 0
sys.exit
这与previous page of the documentation 上的示例不同:
1: %include 'system.inc'
2:
3: section .data
4: hello db 'Hello, World!', 0Ah
5: hbytes equ $-hello
6:
7: section .text
8: global _start
9: _start:
10: push dword hbytes
11: push dword hello
12: push dword stdout
13: sys.write ; <--------- ESP not adjusted after this. Why?
14:
15: push dword 0
16: sys.exit
为什么这两个例子不同?为什么需要add esp, byte 12 之类的东西?系统调用没有弹出值吗?在没有在堆栈上传递参数的 64 位 FreeBSD 中这是必要的吗?我以为堆栈指针会自行处理。
【问题讨论】:
-
能否请您引用您感到困惑的代码,或者至少提供一个链接?
-
“寄存器 esp 已重置”是什么意思?你如何“重置”一个寄存器?您的意思是保存并恢复原始值吗?你的意思是一个值被添加到ESP,就像你清理堆栈一样?还是别的什么?
-
在 32 位代码中,
int 0x80用于系统调用。int 0x80的调用约定要求将参数压入堆栈,int 0x80要求调用者自己恢复堆栈。如果您将参数推送到int 0x80的堆栈上,则必须在之后回收空间。在 64 位代码中,系统调用是通过syscall指令完成的。在这种情况下,系统调用参数都在寄存器中传递。在这种情况下,无需在syscall指令之后调整 RSP。 -
我查看了 FreeBSD 文档的上一页。我知道您对他们显示的代码的困惑在哪里。现实情况是,之后未调整 ESP 的代码可能被认为是正确的,但通常会养成一个坏习惯。它还使他们的文档不一致。在这些简单的情况下,
add esp, byte xxx不是必需的,因为它们在完成时不会返回到调用函数。他们正在执行一个 sys.exit 系统调用,这将终止该过程。系统退出调用后的代码将永远不会返回,因此堆栈的状态无关紧要。 -
@MichaelPetch:感谢您的确认。我还认为,出于一致性原因,他们也应该将其添加到第一个示例中。
标签: assembly x86 nasm freebsd stack-pointer