2012-04-04 21 views
2

Ich bin neu in der Assembly, und ich habe mich gerade mit dem Call Stack vertraut gemacht. Um die Befehlszeilenargumente in x86_64 auf Mac OS X zu bekommen, kann ich folgendes tun:x86_64 Assembly Befehlszeilenargumente

_main: 
    sub rsp, 8   ; 16 bit stack alignment 
    mov rax, 0 
    mov rdi, format 
    mov rsi, [rsp + 32] 
    call _printf 

Wo Format "% s". rsi wird auf argv [0] gesetzt.

Also, aus diesem, zog ich heraus, was (glaube ich) der Stapel sieht aus wie zunächst:

top of stack 
       <- rsp after alignment 
return address <- rsp at beginning (aligned rsp + 8) 
    [something] <- rsp + 16 
    argc  <- rsp + 24 
    argv[0]  <- rsp + 32 
    argv[1]  <- rsp + 40 
    ...   ... 
bottom of stack 

Und so weiter. Tut mir leid, wenn das schwer zu lesen ist. Ich frage mich, was [etwas] ist. Nach ein paar Tests stelle ich fest, dass es normalerweise nur 0 ist. Gelegentlich ist es jedoch eine (scheinbar) zufällige Zahl.

EDIT: Könnten Sie mir auch sagen, ob der Rest meiner Stack-Zeichnung korrekt ist?

Antwort

1

Sie haben es in der Nähe.

argv ist ein Array Zeiger, nicht wo das Array ist. In C ist es geschrieben , also müssen Sie zwei Ebenen der Dereferenzierung tun, um zu den Strings zu bekommen.

top of stack 
       <- rsp after alignment 
return address <- rsp at beginning (aligned rsp + 8) 
    [something] <- rsp + 16 
    argc  <- rsp + 24 
    argv  <- rsp + 32 
    envp  <- rsp + 40 (in most Unix-compatible systems, the environment 
    ...   ...  string array, char **envp) 
bottom of stack 
... 
somewhere else: 
    argv[0]  <- argv+0: address of first parameter (program path or name) 
    argv[1]  <- argv+8: address of second parameter (first command line argument) 
    argv[2]  <- argv+16: address of third parameter (second command line argument) 
    ... 
    argv[argc] <- argv+argc*8: NULL 
+0

Ah ja, das macht mehr Sinn. Aber dann, warum ist es, dass wenn ich mache: "** mov r10, [rsp + 32] **" und dann "** r10, 8 **" und dann r10 in printf übergeben, bekomme ich ein segfault? Das sollte argv [1] sein, oder? –

+0

Warte, mein ** Fehler **. Ich denke argv ist eigentlich "rsp + 40", nicht 32. Vielleicht. Ich bin jetzt ziemlich verwirrt, aber danke für deine Hilfe! –

0

Nach dem AMD64 ABI (3.2.3, Parameterübergabe) werden die Parameter für main(int argc, char **argv) übergeben (von links nach rechts Reihenfolge) rdi & rsi, weil sie von INTEGER Klasse. envp, wenn es verwendet würde, würde in rdx übergeben werden, und so weiter. wie folgt gcc legt sie in den aktuellen Frame (vermutlich aus Bequemlichkeit Registern Freisetzung??):

mov DWORD PTR [rbp-0x4], edi 
mov QWORD PTR [rbp-0x10], rsi 

Wenn der Rahmenzeiger angegeben wird, ist die Adressierung rsp relativ. Normalerweise würde argv ein eightbyte unter rbp sein (argc kommt zuerst, obwohl das nicht vorgeschrieben ist) und daher:

# after prologue 
mov rax, QWORD PTR [rbp-0x10] # or you could grab it from rsi, etc. 
add rax, 0x8 
mov rsi, QWORD PTR [rax] 
mov edi, 0x40064C# format 
call 400418 <[email protected]>