Ich dachte, dass es nur einen GOT im Prozessspeicher gibt, aber diese Bibliothek verweist auf GOT?
Wir sehen deutlich .got
Abschnitt als Teil der Bibliothek. Mit readelf
können wir das finden, was die Abschnitte der Bibliothek sind und wie sie geladen werden:
readelf -e liblib1.so
...
Section Headers:
[21] .got PROGBITS 0000000000200fd0 00000fd0
0000000000000030 0000000000000008 WA 0 0 8
...
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x000000000000078c 0x000000000000078c R E 200000
LOAD 0x0000000000000df8 0x0000000000200df8 0x0000000000200df8
0x0000000000000230 0x0000000000000238 RW 200000
...
Section to Segment mapping:
Segment Sections...
00 ... .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame
01 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
02 .dynamic
So gibt Abschnitt ist .got
, aber runtime linker ld-linux.so.2
(registriert als Dolmetscher für die dynamische ELFs) Abschnitte nicht geladen werden; es lädt Segmente wie vom Programmkopf mit dem Typ LOAD
beschrieben. .got
ist Teil von Segment 01 LOAD mit RW-Flags. Andere Bibliotheken haben eigene GOT (denken Sie daran, dass Sie liblib2.so aus der gleichen Quelle kompilieren, es wird nichts über liblib1.so wissen und wird GOT haben); so ist es "global" nur für die Bibliothek; aber nicht auf das gesamte Programmbild im Speicher nach dem Laden.
Wie shared library weiß, Offset zu Prozess GOT, wenn es (PIC-Bibliothek) nicht weiß, wo im Prozessspeicher würde es geladen werden?
Es wird von statischen Linker getan, wenn es mehrere ELF-Objekte benötigt und sie alle in einer Bibliothek kombinieren.Linker erzeugt .got
Abschnitt und legte es an einer Stelle mit bekannten Offset aus dem Bibliothekscode (pc-relative, rip-relative). Es schreibt Anweisungen in den Programmheader, so dass die relative Adresse bekannt ist und es die einzige benötigte Adresse ist, um auf den eigenen GOT zuzugreifen.
Wenn objdump
mit -r
/-R
Flags verwendet wird, wird es Informationen über Umlagerungen (statisch/dynamisch) drucken, die in der ELF-Datei oder -Bibliothek aufgezeichnet sind; es kann mit dem Flag -d kombiniert werden. lib1.o Objekt hatte hier Umzug; nicht zu GOT bekannten Versatz, mov hat alle Null:
$ objdump -dr lib1.o
lib1.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <shara_func>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax # b <shara_func+0xb>
7: R_X86_64_REX_GOTPCRELX var-0x4
b: 48 8b 00 mov (%rax),%rax
e: 48 89 c6 mov %rax,%rsi
In-Bibliotheksdatei dies durch gcc -shared
auf die relative Adresse umgewandelt wurde (es nennt ld
Variante collect2
innen):
$ objdump -d liblib1.so
liblib1.so: file format elf64-x86-64
00000000000006d0 <shara_func>:
6d0: 55 push %rbp
6d1: 48 89 e5 mov %rsp,%rbp
6d4: 48 8b 05 fd 08 20 00 mov 0x2008fd(%rip),%rax # 200fd8 <_DYNAMIC+0x1c8>
Und schließlich gibt es dynamische Verlagerung in GOT hier aktuelle Adresse von var setzen (done von rtld - ld-linux.so.2):
$ objdump -R liblib1.so
liblib1.so: file format elf64-x86-64
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
...
0000000000200fd8 R_X86_64_GLOB_DAT var
Lassen Sie uns Ihre lib verwenden, fügen ing ausführbare Datei mit Definition, es läuft mit rtld Debuggen aktiviert Kompilieren:
$ cat main.c
long var;
int main(){
shara_func();
return 0;
}
$ gcc main.c -llib1 -L. -o main -Wl,-rpath=`pwd`
$ LD_DEBUG=all ./main 2>&1 |less
...
311: symbol=var; lookup in file=./main [0]
311: binding file /test3/liblib1.so [0] to ./main [0]: normal symbol `var'
So Linker konnte Umzug binden, für var
an die "main" ELF-Datei, wo es definiert:
$ gdb -q ./main
Reading symbols from ./main...(no debugging symbols found)...done.
(gdb) b main
Breakpoint 1 at 0x4006da
(gdb) r
Starting program: /test3/main
Breakpoint 1, 0x00000000004006da in main()
(gdb) disassemble shara_func
Dump of assembler code for function shara_func:
0x00007ffff7bd56d0 <+0>: push %rbp
0x00007ffff7bd56d1 <+1>: mov %rsp,%rbp
0x00007ffff7bd56d4 <+4>: mov 0x2008fd(%rip),%rax # 0x7ffff7dd5fd8
0x00007ffff7bd56db <+11>: mov (%rax),%rax
0x00007ffff7bd56de <+14>: mov %rax,%rsi
Keine Änderungen in mov in Ihrem func. rax nach Func + 4 0x601040 ist, ist es dritte Abbildung von ./main nach/proc/pid $/maps:
00601000-00602000 rw-p 00001000 08:07 6691394 /test3/main
Und es wurde aus dem Haupt nach diesem Programmkopf geladen (readelf-./main
)
LOAD 0x0000000000000df0 0x0000000000600df0 0x0000000000600df0
0x0000000000000248 0x0000000000000258 RW 200000
Es ist Teil .bss Abschnitt:
[26] .bss NOBITS 0000000000601038 00001038
0000000000000010 0000000000000000 WA 0 0 8
nach dem func Schritt + 11, können wir Wert in GOT überprüfen:
(gdb) b shara_func
(gdb) r
(gdb) si
0x00007ffff7bd56db in shara_func() from /test3/liblib1.so
1: x/i $pc
=> 0x7ffff7bd56db <shara_func+11>: mov (%rax),%rax
(gdb) p $rip+0x2008fd
$6 = (void (*)()) 0x7ffff7dd5fd8
(gdb) x/2x 0x7ffff7dd5fd8
0x7ffff7dd5fd8: 0x00601040 0x00000000
Wer hat den richtigen Wert in diesen GOT-Eintrag geschrieben?
(gdb) watch *0x7ffff7dd5fd8
Hardware watchpoint 2: *0x7ffff7dd5fd8
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /test3/main
Hardware watchpoint 2: *0x7ffff7dd5fd8
Old value = <unreadable>
New value = 6295616
0x00007ffff7de36bf in elf_machine_rela (..) at ../sysdeps/x86_64/dl-machine.h:435
(gdb) bt
#0 0x00007ffff7de36bf in elf_machine_rela (...) at ../sysdeps/x86_64/dl-machine.h:435
#1 elf_dynamic_do_Rela (...) at do-rel.h:137
#2 _dl_relocate_object (...) at dl-reloc.c:258
#3 0x00007ffff7ddaf5b in dl_main (...) at rtld.c:2072
#4 0x00007ffff7df0462 in _dl_sysdep_start ([email protected]=0x7fffffffde20,
[email protected]=0x7ffff7dd89a0 <dl_main>) at ../elf/dl-sysdep.c:249
#5 0x00007ffff7ddbe7a in _dl_start_final (arg=0x7fffffffde20) at rtld.c:307
#6 _dl_start (arg=0x7fffffffde20) at rtld.c:413
#7 0x00007ffff7dd7cc8 in _start() from /lib64/ld-linux-x86-64.so.2
(gdb) x/2x 0x7ffff7dd5fd8
0x7ffff7dd5fd8: 0x00601040 0x00000000
Runtime-Linker von glibc tat (rtld.c), kurz vor main
Aufruf - hier ist die Quelle (etwas andere Version) - http://code.metager.de/source/xref/gnu/glibc/sysdeps/x86_64/dl-machine.h
329 case R_X86_64_GLOB_DAT:
330 case R_X86_64_JUMP_SLOT:
331 *reloc_addr = value + reloc->r_addend;
332 break;
Mit Reverse-Stepping wir die Geschichte von Code bekommen und alter Wert = 0:
(gdb) b _dl_relocate_object
(gdb) r
(gdb) dis 3
(gdb) target record-full
(gdb) c
(gdb) disp/i $pc
(gdb) rsi
(gdb) rsi
(gdb) rsi
(gdb) x/2x 0x7ffff7dd5fd8
0x7ffff7dd5fd8: 0x00000000 0x00000000
=> 0x7ffff7de36b8 <_dl_relocate_object+1560>: add 0x10(%rbx),%rax
=> 0x7ffff7de36bc <_dl_relocate_object+1564>: mov %rax,(%r10)
=> 0x7ffff7de36bf <_dl_relocate_object+1567>: nop
Bulat, haben Sie überprüfen 'objdump -r' und' objdump -r' Suche nach RELOC (Verlagerungen) in Ihrem ELF - http://man7.org/linux/man- Seiten/man1/objdump.1.html? – osgx
@osgx, ja, das ist 0x200fd8 R_X86_64_GLOB_DAT var + 0 relocation. PC-relativ: 0x2008fd + 0x6db = 0x200fd8. Ich verstehe nicht, wie Linker 0x2008fd Offset berechnet, wie es weiß, wo Prozess GOT in Runtime befindet. –
Bulat, die Wahrheit ist: Es gibt zwei Linker: Einer ist 'ld' Befehl und andere ist Runtime Linker, RTLD,' ld-linux.so.2'-Programm in Linux (es ist als Interpreter von dynamischen ELFs registriert - http://stackoverflow.com/questions/5130654). R_X86_64_GLOB_DAT, erstellt von ld-Linker, wird also vom RTLD-Laufzeit-Linker aufgelöst: http://osxr.org:8080/glibc/source/sysdeps/x86_64/dl-machine.h#0304. Es ist derjenige, der die lib-Datei öffnet; Mmaps es an den richtigen Ort, erstellen Sie die echte GOT und löst Umlagerungen auf echte GOT zeigen. – osgx