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...
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.
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??
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
Und die glibc braucht man dafür eigentlich auch überhaupt nicht, weder dynamisch noch statisch dazugelinkt, aber das ist ein anderes Thema xD