CoreFoundation在Mac OS X Assembly中起作用

时间:2013-09-03 23:57:38

标签: macos assembly

我在汇编中有以下代码(由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

2 个答案:

答案 0 :(得分:2)

你坠毁的功能的名称应该是一个死的赠品:

misaligned_stack_error_entering_dyld_stub_binder( )

在OS X上,堆栈在任何函数调用时必须具有16B对齐[1]。这是通过dyld存根绑定器中的检查功能对动态链接库边界的调用强制执行的,这是导致崩溃的原因。在push eax之前,您需要在堆栈中添加12个字节的填充,并进行调用以满足此约束。

确保熟悉您打算编写与C库交互的程序集的任何平台上的调用约定。

[1] https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW4


您修改过的示例:

## 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

您可以通过注意_CFStringCreateWithCString0返回时已经有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