Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: rizor 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
-
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?
-
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?
-
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.