【问题标题】:Why there is always a useless function argument in stack?为什么堆栈中总是有一个无用的函数参数?
【发布时间】:2012-07-11 13:18:29
【问题描述】:

我正在学习 FreeBSD 上的汇编语言编程。我正在使用 FreeBSD 9.0 i386 版本和 nasm 汇编程序。

当我写了一个简单的 syscall 函数时,我发现我必须将一个无用的值压入堆栈才能使代码正确运行。

例如:

; File:test.asm
section .text
  global _start
_start:
  xor  eax,eax
  ; Argument of exit()
  push 0x0
  ; Syscall of exit()
  mov  al,1
  int  0x80

我使用以下命令来组装和链接上面的代码:

%nasm -f elf test.asm -o test.o
%ld test.o -o test.bin

我用ktrace查看了程序,发现:

%ktrace ./test.bin
%kdump -d -f ./ktrace.out 
2059 ktrace   RET   ktrace 0
2059 ktrace   CALL  execve(-1077940941,-1077941260,-1077941252)
2059 ktrace   NAMI  "./test.bin"
2059 test.bin RET   execve 0
2059 test.bin CALL  exit(1)

所以代码没有正确运行,因为我提供了 0 作为 exit() 的唯一参数,但程序实际上运行了 exit(1)。

然后我更改了我的代码。

; File:test.asm
section .text
  global _start
_start:
  xor  eax,eax
  push 0x0
  ; Whatever digits,0x1,0x2...0xFFFFFFFF, ect.
  push 0xFFFFFFFF
  mov  al,1
  int  0x80

然后代码被正确执行。

起初,我认为这是因为“堆栈填充”或“堆栈对齐”之类的东西,例如Stack allocation, padding, and alignment。所以它可能尊重 16 位对齐。但我发现没有。例如,以下代码:

; File:test.asm
section .text
  global _start
_start:
  xor  eax,eax
  push 0x0
  ; Actual argument of exit()
  push 0x3
  push 0xFFFFFFFF
  ; Syscall of exit()
  mov  al,1
  int  0x80

实际执行 exit(3)。似乎它没有对齐字节。我用gdb调试了上面的代码,当最后一行即将执行时,堆栈是这样的:

0xFFFFFFFF  -> esp
0x00000003
0x00000000

所以我的问题是:为什么总是有无用的论点,或者有解决方法?

【问题讨论】:

    标签: assembly freebsd


    【解决方案1】:

    这是一个通过阻止调用/ret指令对来略微提高性能的虚拟参数。

    在以下链接中查看 $2.1:

    http://www.int80h.org/bsdasm/#default-calling-convention

    【讨论】:

    • 这个链接非常有用。谢谢!
    • 我读到了,但我不明白使用额外的参数如何消除call/ret
    • unix.derkeiler.com/Mailing-Lists/FreeBSD/hackers/2003-08/… 中给出的答案可能会有所帮助。内核中的trap.c实际上是通过sizeof(int)在栈上偏移参数start,假设最后压入的值是返回地址。
    • 所以更好的描述是它使 libc 系统调用包装器更有效。即包装器的堆栈参数已经在正确的位置作为系统调用的参数。所以它不是被阻止的调用/返回,而是pop ecx/push ecx,或者将所有参数再次复制到包装器的堆栈帧。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-21
    • 2019-01-16
    • 2018-11-07
    • 1970-01-01
    相关资源
    最近更新 更多