2015-04-07 8 views
5

Um zu studieren, wie die Objektdatei in Linux geladen und ausgeführt wird, habe ich den einfachsten c-Code, Dateiname simple.c.Wie funktioniert __libc_start_main @ plt?

int main(){} 

Als nächstes mache ich Objektdatei und speichern Objektdatei als Textdatei.

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

Von vielen Internet-Artikeln, konnte ich wie _start, _init, __libc_start_main @ PLT, und so weiter laden Einleitung Funktionen, dass gcc dynamisch fangen. Also fing ich an, meinen Assembler-Code zu lesen, unterstützt von http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html.

Hier ist ein Teil des Assembler-Codes.

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 

Meine Frage ist;

In 0x804830c wird 0x80482e0 aufgerufen (ich habe bereits die vorherigen Anweisungen verstanden.).

In 0x80482e0 springt der Prozess zu 0x804a010.

In 0x804a010, der Befehl < out% al, 0x82 $>

... warten. rein raus? Was war im% al und wo ist 0x82 ?? Ich bin in dieser Linie stecken geblieben.

Bitte helfen Sie ...

* ps. Ich bin Anfänger zu Linux und Betriebssystem. Ich studiere Betriebssystemkonzepte nach Schulklassen, kann aber immer noch nicht herausfinden, wie man die richtige Linux-Assemblersprache lernt. Ich habe bereits Intel Prozessor manuell heruntergeladen, aber es ist zu groß zum Lesen. Kann mir jemand gutes Material für mich mitteilen? Vielen Dank.

Antwort

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

Dies bedeutet "die 4-Byte-Adresse abrufen, die bei 0x804a010 gespeichert ist, und zu dieser springen."

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

Those 4 Bytes wird als Adresse behandelt werden, 0x80482e6, nicht als Anweisungen.

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> 

Also haben wir gerade eine Anweisung ausgeführt, die uns genau eine Anweisung nach vorne gebracht hat. An dieser Stelle fragen Sie sich wahrscheinlich, ob es einen guten Grund dafür gibt.

Es gibt. Dies ist eine typische PLT/GOT-Implementierung. Viel mehr Details, einschließlich eines Diagramms, sind bei Position Independent Code in shared libraries: The Procedure Linkage Table. Der echte Code für __libc_start_main ist in einer gemeinsam genutzten Bibliothek, glibc.Der Compiler und Compiler-Linker nicht wissen, wo der Code zur Laufzeit sein, so dass sie Platz in Ihrem kompilierte Programm eine kurze __libc_start_main Funktion, die nur drei Befehle enthält:

  • Sprung zu einem angegebenen Ort durch die vierte Eintrag in dem GOT
  • Push $ 8 auf den Stapel
  • Sprung zu einem Resolver-Routine

das erste Mal, wenn Sie __libc_start_main nennen (oder 5., je nachdem, ob Sie von 0 oder 1 zählen) , der Resolver-Code wird ausgeführt. Es wird den tatsächlichen Standort von __libc_start_main in einer gemeinsam genutzten Bibliothek finden und den vierten Eintrag des GOT als diese Adresse patchen. Wenn Ihr Programm erneut __libc_start_main aufruft, wird die Anweisung jmp *0x804a010 das Programm direkt zu dem Code in der gemeinsam genutzten Bibliothek führen.

Kann mir jemand gutes Material für mich mitteilen?

Die x86 Assembly Buch bei Wikibooks könnte ein Ort sein, um zu starten.

+0

Was für eine schöne Erklärung! Vielen Dank! – casamia

+0

Ich vermute, dass '__libc_start_main' das Programmhaupt aufrufen soll und einen Systemaufruf zum Beenden mit dem Rückgabewert machen soll. Möchten Sie die Notwendigkeit von "hlt" erweitern (ich vermute, dass es Fälle zulässt, in denen es eine Verzögerung/ein Rennen mit Aufräumarbeiten in sys exit gibt), ist 'hlt' eine privilegierte Anweisung, ist der Punkt, nur um das illegale zu fangen Anweisung, wenn es dort ankommt? Was ist mit dem Schlitten von 'xchg'? –

+0

* xchg nop Schlitten. –