Autor Thema: GCC veraendert den Stack nicht  (Gelesen 3907 mal)

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« am: 27. December 2011, 19:45 »
Hallo zusammen,

ich stosse momentan auf ein komisches Problem.
Bei Aufrufen von Funktionen veraendert der Kernel den Stack nicht.
Also mal ein wenig genauer:

Eine meiner Funktionen ruft eine andere auf und setzt den Stack richtig (Parameteruebergabe korrekt).
Nachdem die Funktion durchgelaufen ist, kehrt der Code zurueck und zeigt mir im GDB die Parameter der aufrufenden Funktion an.
Dabei faellt mir auf, dass der erste Parameter (der oberste auf dem Stack) der Ruecksprungadresse der aufgerufenen Funktion entspricht.
Woran liegt das?

Ich habe keine plausible Erklaerung dafuer, da der Code auch im Assembler nicht schlecht aussieht (call, ret).
Kann es sein, dass da QEmu was falsch macht und vergisst das Register zu veraendern?
Das kann ich aber fast nicht glauben, da ich auch schon ein Linux in QEmu gestartet habe und das funktioniert.


Gruss,
rizor

Edit:
Der erste Aufruf der Funktion geht aber gut und der Code laeuft ordentlich durch.

Hier mal der betroffene C-Code:
/*
 * this function sets the flags of one entry correctly
 */
static inline void __boot mmu_set_flags(vmm_space_p entry, char rw, char big) {
        entry->present = 0x1;
        entry->no_tlb_flush = 0x1;

        if (rw)
                entry->writable = 0x1;
        if (big)
                entry->big_page = 0x1;
}


/*
 * this function maps physical memory, while paging is inactive
 */
void __boot mmu_map_offline(vmm_space_p space, void* vmem,
                            void* pmem, size_t size, char rw) {
        vmm_space_p l1_tbl;
        uint32_t mapped;
        size_t alloc;
        void* frame;
        int l2, l1;

        while (size) {
                l2 = MMU_L2_INDEX(vmem);

                if (!space[l2].present &&
                    size >= MMU_PAGE_SIZE_BIG && pse_feature) {
                        space[l2].frame = (uint32_t)pmem;
                        mmu_set_flags(&space[l2], rw, 1);
                        mapped = MMU_PAGE_SIZE_BIG;
                }
                else {
                        l1 = MMU_L1_INDEX(vmem);

                        //generate a l1 table
                        if (!space[l2].present) {
                                alloc = 0x1000;
                                frame = boot_malloc(&alloc);
                                if (!alloc) {
                                        //TODO call panic
                                        while (1);
                                }
                                boot_memset(frame, 0x0, 0x1000);

                                space[l2].frame = (uint32_t)frame;
                                mmu_set_flags(&space[l2], 1, 0);
                        }
                        l1_tbl = (vmm_space_p)((uint32_t)space[l2].frame);

                        l1_tbl[l1].frame = (uint32_t)pmem;
                        mmu_set_flags(&l1_tbl[l1], rw, 0);

                        mapped = MMU_PAGE_SIZE_NORM;
                }

                vmem += mapped;
                pmem += mapped;
                size -= mapped;
        }
}

Die bearbeiteten Strukturen wurden wie folgt definiert:
struct l2_entry {
        uint32_t present : 1;
        uint32_t writable : 1;
        uint32_t userspace : 1;
        uint32_t write_through : 1;
        uint32_t no_cache : 1;
        uint32_t dirty : 1;
        uint32_t dirty_page : 1;
        uint32_t big_page : 1;
        uint32_t no_tlb_flush : 1;
        uint32_t free : 3;
        uint32_t frame: 20;
} packed;

struct l1_entry {
        uint32_t present : 1;
        uint32_t writable : 1;
        uint32_t userspace : 1;
        uint32_t write_through : 1;
        uint32_t no_cache : 1;
        uint32_t dirty : 1;
        uint32_t dirty_page : 1;
        uint32_t zero : 1;
        uint32_t no_tlb_flush : 1;
        uint32_t free : 3;
        uint32_t frame: 20;
} packed;
« Letzte Änderung: 27. December 2011, 20:05 von rizor »
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 28. December 2011, 02:50 »
Ich bezweifle, dass das Problem bei qemu liegt, auch wenn das nicht unmöglich wäre. Ich halte es für wahrscheinlicher, dass du den Stack überschreibst. Allerdings sehe ich auch keinen offensichtlichen Fehler.

Wie lässt du dir den Stack ausgeben? Zu welchem Zeitpunkt ganz genau? Breakpoint auf dem RET oder auf der Instruktion nach dem Call?

Was anderes, das vermutlich nichts mit dem Problem zu tun hat:
space[l2].frame = (uint32_t)pmem;Musst du da nicht pmem um 12 Bits nach rechts schieben? (Andere Zuweisungen ebenfalls betroffen.)
l1_tbl = (vmm_space_p)((uint32_t)space[l2].frame);Hier müsste dann um 12 nach links geschoben werden.

Ich glaube außerdem, dass du bei den 4 MB-Pages das Alignment nicht beachtest.

Der erste Aufruf der Funktion geht aber gut und der Code laeuft ordentlich durch.
Wenn damit mmu_map_offline gemeint ist, können die eben genannten Punkte doch das Problem sein.
« Letzte Änderung: 28. December 2011, 02:54 von Jidder »
Dieser Text wird unter jedem Beitrag angezeigt.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 28. December 2011, 07:09 »
Ich dachte auch erst, dass frame geschoben werden muss, aber beim setzen des Frames für die L1-Tabelle geht alles gut.
Da funktioniert auch das Eintragen der Flags richtig. (Frame-Adresse: 0x81000)
Habe das Problem weiter eingegrenzt.

Der Stack sieht doch gut aus, das ist ein Fehler im GDB.
Das Problem besteht darin, dass l1_tbl[l1].frame = ... nicht den Eintrag übernimmt.
Da soll ein 1MB-Frame (Adresse) eingetragen werden.
Das verstehe ich nicht, da 0x81000 ordentlich eingetragen wird.

Ich habe mir mal den ASM-Code angeschaut und was mir dabei aufgefallen ist, ist dass er die unteren 20-Bits behält und den Rest löscht (and $0xfffff, %eax).
Wieso tut der sowas?
Müsste er nicht einfach eher die unteren 12-Bit löschen und den Rest dann eintragen?

Wenn ich frame shifte, verliere ich doch Informationen, oder?
Momentan würde ich eher vermuten, dass ich Frame um 12 nach rechts shiften müsste.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

Dimension

  • Beiträge: 155
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 10. January 2012, 17:07 »
Ich bin mir nicht sicher, aber in solchen Fällen würde ich es mal in einem anderen Emulator testen (zB Bochs). Kannst du den Fehler soweit eingrenzen, dass du ihn reproduzieren kannst? Dann mach ein Testfall, gib das Ergebnis mit int21 aus und lade es in einer VM (oder auf einer Floppy  :wink:).

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 10. January 2012, 18:17 »
int 21? Der DOS-Syscall? Ich habe ja meine Zweifel, dass der in rizors (Protected-Mode-)OS funktioniert... ;)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Dimension

  • Beiträge: 155
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 10. January 2012, 20:19 »
Na, da hast du wohl recht. Ersetze int21 durch VGA.

 

Einloggen