Wie Programmstart-Argumente in Assembler auslesen?

Dieses Thema im Forum "Programmieren allgemein" wurde erstellt von gu4rdi4n, 25.05.2008.

  1. #1 gu4rdi4n, 25.05.2008
    gu4rdi4n

    gu4rdi4n Freak

    Dabei seit:
    29.11.2006
    Beiträge:
    116
    Zustimmungen:
    0
    Ort:
    Elsfleth
    hi,
    ich bin grade dabei Asembler zu lernen, und hätte da mal eine Frage.
    Wie kann ich die Argumente, welche beim Programmstart unter Linux gegeben sind, in Asembler auslesen?

    Wenn ich zum Beispeil ein Programm mit "./meinProgramm 50 100 150" starten würde, wie könnte ich die hinteren werte(50, 100 und 150) in Asembler unter Linux auslesen?


    MfG
    GU4RDI4N
     
  2. Anzeige

    Schau dir mal diese Kategorie an. Dort findest du bestimmt etwas.
    Registrieren bzw. einloggen, um diese und auch andere Anzeigen zu deaktivieren
  3. #2 bytepool, 22.06.2008
    bytepool

    bytepool Code Monkey

    Dabei seit:
    12.07.2003
    Beiträge:
    791
    Zustimmungen:
    0
    Ort:
    /home/sweden/göteborg
    Hi,

    ich bin selber nicht so der Assembler Crack, aber ich dachte mir, dass man das eigentlich rausbekommen koennte, indem man sich mal die Assembler Anweisungen von einem ganz simplen C Programm anschaut:

    Code:
    #include <stdio.h>
    
    int main(int argc, char * argv [])
    {
      if (argc < 2)
        printf("file name: %s\n", argv[0]);
      else
        printf("first cl argument: %s\n", argv[1]);
    }
    
    
    Ich gehe jetzt mal davon aus, dass du dich mit C schon halbwegs auskennst und weisst was da passiert.

    Das habe ich jetzt mit "gcc -S ./cl-args.c -fverbose-asm" in asm code umgewandelt (cl-args.s).

    Der relevante asm code sieht wie folgt aus:

    Code:
    	.file	"cl-args.c"
    	.section	.rodata
    .LC0:
    	.string	"file name: %s\n"
    .LC1:
    	.string	"first cl argument: %s\n"
    	.text
    .globl main
    	.type	main, @function
    main:
    .LFB2:
    	pushq	%rbp	#
    .LCFI0:
    	movq	%rsp, %rbp	#,
    .LCFI1:
    	subq	$16, %rsp	#,
    .LCFI2:
    	movl	%edi, -4(%rbp)	# argc, argc
    	movq	%rsi, -16(%rbp)	# argv, argv
    	cmpl	$1, -4(%rbp)	#, argc
    	jg	.L2	#,
    	movq	-16(%rbp), %rax	# argv, argv
    	movq	(%rax), %rsi	#* argv, D.2135
    	movl	$.LC0, %edi	#,
    	movl	$0, %eax	#,
    	call	printf	#
    	jmp	.L6	#
    .L2:
    	movq	-16(%rbp), %rax	# argv, D.2136
    	addq	$8, %rax	#, D.2136
    	movq	(%rax), %rsi	#* D.2136, D.2137
    	movl	$.LC1, %edi	#,
    	movl	$0, %eax	#,
    	call	printf	#
    .L6:
    	leave
    	ret
    
    In der generierten Datei steht noch mehr, aber ich denke das ist der wichtige Teil.
    So wie es aussieht, steht argc direkt nach Programmaufruf in %edi und der argv Pointer in %rsi (auf 32 bit systemen ist das wahrscheinlich einfach %esi).

    Ich weiss jetzt nicht genau wie weit du so mit deinem Assembler Wissen bist und wie klar obiger Code fuer dich ist. Insbesondere musst du 64 bit Assembly und die AT&T Syntax verstehen um mit dem Code was anfangen zu koennen.
    Sag Bescheid falls etwas Unklar ist, aber ich finde den Code eigentlich recht aussagekraeftig.

    mfg,
    bytepool
     
  4. #3 bytepool, 05.04.2009
    Zuletzt bearbeitet: 05.04.2009
    bytepool

    bytepool Code Monkey

    Dabei seit:
    12.07.2003
    Beiträge:
    791
    Zustimmungen:
    0
    Ort:
    /home/sweden/göteborg
    Hi,

    man sollte Assembler Code doch immer direkt vernuenftig kommentieren. Als ich das schrieb, war mir klar was da geschieht, jetzt ein 3/4 Jahr spaeter finde ich das nicht mehr so klar.

    Ich glaube ich mache mir jetzt doch nochmal die Muehe das Stueck fuer Stueck durch zu gehen, und zu kommentieren, und wenn es nur fuer mich selber ist. ;)

    Code:
    	.file	"cl-args.c"
    	.section	.rodata
    .LC0:
    	.string	"file name: %s\n"
    .LC1:
    	.string	"first cl argument: %s\n"
    	.text
    .globl main
    	.type	main, @function
    main:
    .LFB2:
    	pushq	%rbp	        # sichere den base pointer auf dem Stack
    .LCFI0:
    	movq	%rsp, %rbp	# schreibe den alten stack pointer in den base pointer
    .LCFI1:
    	subq	$16, %rsp	# reserviere 16 byte auf dem Stack
    .LCFI2:
    	movl	%edi, -4(%rbp)	# schreibe argc auf den Stack, in den dafuer reservierten Bereich
    	movq	%rsi, -16(%rbp)	# schreibe argv auf den Stack
    	cmpl	$1, -4(%rbp)	# compare(1, argc)
    	jg	.L2	        # if (argc > 1): goto .L2
    	movq	-16(%rbp), %rax	# schreibe argv in Register rax
    	movq	(%rax), %rsi	# schreibe argv[0] in rsi
    	movl	$.LC0, %edi	# schreibe die Adresse von string .LC0 in edi
    	movl	$0, %eax	# eax = 0
    	call	printf	        # rufe printf auf
    	jmp	.L6	        # goto .L6
    .L2:
    	movq	-16(%rbp), %rax	# schreibe argv in Register rax
    	addq	$8, %rax	# fuege 8 byte zu rax hinzu (rax zeigt nun auf argv[1])
    	movq	(%rax), %rsi	# schreibe argv[1] in rsi
    	movl	$.LC1, %edi	# schreibe die Adresse von string .LC1 in edi
    	movl	$0, %eax	# eax = 0
    	call	printf	        # rufe printf auf
    .L6:
    	leave                   # stelle alte Register Zustaende wieder her
    	ret                     # return
    
    Sollte ich etwas falsch kommentiert haben, duerft ihr mich gerne korrigieren. ;)

    mfg,
    bytepool
     
  5. Akendo

    Akendo 4k3nd0

    Dabei seit:
    05.02.2008
    Beiträge:
    396
    Zustimmungen:
    0
    Nur aus Interesse, wozu brauchst den Assembler Code?
     
  6. #5 bytepool, 05.04.2009
    bytepool

    bytepool Code Monkey

    Dabei seit:
    12.07.2003
    Beiträge:
    791
    Zustimmungen:
    0
    Ort:
    /home/sweden/göteborg
    Hi,

    wen meinst du jetzt, den TE oder mich? Ich brauche diesen konkreten Code gar nicht, aber ich mag es nicht, wenn ich irgendwo Code veroeffentliche, den ich dann ein Jahr spaeter selber nicht mehr verstehe. Daher nun nochmal die ausfuehrlicheren Kommentare. ;)

    Wenn deine Frage eher darauf abzielt, wofuer man Assembler heutzutage ueberhaupt noch braucht, waere die Antwort dass ich zu den Leuten gehoere, die glauben dass low-level Verstaendnis auch auf hoeheren Abstraktionsebenen sehr hilfreich ist. Aber ich kaeme sicherlich auch nicht auf die Idee ein ganzes Programm in Assembler zu schreiben.

    Doch wenn du dich zum Beispiel mit security bugs beschaeftigst, kommst du um Assembler nicht herum. D.h. auch wenn du "nur" sichere C Programme schreiben willst, hilft ein tieferes Verstaendnis, was da bei Ausfuehrung eigentlich genau passiert. Aber auch da gibt es unterschiedliche Meinungen zu.

    mfg,
    bytepool
     
  7. Anzeige

    Vielleicht findest du HIER Antworten.
    Registrieren bzw. einloggen, um diese und auch andere Anzeigen zu deaktivieren
  8. Akendo

    Akendo 4k3nd0

    Dabei seit:
    05.02.2008
    Beiträge:
    396
    Zustimmungen:
    0
    Naja der Thread ist schon etwas älter, meinte dazu den TE.
     
  9. #7 diciani, 19.05.2009
    diciani

    diciani Grünschnabel

    Dabei seit:
    19.05.2009
    Beiträge:
    3
    Zustimmungen:
    0
    Ort:
    Berlin
    Vielen Dank bytepool, das verbesserte Stück Code ist nicht nur für dich. Und außerdem per google von jedem Suchenden auffindbar. :))

    Allerdings habe ich dem noch ein paar Sachen hinzuzufügen, nachdem ich mich heute etwas mit der Sache beschäftigt habe.

    Der von dir erzeugte und kommentierte Code liefert keinerlei Argumente, wenn man ihn ausprobiert. Auch argc ist nach deiner "Methode" auch stets 0.

    Jetzt mein Erklärungsversuch: Wie ich auch erst heute gelernt habe, wird ein Programm normalerweise so erstellt, dass nicht nur der eigene Code im Binary landet, sondern allerhand libc-code dazugelinkt wird, egal ob man den braucht oder nicht...

    Code:
    int main() {
      return 0;
    }
    z.B. führt zu einem recht großen Binary und ein ldd darauf führt bei mir zu

    user@rechner:~$ ldd ./a.out
    linux-vdso.so.1 => (0x00007ffffd1ff000)
    libc.so.6 => /lib/libc.so.6 (0x00007f6cf4b30000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f6cf4e92000)

    Deswegen hört man von Neulingen manchmal auch Hilferufe wegen Fehlermeldungen ala "cannot find entry symbol _start" bei einem Hello-Wolrd-Programm, obwohl das natürliche keine "_start"-Funktion enthält.

    Außerdem fand ich es vor einiger Zeit sehr interessant, dass ein leeres
    int main() {return 0;}
    zu einem Segmentation fault führt. Was erstmal sehr erstaunlich zu sein scheint. 8o


    :oldman Anscheinend wird das eigene Programm von anderem Code gekapselt. Und zwar libc-code, der z.B. in einer "_start"-Funktion steht. Kann auch andere Namen haben, k.A... Damit fängt das fertige Programm wohl an und nicht gleich mit meiner eigenen main-Funktion. main() wird erst von diesem Kapselcode irgendwo aufgerufen und springt am Ende, nämlich beim "return 0;" wieder zu diesem Kapselcode zurück. Und eben nicht ins Betriebssystem. Der Kapselcode kann dann noch aufräumen und "richtig" beenden. Das würde auch den Segfault in dem leeren c-Programm erklären, da beim aufruf von "return 0;" ja keine gültige Rücksprungadresse auf dem Stack liegt und der Sprung "irgendwohin" geht, aber nicht dahin, wo es erlaubt ist und deswegen ein segfault ausgelöst wird.

    Das rauszufinden hat mich viel viel Zeit gekostet und ich wäre dankbar wenn mir das ein Fachkundiger bestätigen könnte :)


    Meine Frage wäre jetzt, was genau macht der Code alles? Das weiss ich bis jetzt nämlich nicht und in diesem "wusligen" glibc-Quellcode seh ich auch nicht wirklich durch, leider!?!

    Im libc-code, der nach dem "return 0;" ausgeführt wird, wird sys_exit, ein Systemaufruf zum beenden von Programmen, aufgerufen, das ist klar und am Anfang des libc-codes, also noch vor Aufrufen der main-funktion müssen die Kommandozeilenargumente irgendwo her geholt werden und gemäß der AMD64 (aka x86-64) ABI calling-conventions verpackt werden. (siehe http://en.wikipedia.org/wiki/X86_calling_conventions#AMD64_ABI_convention)

    Da sieht man auch gleich, dass die von bytepool gefundenen argc und argv parameter, die er in edi und rsi "gefunden" hat, demnach auch genau dort zu erwarten sind, weil eben dort die Funktionsparameter in C auf x86-64-Plattform landen und main(int argc, char **argv) auch nur eine normale Funktion ist. ;)


    Unter http://fixunix.com/unix/531186-how-grab-command-line-args-without-libc.html und http://asm.sourceforge.net/articles/startup.html findet man, dass die Argumente auf dem stack liegen sollen...bei 32-bit.

    Frage nun: Kann das wer bestätigen? Ist das auch unter 64-bit so?? :help:



    Ist leider etwas länglich geworden der Beitrag, aber da das recht komplex ist, ist es vielleicht besser zu viel zu schreiben, als dass irgendwer mich nicht versteht. ^^

    Hab mich sogar für diesen Beitrag extra hier im Forum angemeldet.

    Und wegen der Frage von Akendo...warum suche (auch) ich nach sowas...? xD

    Erstens schonmal aus Interesse, wie und was da alles passiert beim Kompilieren bis zum Ausführen.
    Solches Wissen bringt meiner Erfahrung nach auch viele Vorteile beim Lösen von Problemen, die man so beim Programmieren und Arbeiten oft hat.

    Außerdem kann ich es persönlich nicht leiden, wenn meine eigenen Programme mit unnötigem Code verseucht und aufgeblasen werden und ich unnötige Bibliotheksabhängigkeiten habe. bloat gibt es schon genug!

    Ein Hello-World-programm in C kann man zB auch so kompilieren, dass kein 8kb-binary entsteht :D
    Und die glibc braucht man dafür eigentlich auch überhaupt nicht, weder dynamisch noch statisch dazugelinkt, aber das ist ein anderes Thema xD
     
