[Assembler] Kommandozeile auslesen

Magnes

Cadet 2nd Year
Registriert
Apr. 2012
Beiträge
18
Hallo,

ich beschäftige mich zurzeit ein wenig mit x86 Assembler und versuche 'einfache' Programme zu basteln. Wie der Titel schon sagt, beschäftigt mich zur Zeit das auslesen der Kommandozeilen Parameter. Als Beispiel wie das funktioniert habe ich mir ein kleines C(++) Programm geschrieben und geschaut wie der Assemblercode davon aussieht. Der C-Code sieht wie folgt aus:

Code:
#include "stdio.h"

int main(int arc, char ** arcv)
{
      printf("%d", arc);
      return 0;
}

Wie man sieht wird hier einfach auf die Konsole geschrieben wie viele Parameter auf der Kommandozeile übergeben wurden.

In Assembler sieht das ganze dann (gekürzt) so aus:

Code:
...

_text   SEGMENT BYTE PUBLIC 'CODE'                      ; section number 1

_main   LABEL NEAR
        push   ebp
        mov    eax, 16    ; Warum wird 16 nach eax geladen? Für __alloca oder ___main?
        mov    ebp, esp
        sub    esp, 8
        and    esp, 0FFFFFFF0H    ; Laut Google Stackalignment und hier unwichtig, richtig?
        call    __alloca    ; Laut Google reserviert dies Speicher auf dem Stack, ist das korrekt?
        call    ___main    ; Was macht dies? Hab bei Google keine vernünftige Antwort gefunden.
        mov    dword ptr [esp], offset ?_001
        mov    eax, dword ptr [ebp+8H]
        mov    dword ptr [esp+4H], eax
        call    _printf
        leave
        xor    eax, eax
        ret

...

.rdata  SEGMENT BYTE PUBLIC 'CONST'                     ; section number 4

?_001   label byte
        db 25H, 64H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0000 _ %d......
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0008 _ ........

...

Kann mir wer erklären, ob das was ich oben in den Kommentaren geschrieben habe so richtig ist und was es mit __alloc und ___main auf sich hat?

Mein Nachbau sieht wie folgt aus:

Code:
DATA SECTION
	FORMAT	DD	"%d",0
CODE SECTION
	START:
		PUSH    EBP			; Org. Basepointer für Rücksprung auf dem Stack sichern
		MOV     EBP, ESP		; Basepointer durch aktuellen Stackpointer ersetzen
		SUB     ESP, 8			; 8Byte auf dem Stack reservieren
		MOV     [ESP], ADDR FORMAT	; Adresse von "%d" auf den Stack legen
		MOV     EAX, [EBP+8H]		; Sollte eigentlich den wert von 'argc' nach EAX schieben
		MOV     [ESP+4H], EAX		; 'argc' unter die Adresse von"%d" auf den Stack legen
		CALL    printf			; printf aufrufen
		XCHG    EBP, ESP		; Aufräumen Stackpointer auf Basepointer setzen
		POP     EBP			; Alten Basepointer für Rücksprung laden
		XOR     EAX, EAX		; EAX auf 0 setzen
		RET				; Verlassen...

Jetzt die Frage alles Fragen:

Warum funktioniert das oben und es wird korrekterweise die Anzahl an Parametern ausgegeben, während in meinem Nachbau nur Schwachsinn (scheinbar zufällige Zahl) ausgegeben wird?

Falls noch weitere Infos notwendig sind, schreit bitte. Dann werde ich diese nach Möglichkeit liefern.

Gruß,

Magnes
 
argc ist bei esp+4 abgelegt
pointer auf argv[0] ist bei esp+8 abgelegt
die Argv sind in einer verketteten List:
argv[0]: Pointer auf arg0, Pointer auf argv[1]
argv[1]: Pointer auf arg1, Pointer auf argv[2] ...

Also hast Du statt argc der Pointer auf argv[0] ausgegeben.
 
Danke für die Antwort Lynxx,

ich glaube aber, dass du da falsch liegst.

Direkt nach dem Start der Anwendung hättest du recht. Aber durch das voran gegangene PUSH EBP zur Sicherung des Basepointers und das darauf folgende MOV EBP, ESP sollte argc nun bei EBP+8 liegen oder nicht?

Habe es eben jedoch mal ausprobiert und EBP+4 hilft auch nicht.
 
Das
Code:
PUSH    EBP
am Anfang schiebt ja auch noch was auf den Stack.

Stack vorher:
*envp[]
*argv[]
argc
return address

Nach dem PUSH:
*envp[]
*argv[]
argc
return address
ebp

Kommste jetzt drauf ? :evillol:

Edit: Ok, kleiner Extra-Hinweis .. argc ist KEIN Pointer ..
 
Zuletzt bearbeitet: (Zusätzliche Info ..)
Hast du eigentlich keinen Debugger? asm kann manchmal ziemlich hart sein.
 
Ja da stimme ich dir zu nach dem PUSH sieht es so aus:

32| *envp[]
28| *argv[]
24| argc
20| return address
16| ebp (20)

Damit steht in
EBP: 20
ESP: 16

Dann kommt
Code:
MOV EBP, ESP
und daraus folgt:

EBP: 16
ESP: 16

und argc ist erreichbar durch EBP+8 nicht EBP+4

Somit schiebt
Code:
MOV EAX, [EBP+8]
den wert argc in EAX...

Also meiner Ansicht nach müsste der Stack vor dem
Code:
CALL printf
somit wie folgt aussehen:

32 | *envp[]
28 | *argv[]
24 | argc
20 | retaddr
16 | EBP(20)
12 | argc
08 | ADDR FORMAT
04 |

EBP: 16
ESP: 8
EAX: argc

Nen Debugger habe ich (noch) nicht. Kannst mir einer einen empfehlen? :-D
 
Zurück
Oben