我在汇编中有以下代码(由clang组装)
更新了我认为会导致对齐的内容;仍然没有。
再次更新;即使有你的建议,代码仍然会出现错误(感谢Stephen Canon的建议) 我还试图减去4,8,12所有不能使用更多信息更新相同的堆栈重新调整问题。
.globl _main
.data
_hw: .asciz "Hello World\n\0"
.text
_main:
push 8 # 4 bytes
push _hw # 4 bytes
push 0 # 4 bytes
##https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFStringRef/Reference/reference.html#//apple_ref/c/func/CFStringCreateWithCString
call _CFStringCreateWithCString # 4 bytes
## push CFSTR return value in eax
sub esp, 8 # 8 bytes
push eax # 4 bytes
##https://developer.apple.com/library/ios/DOCUMENTATION/CoreFoundation/Reference/CFTypeRef/Reference/reference.html#//apple_ref/c/func/CFShow
call _CFShow # 4 bytes
add esp, 8 # remove padding from stack pointer
mov eax, 99
ret
程序执行
主堆栈的开始是空的
=============== (0xFFFF)
| |
| STACK |
| |
===============
I push 8,_hw的地址,0然后调用_CFStringCreateWithCString。现在看起来像
=============== (0xFFFF)
| 8 |
|-------------- (0xFFFB) 4 bytes for 8
| hw address |
|-------------- (0xFFF7) 4 bytes for address of hw
| 0 |
|-------------- (0xFFF3) 4 bytes for 0 (NULL)
| call |
--------------- (0xFFEF) 4 bytes for address to return to after call (eip?) Is this 8 on x64?
然后调用CFStringCreateWithCString保存返回地址(从调用正确弹出它?),从堆栈中弹出参数并跳转到保存的eip地址后执行并将其返回值放入eax。
之后,堆栈看起来像
=============== 0xFFFF
| |
| STACK |
| |
===============
然后我从esp中减去8,所以它现在看起来像
=============== (0xFFFF)
| Padding |
| 8 bytes |
|-------------- (0xFFF7) (esp)
| |
===============
然后我从CFStringCreateWithCString推送eax,使堆栈看起来像
=============== (0xFFFF)
| Padding |
| 8 bytes |
|-------------- (0xFFF7) # 8 bytes padding from subtracting the stack counter
| eax |
|-------------- (0xFFF3) # 4 bytes from eax, the return from last call, or is it 8 bytes on x64?
| call |
|-------------- (0xFFEF) # 4 bytes to return after call (eip?)
===============
在调用CFShow之后(它弹出了它的参数和调用的地址)堆栈看起来像这样
=============== (0xFFFF)
| Padding |
| 8 bytes |
|-------------- (0xFFF7) # 8 bytes padding from subtracting the stack counter, CFShow doesn't touch this as it only expects 4 byte address
然后我将8个字节添加到esp中删除填充,使其看起来像这样
=============== (0xFFFF)
| |
| STACK |
| |
===============
正确?
这是我运行代码的类型,我需要更改一些东西,因为处理器是64位吗?
MacBookPro:HelloWorld user$ cat hand.s
.globl _main
.data
_hw: .asciz "Hello World\n\0"
.text
_main:
push 8 # 4 bytes
push _hw # 4 bytes
push 0 # 4 bytes
call _CFStringCreateWithCString
## push CFSTR return value in eax
sub esp, 8 # 8 bytes
push eax # 12 bytes
call _CFShow
mov eax, 99
ret
我的编译步骤,使用clang的内置汇编程序(我认为是气体)然后使用ld。这是在Mac OS X 64位Mountain Lion上
MacBookPro:HelloWorld user$ clang -cc1as -filetype obj -mllvm --x86-asm-syntax=intel -o hand.o hand.s
将其与CoreFoundation链接
MacBookPro:HelloWorld user$ ld -macosx_version_min 10.8.0 -o hand hand.o -lSystem -framework CoreFoundation
运行可执行文件。
MacBookPro:HelloWorld user$ ./hand
Segmentation fault: 11
MacBookPro:HelloWorld user$
导致以下错误
Segmentation fault: 11
答案 0 :(得分:2)
你坠毁的功能的名称应该是一个死的赠品:
misaligned_stack_error_entering_dyld_stub_binder( )
在OS X上,堆栈在任何函数调用时必须具有16B对齐[1]。这是通过dyld存根绑定器中的检查功能对动态链接库边界的调用强制执行的,这是导致崩溃的原因。在push eax
之前,您需要在堆栈中添加12个字节的填充,并进行调用以满足此约束。
确保熟悉您打算编写与C库交互的程序集的任何平台上的调用约定。
您修改过的示例:
## push CFSTR return value in eax
push eax # 4 bytes
add esp, 8 # 8 bytes
# call puts on last 4 bytes
call _CFShow
还有一些瑕疵。首先,堆栈 down 而不是向上增长,因此您需要从esp
中减去它以对齐它。其次,您尝试将eax
作为参数传递给_CFShow
,因此在esp
指令时它需要位于call
。最后,您需要在call
之前进行16字节对齐,而不是在## push CFSTR return value in eax
sub esp, 12 # esp aligned 4 mod 16
push eax # esp aligned 0 mod 16
call _CFShow
之后。
相反,你需要这样的东西:
esp
您可以通过注意_CFStringCreateWithCString
在0
返回时已经有16字节对齐,并且您不再需要推送的eax
,这样可以让它更清晰一些在堆栈上调用该函数,因此您只需将## push CFSTR return value in eax
mov [esp], eax
call _CFShow
存储在其中并避免进一步的堆栈操作:
esp
最后,在从函数返回之前,不要忘记清理堆栈并将{{1}}恢复为初始值!
答案 1 :(得分:1)
我无法测试此代码,我不熟悉这种汇编语法,但对我来说似乎不对...
恕我直言,正确的代码应该是:
.globl _main
.data
_hw: .asciz "Hello World\n\0"
.text
_main:
push 8
push _hw
push 0
call _CFStringCreateWithCString
add esp, 12 ; remove arguments from the stack...
sub esp, 8 ; align the stack for the next call...
push eax
call _CFShow
add esp, 12
mov eax, 99
ret
注意,添加/子序列:
add esp, 12 ; remove arguments from the stack...
sub esp, 8 ; align the stack for the next call...
我这样写是为了清理逻辑,但当然可以简化为:
add esp, 4
所以,最终的代码:
.globl _main
.data
_hw: .asciz "Hello World\n\0"
.text
_main:
push 8
push _hw
push 0
call _CFStringCreateWithCString
add esp, 4 ; clean the arguments and align the stack for the next call...
push eax
call _CFShow
add esp, 12
mov eax, 99
ret