2013-09-06 10 views
0

다음 코드는 CoreFoundation 함수를 사용하여 Hello World를 인쇄하는 것입니다. 그러나 내가 겉으로보기에 제대로 정렬 된 스택을 가지고있을 때마다 작동하지 않습니다. 하지만 마침내 스택이 제대로 작동하지 않게되었을 때?!?!?!esp가 증가하지 않는 한 코드 segfaults

global _main 

align 4, db 0x90 

extern _CFStringCreateWithCString 
extern _CFShow 

section .data 
    hw: db 'Hello World!' ,0xA,0 

section .text 
    _main: ; entering a new function stack must be balanced right? 

    push ebp ; saving ebp (esp + 4) 
    mov ebp, esp ; moving registers around 
    ; align stack as calling pushed a 4 byte address on to the stack 
    sub esp, 12 ; balancing the stack back to mod 16 (4 + 12 = 16) 


    push 8 ; 4 bytes 
    push hw ; 4 bytes 
    push 0 ; 4 bytes 
    call _CFStringCreateWithCString ; 4 bytes 

    ; stack still balanced 

    sub esp, 12 ; 12 bytes 
    push eax  ; 4 bytes 
    call _CFShow ; 4 bytes 

    ; that is 20 bytes?!?!? yet when I change the 12 to an 8 it doesn't run and instead segfaults! When I have the stack balanced! 


    mov eax, 99 ; return value 

    mov esp, ebp ; restore stack for function that called us 
    pop ebp 
    ret   ; return 

실행하면 작동하지만 아무런 이유가 없습니다. 하나의 인수 함수에 대해 esp에서 12를 빼야합니다. 그것은 8이 아니어야하며, 인수에 대해 스택을 증가시키는 것을 이미 처리하지 않았습니까?

+0

스택에서 마지막 세 개의 매개 변수를 제거하기 위해 esp에 12를 추가하면 안됩니까? (_CFStringCreateWithCString 호출 후) – BlackBear

+0

CFStringCreateWithCString이 스택에서 해당 인수를 팝하면 그렇게하지 않습니까? – Zimm3r

+0

인수는 호출 된 함수에 의해 스택에서 절대 팝 아웃되지 않습니다. 그렇지 않으면 스택 프레임이 엉망이됩니다. – BlackBear

답변

1

원래 함수가 스택에 할당 된 공간을 사용하지 않고 스택에서 추가 빼기를하는 이유가 확실하지 않습니다. 스택은 x86에서 커집니다. 이러한 맥락에서, 당신이 할 경우 : 당신이 할당된다

sub esp, NUMBER 

스택에 NUMBER 바이트가 어떤 목적으로 사용하는 (사용할 수 있도록). 내가 라이브러리는 C 호출 규칙을 따른다고 가정하고있어

: 마음에 이러한 것들로

1) Push the parameters (in reverse order) onto the stack 
2) Call the function 
3) Restore the stack based upon the amount of space used by the prior pushes. 

, 여기에 내가 당신의 기능을 써서 방법은 다음과 같습니다

global _main 

align 4, db 0x90 

extern _CFStringCreateWithCString 
extern _CFShow 

section .data 
hw: db 'Hello World!' ,0xA,0 

section .text 
_main: ; entering a new function stack must be balanced right? 

    push ebp   ; saving ebp (esp + 4) 
    mov ebp, esp ; set stack frame pointer 

    push 8   ; String encoding - 4 bytes 
    push hw   ; String pointer - 4 bytes 
    push 0   ; Allocator [0 for default] - 4 bytes 
    call _CFStringCreateWithCString 
    add esp, 12  ; restore the stack [pop the 12 bytes back off] 

    push eax   ; Address of string to show (returned by prior call) - 4 bytes 
    call _CFShow 
    add esp, 4  ; restore the stack [pop the 4 bytes back off] NOT NEEDED with 

    mov eax, 99  ; return value 

    mov esp, ebp ; restore stack for function that called us 
    pop ebp 
    ret 

주를이 마지막 mov 명령어가 스택을 복원 한 이후에 마지막으로 add esp,4을 생략 할 수 있지만 여기서는 완전성을 위해 설명합니다.

하는 I 모든 함수 호출에 스택의 16 바이트의 정렬을 유지하는 것을 시도하고, 가정 한 경우는 16 바이트가이 기능 항목 정렬이다 : 첫번째 경우와 마찬가지로

global _main 

align 4, db 0x90 

extern _CFStringCreateWithCString 
extern _CFShow 

section .data 
hw: db 'Hello World!' ,0xA,0 

section .text 
_main: ; entering a new function stack must be balanced right? 

    push ebp   ; saving ebp (esp + 4) 
    mov ebp, esp ; set stack frame pointer 

    sub esp,4  ; Maintain 16-byte alignment on next call 
    push 8   ; String encoding - 4 bytes 
    push hw   ; String pointer - 4 bytes 
    push 0   ; Allocator [0 for default] - 4 bytes 
    call _CFStringCreateWithCString 

    add esp, 4  ; add 16 to restore, then sub 12 for 16-byte alignment on next call 

    push eax   ; Address of string to show (returned by prior call) - 4 bytes 
    call _CFShow 
    add esp, 16  ; restore the stack [pop 16 bytes back off] 

    mov eax, 99  ; return value 

    mov esp, ebp ; restore stack for function that called us 
    pop ebp 
    ret 

, 마지막 add esp,16은 생략 될 수 있습니다.

+0

Mac OS X은 스택이 16 바이트로 정렬되어 있어야합니다. 이는 두통이었습니다. 그러나 나는 그것을 감사 일하게했다 – Zimm3r

+0

@ Zimm3r ok. 당신은 위의 원칙을 적용 할 수 있습니다. 네가 일하게되어 기쁘다. – lurker