Thema:

Wie Programmstart-Argumente in Assembler auslesen?

Die Seite wird geladen...

Wie Programmstart-Argumente in Assembler auslesen? - Ähnliche Themen

  1. Übersicht über Assemblercode in freier Software

    Übersicht über Assemblercode in freier Software: Steve McIntyre hat für Linaro die Verwendung von Assemblercode in freier Software untersucht. Die Studie diente dazu, die Portierbarkeit auf die...
  2. Assembler, Linux und Keyboard HIT-Abfangen

    Assembler, Linux und Keyboard HIT-Abfangen: Hallo allerseits. Ich mach das Buch Art Of Assembly durch, seit 2 Jahren mach ich endlich wieder weiter damit, schei.... Pause, aber musste...
  3. objdump als disassembler

    objdump als disassembler: hallo, ich möchte eine (ELF-)ausführbare datei mit objdump disassemblieren (at&t syntax). wenn ich das mit objdump -d mache, bekomme ich zwar...
  4. assembler->os

    assembler->os: hallo leute, kann mir jemand ein buch/onlinetutorial empfehlen in dem man assembler auf os basis programmieren kann. also ich würde gern ein os...
  5. Assembler Programmierung

    Assembler Programmierung: Hallo, ich würde gerne Assembler lernen. Welche Programme brauche ich dazu? Kennt ihr gute Tutorial? Was würdet ihr mir sonst noch raten? Ich habe...