2014-11-12 2 views
1

Я изо всех сил, чтобы понять, почему это x86-код сборки, отлично компилируется с GCC 4.2.1 (LLVM) на OSX, но дает ошибку сегментации, когда исполняемый файл запускается:Segfault с поп/толчок в x86/OSX

.globl _main 
_main: 
     push %rbp 
     mov  %rsp, %rbp 
     mov  $1, %rbx 
     push %rbx 
     lea  L_.str0(%rip), %rdi 
     mov  %rbx, %rsi 
     call _printf 
     pop  %rbx 
     pop  %rbp 
     ret 

     .section  __TEXT,__cstring,cstring_literals 
L_.str0: 
     .asciz "%d \000" 

Я заметил, что если линия pop %rbx перемещается до call _printf, программа работает правильно. Но почему это должно терпеть неудачу в ее первоначальной форме?

+1

Вам нужно выровнять стек ... – Macmade

+0

@Macmade верен, я верю - я скомпилировал и запустил ваш код, и журнал сбоев даже говорит, что это несоосность стека (не выровнено по 16 байт). –

+0

@PaulR - Спасибо. Есть ли способ сделать это с помощью директивы? или мне нужно посыпать код для выравнивания вручную? – fairville

ответ

3

Этот вопрос подробно ответил на: How to print argv[0] in NASM?, а также x86 Assembly on a Mac. По сути, это важно при программировании сборки на MacOSX.

Подводя итог:

  • вина Это SEG происходит из-за перекоса стека.
  • Это происходит только в ОС, использующих соглашение о вызове System V (включая MacOSX, но исключая Linux), который настаивает на том, что указатель стека должен быть кратным 16 перед вызовом функции (например, до printf).

Простое решение состоит в согласовании указатель стека (то есть, выравнивание кратному 16 байтов в соответствии с требованием Sys V) до вызова, и восстановить его после вызова:

.globl _main 
_main: 
     push %rbp 
     mov  %rsp, %rbp 
     mov  $1, %rbx 
     lea  L_.str0(%rip), %rdi 
     mov  %rbx, %rsi 
     push %rbx 

    mov %rsp, %rax ; Save copy of the stack pointer (SP) 
    and $-16, %rsp ; Align the SP to the nearest multiple of 16. 
    sub $8, %rsp  ; Pad the SP by 8 bytes so that when we ... 
    push %rax  ; push the saved SP (=8 bytes on a 64-bit OS), 
        ; we remain aligned to 16 bytes (8+8 = 16). 

     call _printf 

    pop %rax   ; retrieve the saved SP 
    mov %rax, %rsp ; restore SP using saved value. 

     pop  %rbx 
     pop  %rbp 
     ret 

     .section  __TEXT,__cstring,cstring_literals 
L_.str0: 
     .asciz "%d \000" 
+1

+1 Отличный ответ. Добро пожаловать в Stackoverflow. – trojanfoe