2015-04-07 15 views
5

Per studiare come il file oggetto è stato caricato ed eseguito in linux, ho creato il codice c più semplice, nome file simple.c.come funziona __libc_start_main @ plt?

int main(){} 

Successivamente, eseguo il file oggetto e salva il file oggetto come file di testo.

$gcc ./simple.c 
$objdump -xD ./a.out > simple.text 

Da molti articoli su internet, ho potuto prendere che gcc caricare dinamicamente funzioni avvio come _start, _init, __libc_start_main @ plt, e così via. Così ho iniziato a leggere il mio codice assembly, aiutato da http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html.

Ecco una parte del codice assembly.

080482e0 <[email protected]>: 
80482e0:  ff 25 10 a0 04 08  jmp *0x804a010 
80482e6:  68 08 00 00 00   push $0x8 
80482eb:  e9 d0 ff ff ff   jmp 80482c0 <_init+0x2c> 

Disassembly of section .text: 

080482f0 <_start>: 
80482f0:  31 ed     xor %ebp,%ebp 
80482f2:  5e      pop %esi 
80482f3:  89 e1     mov %esp,%ecx 
80482f5:  83 e4 f0    and $0xfffffff0,%esp 
80482f8:  50      push %eax 
80482f9:  54      push %esp 
80482fa:  52      push %edx 
80482fb:  68 70 84 04 08   push $0x8048470 
8048300:  68 00 84 04 08   push $0x8048400 
8048305:  51      push %ecx 
8048306:  56      push %esi 
8048307:  68 ed 83 04 08   push $0x80483ed 
804830c:  e8 cf ff ff ff   call 80482e0 <[email protected]> 
8048311:  f4      hlt 
8048312:  66 90     xchg %ax,%ax 
8048314:  66 90     xchg %ax,%ax 
8048316:  66 90     xchg %ax,%ax 
8048318:  66 90     xchg %ax,%ax 
804831a:  66 90     xchg %ax,%ax 
804831c:  66 90     xchg %ax,%ax 
804831e:  66 90     xchg %ax,%ax 

080483ed <main>: 
80483ed:  55      push %ebp 
80483ee:  89 e5     mov %esp,%ebp 
80483f0:  b8 00 00 00 00   mov $0x0,%eax 
80483f5:  5d      pop %ebp 
80483f6:  c3      ret 
80483f7:  66 90     xchg %ax,%ax 
80483f9:  66 90     xchg %ax,%ax 
80483fb:  66 90     xchg %ax,%ax 
80483fd:  66 90     xchg %ax,%ax 
80483ff:  90      nop 



... 

Disassembly of section .got: 

08049ffc <.got>: 
8049ffc:  00 00     add %al,(%eax) 
     ... 

Disassembly of section .got.plt: 

0804a000 <_GLOBAL_OFFSET_TABLE_>: 
804a000:  14 9f     adc $0x9f,%al 
804a002:  04 08     add $0x8,%al 
     ... 
804a00c:  d6      (bad) 
804a00d:  82      (bad) 
804a00e:  04 08     add $0x8,%al 
804a010:  e6 82     out %al,$0x82 
804a012:  04 08     add $0x8,%al 

La mia domanda è;

In 0x804830c, viene chiamato 0x80482e0 (ho già preso le istruzioni precedenti).

In 0x80482e0, il processo passa a 0x804a010.

Nel 0x804a010, l'istruzione è < out% al, $ 0x82>

... aspettare. appena fuori? Cosa c'era in% al e dov'è 0x82 ?? Sono rimasto bloccato in questa linea.

Please help ....

* p.s. Sono principiante di Linux e sistema operativo. Sto studiando i concetti del sistema operativo per classe, ma ancora non riesco a trovare il modo di studiare il corretto linguaggio di assemblaggio linux. Ho già scaricato il manuale del processore Intel, ma è troppo grande da leggere. Qualcuno può informarmi del buon materiale per me? Grazie.

risposta

6
80482e0:  ff 25 10 a0 04 08  jmp *0x804a010 

Ciò significa "recuperare l'indirizzo a 4 byte memorizzato su 0x804a010 e passare direttamente ad esso."

804a010:  e6 82     out %al,$0x82 
804a012:  04 08     add $0x8,%al 

quelle 4 byte sarà trattato come un indirizzo, 0x80482e6, non come istruzioni.

80482e0:  ff 25 10 a0 04 08  jmp *0x804a010 
80482e6:  68 08 00 00 00   push $0x8 
80482eb:  e9 d0 ff ff ff   jmp 80482c0 <_init+0x2c> 

Quindi abbiamo appena eseguito un'istruzione che ci ha spostato esattamente un'istruzione in avanti. A questo punto, probabilmente ti starai chiedendo se c'è una buona ragione per questo.

C'è. Questa è una tipica implementazione PLT/GOT. Molti più dettagli, incluso un diagramma, sono a Position Independent Code in shared libraries: The Procedure Linkage Table.

Il codice reale per __libc_start_main è in una libreria condivisa, glibc.Il compilatore e compilare in tempo linker non sanno dove il codice sarà in fase di esecuzione, in modo da inserire nel programma compilato una breve funzione di __libc_start_main che contiene solo tre istruzioni:

  • salto ad una posizione specificata dal il 4 ° (o 5, a seconda se vi piace a contare da 0 o 1) iscrizione nel GOT
  • spinta $ 8 sul stack di
  • salto per un resolver routine di

la prima volta che si chiama __libc_start_main , il codice del risolutore verrà eseguito. Troverà la posizione attuale di __libc_start_main in una libreria condivisa e applicherà la quarta voce del GOT a quell'indirizzo. Se il tuo programma chiama di nuovo __libc_start_main, l'istruzione jmp *0x804a010 porterà il programma direttamente al codice nella libreria condivisa.

Qualcuno può informarmi del buon materiale per me?

Il libro x86 Assembly su Wikibooks potrebbe essere un punto di partenza.

+0

Che bella spiegazione! Grazie! – casamia

+0

Sospetto che '__libc_start_main' debba chiamare il programma principale e fare una chiamata di sistema per uscire con il valore di ritorno. Ti piacerebbe espandere la necessità di 'hlt' (sospetto che sia per consentire casi in cui c'è un ritardo/gara con pulizia in uscita sys),' hlt' è un'istruzione privilegiata, è il punto giusto per intrappolare l'illegale istruzioni se arriva lì? Che mi dici della slitta di 'xchg'? –

+0

* xchg nop slitta. –