Stackpointer, falsches Argument



  • Ich kann mir keinen Reim aus diesen Code machen. An und für sich nichts ungewöhnliches, aber in diesem Fall regnet es Bahnhöfe.
    das ganze ist in nasm für win32.

    extern _printf
    
    section .data
    mstring: db "%d"
    
    global _main
    
    section .text
    _main:
    
    mov eax,[esp+4]
    
    push eax
    push mstring
    call _printf
    add esp, 8
    ret
    

    main soll einfach eine Funktion mit einem Argument sein, die ihr Argument auf der Konsole ausgibt. Das Argument müsste eigentlich auf [esp+4] liegen. Wenn ich das Programm aber ausführe, gibt das Programm immer 2 aus, unabhängig vom Argument. Ich hab aus dem Programm soviel Komplexität rausgenommen wie's nur geht, aber es ergibt einfach keinen Sinn.



  • Gibst du da argc aus?



  • ist argc die Zahl der Argumente? Kanns normal nicht sein. Wenn ich a(x, y) mit 2 Argumenten aufrufe, gibt er mir normalerweise auch 2 aus. Manchmal auch 3, ist aber selten



  • extern _printf		; reference to external function '_printf'
    
    section .data		; start data section to initialize variables
    mstring: db "%d", 0	; mystring = terminating string "%d"
    
    section .text		; start code section to define instruction calls
    global _main		; _main is now in global scope (standard program entry point becomes visible)
    _main:				; set label _main (=function head)
    mov eax,[esp+4]		; move 4 byte from memory at stack adress + 4 (=first _main function argument = argc) to register eax
    push eax			; push eax onto stack as _printf argument
    push mstring		; push mystring onto stack as _printf argument
    call _printf		; call _printf with arguments on stack
    add esp, 8			; reset stack state to adress before the 2 pushes of 4 byte
    ret					; return
    

    Gute Beispiele findest du hier.
    Um Zeile 9,13 und 14 zu erklären:
    Bei Funktionsaufrufen wird die Rücksprung-Adresse als letztes auf den Stack gelegt und wird bei ret genutzt, um aus der Funktion zum vorherigen Code zurückzukehren bzw. dort weiterzumachen.



  • Dann wird also tatsächlich argc ausgegeben? Versteh ich nicht, das macht überhaupt keinen Sinn. Ich kann in die Konsole a(1,4,2,5) eingeben (a ist der Name der exe Datei) und ich bekomme immer noch nur 2 ausgegeben, obwohl die Funktion dann 4 Argumente hat.
    Außerdem, wenn argc auf der Adresse esp+4 liegt, wo liegt dann das Argument, dass ich eigentlich ausgeben will, also zum Beispiel bei a(5), die 5? Das müsste doch eigentlich auch auf dem Stack gespeichert werden.



  • Zuerst einmal würde ich sicherstellen, dass der Linker auch den entsprechend setup code hinzufügt, der dein _main-Funktion aufruft - andernfalls handelt es sich um den rohen Programmeintrittspunkt der überhaupt kein Argument besitzt (das Programm wird mittels ExitProcess beendigt).
    Unter der Annahm es handelt sich um main(int argc,char** argv), dann ist argv (=[esp+8]) der Zeiger auf ein pointer array (string pointer). Die Größe des Arrays ist durch argc gegeben.



  • Hattest du dich mit dem Argumenten in main bereits in C auseinandergesetzt?

    Die ersten 4 Bytes auf dem Stack machen die Rücksprung-Adresse der Funktion aus.
    Die zweiten 4 Byte sind das erste _main Argument argc, welches die Anzahl an Programm Parametern angibt.
    Die dritten 4 Byte sind das zweite _main Argument argv, welches eine Adresse auf String-Adressen ist, welche die Programm Parameter sind.

    Der erste Programm Parameter ist der Programmpfad selbst. Weitere sind jene, welche bei Programmausführung angegeben wurden.

    climits schrieb:

    Ich kann in die Konsole a(1,4,2,5) eingeben (a ist der Name der exe Datei) und ich bekomme immer noch nur 2 ausgegeben...

    Wo hast du denn diese Schreibweise her? Bis zum ersten ungültigen Satzzeichen ( wird der Programmname angenommen, also a, (1,4,2,5) wird dann als ein Parameter / ein Text gewertet (demnach hast du tatsächlich nur einen Parameter).

    CRTStartup schrieb:

    ...dann ist argv (=[esp+8]) der Zeiger auf ein pointer array (string pointer).

    "pointer" und Assembler 🙄



  • Ja, jetzt versteh ich's auch. Habe nicht gewusst, dass die main argumente wie sie in C vorkommen, so etwas Universelles sind. Scheint aber bei jedem Programmeintrittspunkt vorhanden zu sein.

    Jetzt frag ich mich allerdings, wie greif ich auf die einzelnen Array-Elemente von argv[] zu? Ich hab es mit diesem Code

    extern _printf
    
    section .data
    mstring: db "%s"
    global _main
    section .text
    _main:
    mov eax,[esp+8]
    push dword [eax]
    push mstring
    call _printf
    add esp, 8
    mov eax, 0
    ret
    

    lediglich geschafft den Programmnamen a auszugeben, allerdings nicht den Programmpfad was ja das erste Element von argv[] ist, und wie ich an die restlichen Array-Elemente rankomme ist mir eh ein Rätsel.

    Youka schrieb:

    Wo hast du denn diese Schreibweise her? Bis zum ersten ungültigen Satzzeichen ( wird der Programmname angenommen, also a, (1,4,2,5) wird dann als ein Parameter / ein Text gewertet. Demnach hast du tatsächlich nur ein Parameter!

    Tatsächlich, wenn ich a(1, 4, 2, 5) mit Leerzeichen zwischendrin schreibe, gibt er die korrekte Zahl der Parameter aus... find ich bescheuert. Voneinander getrennte Parameter werden sonst doch auch überall an zwischenliegenden Kommas festgemacht, und nicht an zwischenliegenden Leerzeichen. In einem C++ source code interessiert es den Compiler ja auch nicht, ob ich func(a,b,c) oder func(a, b, c) schreibe.. und überhaupt, was soll 1,4,2,5 für ein Parameter sein? Ein int-Array oder wie?

    CRTStartup schrieb:

    Zuerst einmal würde ich sicherstellen, dass der Linker auch den entsprechend setup code hinzufügt, der dein _main-Funktion aufruft

    Ich hab mir jetzt einfach mal per Editor die Exedatei angesehen. Hatte für mich genug "Füllung" um davon auszugehen dass mehr drin ist als nur eine ExitProcess Anweisung. Falls das irgendwas aussagt.



  • Du scheinst sowohl in Assembler als auch Windows noch recht unwissend zu sein und solltest erstmal mehr lernen, bevor hier noch alles in ein Tutorial ausartet.
    Zudem gefällt mir dein Ton nicht (z.B. auf die ausführliche Hilfe früh morgens kommt ein "Ja, jetzt versteh ich's auch.").



  • Youka schrieb:

    "pointer" und Assembler 🙄

    Möchtest du uns etwas mitteilen?



  • climits schrieb:

    Tatsächlich, wenn ich a(1, 4, 2, 5) mit Leerzeichen zwischendrin schreibe, gibt er die korrekte Zahl der Parameter aus... find ich bescheuert. Voneinander getrennte Parameter werden sonst doch auch überall an zwischenliegenden Kommas festgemacht, und nicht an zwischenliegenden Leerzeichen.

    Hast du schonmal irgendwann in deinem Leben einen Konsolenbefehl benutzt? Offensichtlich nicht. Konsolenbefehle sehen z.b. so aus:

    format c:

    dir *.txt

    copy meins.txt d:\ordner

    Keine Klammern, keine Kommas.

    In einem C++ source code interessiert es den Compiler ja auch nicht, ob ich func(a,b,c) oder func(a, b, c) schreibe.. und überhaupt, was soll 1,4,2,5 für ein Parameter sein? Ein int-Array oder wie?

    Ein String. Die main hat in C folgende Signatur:

    int main()(int argc, char *argv[])
    

    ... damit du mal irgendeine Vorstellung bekommst, was du da gerade versuchst nachzubauen.



  • Youka schrieb:

    Du scheinst sowohl in Assembler als auch Windows noch recht unwissend zu sein und solltest erstmal mehr lernen, bevor hier noch alles in ein Tutorial ausartet.
    Zudem gefällt mir dein Ton nicht (z.B. auf die ausführliche Hilfe früh morgens kommt ein "Ja, jetzt versteh ich's auch.").

    Das war so gemeint wie's da steht, und in keinster Weise sarkastisch oder sonstwie. Tut mir Leid wenn's so rübergekommen ist. Ich bin dankbar, für jede Hilfe die ich hier bekomme.

    Bashar schrieb:

    Hast du schonmal irgendwann in deinem Leben einen Konsolenbefehl benutzt? Offensichtlich nicht. Konsolenbefehle sehen z.b. so aus:

    format c:

    dir *.txt

    copy meins.txt d:\ordner

    Keine Klammern, keine Kommas.

    Erm, das ist gut zu wissen.

    Bashar schrieb:

    Ein String. Die main hat in C folgende Signatur:
    C++:
    int main()(int argc, char *argv[])

    ... damit du mal irgendeine Vorstellung bekommst, was du da gerade versuchst nachzubauen.

    Zu meiner Verteidigung muss ich sagen, dass ich durchaus weiß, wie eine main funktion in c++ aussieht. Ich konnte bisher nur nicht die geistige Brücke von C++ auf den Kommandozeileninterpreter von Windows schlagen. Meine C++ Programme habe ich nie über die Konsole aufgerufen.

    Ich habe es jetzt über diesen code geschafft, auf das gesuchte Argument zuzugreifen.

    extern _printf
    section .data
    mstring: db "%s"
    global _main
    
    section .text
    
    _main:
    
    mov eax,[esp+8]
    
    push dword [eax+4]
    push mstring
    call _printf
    add esp, 8
    mov eax, 0
    ret
    

    Hat sich damit erledigt. Danke für alle Antworten


Log in to reply