Autor Thema: switch setzt EIP auf 0x0  (Gelesen 2527 mal)

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« am: 27. September 2011, 22:53 »
Nabend zusammen,

ich bin gerade dabei die ACPI-Tabellen auszulesen und habe mir eine Switch-Anweisung geschrieben, damit ich die verschiedenen APIC-Strukturen aus der MADT auslesen kann.
Diese Anweisung setzt den EIP auf 0x0.

Hier der Code:
switch (apic->type) {
case MADT_LAPIC:
lapic = (struct lapic*)apic;
offset = sizeof(struct lapic);

if(hit_if(!lapic->flags))
cpu_count++;
break;
case MADT_IO_APIC:
offset = sizeof(struct ioapic);
break;
case MADT_INT_SRC_OVERRIDE:
offset = sizeof(struct int_src_override);
break;
case MADT_NMI:
offset = sizeof(struct nmi);
break;
case MADT_LAPIC_NMI:
offset = sizeof(struct lapic_nmi);
break;
case MADT_LAPIC_ADDR_OVERRIDE:
offset = sizeof(struct lapic_address_override);
break;
case MADT_IO_SAPIC:
offset = sizeof(struct io_sapic);
break;
case MADT_LOCAL_SAPIC:
offset = sizeof(struct local_sapic);
break;
case MADT_PLATFORM_INT_SRC:
offset = sizeof(struct platform_int_src);
break;
default:
offset = sizeof(struct apic_header);
break;
}

Wenn ich diesen Code mit if-else-Anweisung verwende, funktioniert alles einwandfrei.
Woran liegt das?

Hier mal der Assembler-Code:
while (i < madt->header.length) {
  100016: e9 c5 00 00 00        jmp    1000e0 <acpi_count_cpus+0xe0>
apic = (struct apic_header*)addr;
  10001b: 8b 44 24 1c          mov    0x1c(%esp),%eax
  10001f: 89 44 24 0c          mov    %eax,0xc(%esp)

switch (apic->type) {
  100023: 8b 44 24 0c          mov    0xc(%esp),%eax
  100027: 0f b6 00              movzbl (%eax),%eax
  10002a: 0f be c0              movsbl %al,%eax
  10002d: 83 f8 08              cmp    $0x8,%eax
  100030: 0f 87 8b 00 00 00    ja     1000c1 <acpi_count_cpus+0xc1>
  100036: 8b 04 85 00 10 00 c0 mov    -0x3ffff000(,%eax,4),%eax
  10003d: ff e0                jmp    *%eax
case MADT_LAPIC:
lapic = (struct lapic*)apic;
  10003f: 8b 44 24 0c          mov    0xc(%esp),%eax
  100043: 89 44 24 10          mov    %eax,0x10(%esp)
offset = sizeof(struct lapic);
  100047: c7 44 24 14 08 00 00 movl   $0x8,0x14(%esp)
  10004e: 00

if(hit_if(!lapic->flags))
  10004f: 8b 44 24 10          mov    0x10(%esp),%eax
  100053: 8b 40 04              mov    0x4(%eax),%eax
  100056: 85 c0                test   %eax,%eax
  100058: 0f 94 c0              sete   %al
  10005b: 0f b6 c0              movzbl %al,%eax
  10005e: 85 c0                test   %eax,%eax
  100060: 74 69                je     1000cb <acpi_count_cpus+0xcb>
cpu_count++;
  100062: a1 f0 05 10 00        mov    0x1005f0,%eax
  100067: 83 c0 01              add    $0x1,%eax
  10006a: a3 f0 05 10 00        mov    %eax,0x1005f0
break;
  10006f: eb 5b                jmp    1000cc <acpi_count_cpus+0xcc>

Kann mir nur vorstellen, dass jmp *%eax den Fehler verursacht.

Gruss,
rizor
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 27. September 2011, 23:14 »
Sehe ich auch so. Der Wert für eax kommt ja aus dieser Anweisung:
  100036: 8b 04 85 00 10 00 c0 mov    -0x3ffff000(,%eax,4),%eax
Kann es sein, dass du irgendwelche verrückten Dinge in deinem Linkerskript machst? Zum Beispiel Teile des Kernels nach 3 GB linken?
« Letzte Änderung: 27. September 2011, 23:16 von PorkChicken »
Dieser Text wird unter jedem Beitrag angezeigt.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 27. September 2011, 23:29 »
Ja, der Kernel wird gegen 3GB gelinkt, allerdings nicht dieser Code.
Der wird weiterhin gegen die 1MB-Grenze gelinkt.
Innerhalb dieser Funktion wird ja keine andere Funktion aufgerufen. Also duerfte das ja keine Probleme machen, oder?
Kann es sein, dass der Compiler irgendwie was falsch interpretiert und somit der Meinung ist, dass die Werte bei 3GB liegen?
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 28. September 2011, 01:13 »
Kann es sein, dass der Compiler irgendwie was falsch interpretiert und somit der Meinung ist, dass die Werte bei 3GB liegen?

Ja, ich denke, dass das der Fall ist. Er weiß ja nicht, dass du den Code verteilst. Die Sprungtabelle, die vom switch-Statement verwendet wird, könnte im 3 GB-Bereich landen, obwohl sie eigentlich bei 1 MB landen müsste. Ich vermute, dass du das dem Linker nicht korrekt gesagt hast. Wenn ich raten soll, musst du nach einem Fehler suchen, der ungefähr so aussieht: Der Compiler hat die Sprungtabelle in die .rodata-Sektion (ggf. anderer Sektionsname) gesteckt, und du hast diese nicht im Linkerskript für den 1 MB-Teil platziert.

Ich weiß nicht genau wie dein Linkerskript aussieht, deswegen kann ich dir da nur soweit helfen: Vielleicht solltest du rausfinden, in welcher Sektion die Sprungtabelle tatsächlich liegt. Um das rauszukriegen wäre mein Vorschlag, dass du die .c-Datei einmal assemblierst (mit gcc -S) oder objdump -d auf die Objekt-Datei anwendest. Dann solltest du schauen, wie du den Linker dazu bringst, diese Sektion ebenfalls nach 1 MB zu linken. Dabei kommt es darauf an, wie genau dein Linkerskript funktioniert. Es könnte reichen anstatt der .text-Sektion alle Sektionen in den 1 MB-Teil zu schieben, indem du apic.o(*) statt apic.o(.text) verwendest, falls du das so schreibst.
« Letzte Änderung: 28. September 2011, 01:16 von PorkChicken »
Dieser Text wird unter jedem Beitrag angezeigt.

 

Einloggen