Das Tutorial, das Sie gerade lesen, stimmt nicht ganz. Es gab zwei unterschiedliche Konventionen für globale Symbole in den ausführbaren ELF-Dateien (ausführbare und verknüpfbare Formate). Eine Konvention besagt, dass allen globalen C-Symbolen das Präfix _
vorangestellt sein sollte, während die andere Konvention den C-Symbolen nicht vorangestellt ist. In GNU/Linux, insbesondere in x86-64 ABI, haben die globalen Symbole kein Präfix _
. Allerdings könnte das Tutorial, das Sie verknüpft haben, für einige andere Compiler für Linux/ELF, die nicht die GNU-libc verwendet haben.
Nun, was in Ihrem ursprünglichen Code geschieht, ist, dass Ihre Assembler-Funktion als _write
in C-Code sichtbar wäre, nicht write
. Stattdessen wird das write
Symbol in der libc
(der Wrapper für write(2)
Systemaufruf) gefunden:
ssize_t write(int fd, const void *buf, size_t count);
Jetzt erklärt man diesewrite
als Funktion void write(void);
, die als solche undefinierten Verhalten führt, wenn Sie anrufen es. Sie können strace ./program
verwenden, um herauszufinden, was System nennt es macht:
% strace ./program
...
write(1, "\246^P\313\374\177\0\0\0\0\0\0\0\0"..., 140723719521144) = -1 EFAULT (Bad address)
...
So nannte es den write
Systemaufruf nicht mit Ihren beabsichtigten Argumenten, sondern mit dem, was Müll gibt es in den dafür vorgesehenen Registern write
Wrapper glibc.(Eigentlich ist der "Müll" hier bekannt - erstes Argument ist das argc
, und das zweite Argument ist der Wert argv
und das dritte Argument ist der Wert char **environ
). Und als der Kernel bemerkte, dass ein Puffer, der bei (void*)argv
und 140723719521144 Bytes lang begann, nicht vollständig innerhalb des abgebildeten Adressraums enthalten war, gab er EFAULT
von diesem Systemaufruf zurück. Ergebnis: kein Absturz, keine Nachricht.
write
ist kein reserviertes Wort als solches in C. Es ist eine Funktion, und möglicherweise ein Makro in POSIX. Sie könnte überschreiben, die Verknüpfung Reihenfolge von Bedeutung - wenn Sie definiert write
Programm, würde andere Code gegen diese Definition anstelle der in Glibc gefunden werden. Dies würde jedoch bedeuten, dass ein anderer Code, der write
aufruft, stattdessen Ihre inkompatible Funktion aufruft.
Die Lösung besteht also darin, keinen Namen zu verwenden, der eine Funktion in der GNU libc oder in anderen Bibliotheken ist, mit denen Sie verknüpft sind. So ist in Assembler können Sie:
.global writehello
writehello:
und dann
extern void writehello(void);
wie Sie selbst herausgefunden haben.
OK, gut, wenn Sie einen Haltepunkt auf dem 'pushq% rbp' setzen, wird es geschlagen? –
Wie ich bereits in Ihrer früheren Eingabe erwähnt habe, ist 'write' ein reserviertes Wort in 'C'. Benennen Sie Ihre Funktion um und versuchen Sie es erneut. – KevinDTimm
Korrektur: Es ist kein reserviertes Wort, aber es ist eine Funktion, die häufig von 'C'-Programmen verwendet wird und möglicherweise mit Ihrem Programm verknüpft ist, bevor Ihre lokale Funktion aufgerufen wird. Mein Rat steht. – KevinDTimm