1

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

我推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的内置汇编器(我认为是gas),然后是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
4

2 回答 2

2

您崩溃的函数的名称应该是一个死的赠品:

misaligned_stack_error_entering_dyld_stub_binder( )

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

确保熟悉您打算为其编写与 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

仍然有一些缺陷。首先,堆栈向下增长,而不是向上增长,因此您需要减去 fromesp以对齐它。其次,您试图将eax其作为参数传递给_CFShow,因此它需要espcall指令时出现。最后,您需要在 之前而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在 return from 点已经有 16 字节对齐_CFStringCreateWithCString,并且您不再需要0压入堆栈来调用该函数来使其更清晰,因此您可以简单地存储eax在它的位置并避免进一步的堆栈操作:

## push CFSTR return value in eax
mov [esp], eax
call _CFShow

最后,不要忘记在从函数返回之前清理堆栈并恢复esp到初始值!

于 2013-09-04T00:02:40.083 回答
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
于 2013-09-10T21:26:07.040 回答