Forums Neueste Beiträge
 

libc_nonshared.a

22/06/2010 - 10:28 von Markus Wichmann | Report spam
Hi all,

kann mir mal jemand den Sinn der im Betreff genannten Datei nennen? Ich
meine, sie enthàlt folgende Funktionen:

__libc_csu_fini
__libc_csu_init
at_quick_exit
atexit
fstat
fstat64
fstatat
fstatat64
lstat
lstat64
mknod
mknodat
nop
stat
stat64

Für atexit und at_quick_exit hab ich schon Begründungen gefunden,
nàmlich, dass mit atexit registrierte Funktionen auch ausgeführt werden,
wenn das atexit in einem DSO kam und jemand dasselbe mit expliziten
Aufrufen zu dlopen() geladen hat. (Weil dann das dazugehörige dlclose()
lange vor dem exit() kommen kann.)

Soweit, so gut, aber ich habe dennoch in den Standards (SUSv3, ISO-C99)
nichts gefunden, was darauf hinweisen würde, dass man atexit() überhaupt
auf diese Weise einsetzen darf. IOW: Mit einer ekelhaften Kludge
(/usr/lib/libc.so als Linkerskript) wird hier Funktionalitàt
hergestellt, auf die sich sowieso niemand verlassen kann, die also
niemand ernsthaft benutzen können will. Für Funktionen, die unbedingt
bei der Entladung einer Lib ausgeführt werden müssen, gibt es außerdem
den Eintrag DT_FINI im PT_DYNAMIC-Segment des DSO, und dessen
Funktionaitàt wird vom ELF-Standard abgesichert. Jeder halbwegs
konformante Lader muss das unterstützen.

Die zwei Funktionen __libc_csu_* sind Abhàngigkeiten aus
/usr/lib/crt1.o. Ich habe sie mal disassembliert: __libc_csu_fini tut
_gar_nichts_. __libc_csu_init macht irgendwas, von dessen Sinnhaftigkeit
ich noch nicht restlos überzeugt bin: Erst werden r15 bis r12 gesichert,
dann wird auf komplizierte Weise 0x4a - 0x29 berechnet und dann gucken
wir, ob das Ergebnis (0x21) kleiner als 7 ist. WTF? Aber richtig seltsam
ist das folgende:

xor ebx, ebx ; erste Änderung von rbx in dieser Funktion
[...]
call [r15+rbx*8]

Was soll das denn? Entweder rbx war vorher kleiner als 4G, dann springt
die ganze Aktion wieder zum Beginn der Funktion, oder rbx war vor
Funktionsaufruf größer als 4G, dann springt diese Anweisung wenigstens
32 GB nach vorne.

Aber am meisten bin ich über die ganzen Syscalls erstaunt. Was sollen
die dort? Ein syscall hàngt doch nicht von statischen Daten ab, oder?

Tschö,
Markus
 

Lesen sie die antworten

#1 Sven Joachim
22/06/2010 - 12:01 | Warnen spam
Am 22.06.2010 um 10:28 schrieb Markus Wichmann:

Hi all,

kann mir mal jemand den Sinn der im Betreff genannten Datei nennen? Ich
meine, sie enthàlt folgende Funktionen:

__libc_csu_fini
__libc_csu_init
at_quick_exit
atexit
fstat
fstat64
fstatat
fstatat64
lstat
lstat64
mknod
mknodat
nop
stat
stat64

Für atexit und at_quick_exit hab ich schon Begründungen gefunden,
nàmlich, dass mit atexit registrierte Funktionen auch ausgeführt werden,
wenn das atexit in einem DSO kam und jemand dasselbe mit expliziten
Aufrufen zu dlopen() geladen hat. (Weil dann das dazugehörige dlclose()
lange vor dem exit() kommen kann.)

Soweit, so gut, aber ich habe dennoch in den Standards (SUSv3, ISO-C99)
nichts gefunden, was darauf hinweisen würde, dass man atexit() überhaupt
auf diese Weise einsetzen darf. IOW: Mit einer ekelhaften Kludge
(/usr/lib/libc.so als Linkerskript) wird hier Funktionalitàt
hergestellt, auf die sich sowieso niemand verlassen kann, die also
niemand ernsthaft benutzen können will. Für Funktionen, die unbedingt
bei der Entladung einer Lib ausgeführt werden müssen, gibt es außerdem
den Eintrag DT_FINI im PT_DYNAMIC-Segment des DSO, und dessen
Funktionaitàt wird vom ELF-Standard abgesichert. Jeder halbwegs
konformante Lader muss das unterstützen.



Das mag sein, aber weißt du, welche Bibliotheken atexit() aufrufen und
was kaputt geht, wenn die derzeitige Semantik geàndert wird?
Binàrkompatibilitàt ist der glibc heilig.

Die zwei Funktionen __libc_csu_* sind Abhàngigkeiten aus
/usr/lib/crt1.o.



In neueren glibc-Versionen ist stattdessen elf-init enthalten, was
Referenzen auf diese beiden Funktionen enthàlt.

Ich habe sie mal disassembliert: __libc_csu_fini tut
_gar_nichts_. __libc_csu_init macht irgendwas, von dessen Sinnhaftigkeit
ich noch nicht restlos überzeugt bin: Erst werden r15 bis r12 gesichert,
dann wird auf komplizierte Weise 0x4a - 0x29 berechnet und dann gucken
wir, ob das Ergebnis (0x21) kleiner als 7 ist. WTF? Aber richtig seltsam
ist das folgende:

xor ebx, ebx ; erste Änderung von rbx in dieser Funktion
[...]
call [r15+rbx*8]

Was soll das denn? Entweder rbx war vorher kleiner als 4G, dann springt
die ganze Aktion wieder zum Beginn der Funktion, oder rbx war vor
Funktionsaufruf größer als 4G, dann springt diese Anweisung wenigstens
32 GB nach vorne.



Du hàttest auch in csu/elf-init.c einer aktuellen glibc-Version
nachschlagen können.

Aber am meisten bin ich über die ganzen Syscalls erstaunt. Was sollen
die dort? Ein syscall hàngt doch nicht von statischen Daten ab, oder?



Siehe io/stat.c:

,-
| /* This definition is only used if inlining fails for this function; see
| the last page of <sys/stat.h>. The real work is done by the `x'
| function which is passed a version number argument. We arrange in the
| makefile that when not inlined this function is always statically
| linked; that way a dynamically-linked executable always encodes the
| version number corresponding to the data structures it uses, so the `x'
| functions in the shared library can adapt without needing to recompile
| all callers. */
|
| #undef stat
| int
| attribute_hidden
| __stat (const char *file, struct stat *buf)
| {
| return __xstat (_STAT_VER, file, buf);
| }
|
| weak_hidden_alias (__stat, stat)
`-

Sven

Ähnliche fragen