Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.de  
   

Die mobilen Seiten von c++.de:
http://m.c-plusplus.de
Infos hier [BETA]

  
c++.de :: Projekt: OS-Development  ::  Mehrmaliges aufrufen von Funktionen verursacht Fehler     Zeige alle Beiträge auf einer Seite Auf Beitrag antworten
Autor Nachricht
Dennis G.
Mitglied

Benutzerprofil
Anmeldungsdatum: 10.08.2012
Beiträge: 4
Beitrag Dennis G. Mitglied 21:42:55 10.08.2012   Titel:   Mehrmaliges aufrufen von Funktionen verursacht Fehler            Zitieren

Grüße,
ich arbeite nun schon eine Weile an einem eigenen Kernel und bin auf einen Fehler gestoßen, dessen Ursache ich nicht finde. Sobald ich eine Funktion, z.B. zum Ausgeben eines Textes, mehrmals aufrufe, erhalte ich eine merkwürdige Ausgabe. Ich glaube besser kann ich das nicht beschreiben, deshalb lasse ich einfach Quellcode sprechen.

Ich habe das Problem auf diese Zeilen eingegrenzt:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
EXTERN void main(uint32 magic, MultibootInfo*)
{
    clearScreen();
    hideCursor();
   
    print("Hello World!\r\n");
    print("1234567890\r\n");
    print("\tUmlaute:\n");
    print("äöüÄÖÜß\r\n");
    print((int)magic);
    print("\r\n");
    printHex(magic);
 
    print("\r\n");
    print("\r\n");
    //print("\r\n");
}
 
EXTERN void clearScreen()
{
    byte* videomemory = (byte*)0xB8000;
    for(int i = 0; i < 2000; ++i)
    {
        videomemory[i*2] = ' ';
        videomemory[i*2+1] = 0x07;
    }
 
    cursorPosition = 0;
}
 
EXTERN void hideCursor()
{
    //Position ist außerhalb des Bildschirms -> Cursor versteckt
    uint16 position = 25*80;
    outb(0x3D4, 0x0F);
    outb(0x3D5, static_cast<byte>(position&0xFF));
 
    outb(0x3D4, 0x0E);
    outb(0x3D5, static_cast<byte>((position>>8)&0xFF));
}
 
void print(const char* ptr, ConsoleColor color/* = CONSOLE_COLOR_LIGHT_GREY*/)
{
    byte* videomemory = (byte*)0xB8000;
    const uint16 step = 4;
 
    for(; *ptr; ++ptr, ++cursorPosition)
    {
        if(cursorPosition > 4000)
            cursorPosition -= 4000;
       
        switch (*ptr)
        {
        default:
            videomemory[cursorPosition*2] = *ptr;
            videomemory[cursorPosition*2+1] = color;
            break;     
        case '\r':
            cursorPosition -= cursorPosition % 80 + 1;
            continue;
        case '\n':
            cursorPosition += 80 - 1;
            continue;
        case '\t':
            cursorPosition += step;
            continue;
        case 'ü':
            videomemory[cursorPosition*2] = 0x81;
            videomemory[cursorPosition*2+1] = color;
            continue;
        case 'ä':
            videomemory[cursorPosition*2] = 0x84;
            videomemory[cursorPosition*2+1] = color;
            continue;
        case 'Ä':
            videomemory[cursorPosition*2] = 0x8E;
            videomemory[cursorPosition*2+1] = color;
            continue;
        case 'ö':
            videomemory[cursorPosition*2] = 0x94;
            videomemory[cursorPosition*2+1] = color;
            continue;
        case 'Ö':
            videomemory[cursorPosition*2] = 0x99;
            videomemory[cursorPosition*2+1] = color;
            continue;
        case 'Ü':
            videomemory[cursorPosition*2] = 0x9A;
            videomemory[cursorPosition*2+1] = color;
            continue;
        case 'ß':
            videomemory[cursorPosition*2] = 0xE1;
            videomemory[cursorPosition*2+1] = color;
            continue;
        }
    }
}
 
EXTERN void printHex(uint32 value, ConsoleColor color/* = CONSOLE_COLOR_LIGHT_GREY*/)
{
    int n = value, i = 7;
    char output[] = "00000000";
    do
    {
        auto tmp = n % 16;
        output[i--] = static_cast<char>(tmp < 10 ? tmp+0x30 : tmp+0x37);
        n = n >> 4;
    } while(i >= 0);
 
    print(output, color);
}


Ausgabe (wie gewollt):
Code:
Hello World!
1234567890
    Umlaute:
            äöüÄÖÜß
38144
00009500



Wenn ich nun jedoch den Kommentar aus Zeile 16 entferne, so dass dort ein drittes mal print("\r\n") steht, dann erhalte ich die folgende Ausgabe:

Code:
4



Wodurch lässt sich das erklären? Hat es mir irgendwo zwischendrinnen den Stack zerschossen? Ist das ein Bug des Emulators QEmu?
Falls ihr mehr Infos braucht (disassembly z.B.), dann lasst es mich wissen.

Ich hoffe ihr könnt mir hier helfen!

Dennis
Mr X
Mitglied

Benutzerprofil
Anmeldungsdatum: 18.09.2007
Beiträge: 1231
Beitrag Mr X Mitglied 10:46:40 11.08.2012   Titel:              Zitieren

Schwer zu sagen, was schief läuft. Zumindest fällt mir nichts auf Anhieb ein. Der Bildschirm ist ja nach den paar Zeilen wohl kaum voll. Bemerkenswert ist insbesondere, dass \r\n ja nur den Cursor verschiebt, also garkeine Zugriffe auf den Bildspeicher passieren. Für mich sieht das so aus, als würde ein Fehler in einem anderen Teil deines Kernels (Multitasking, Paging, Heap-Verwaltung) hier einen Streich spielen. In der Anfangszeit von PrettyOS gab es öfter solche seltsamen Probleme.
Dennis G.
Mitglied

Benutzerprofil
Anmeldungsdatum: 10.08.2012
Beiträge: 4
Beitrag Dennis G. Mitglied 11:53:30 11.08.2012   Titel:              Zitieren

Ich habe den gesamten Code auf diese Zeilen reduziert, es wird nichts anderes mehr ausgeführt, abgesehen vom Sprung des Multiboot Einstiegpunktes zur Main Funktion.

Das geschieht so:

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
NAKED void __multiboot_entry__()
{
    __asm
    {
multiboot_header:
        dd(0x1BADB002)              ;magic
        dd(0x0010000)                   ;flags
        dd(-(0x1BADB002 + 0x0010000))   ;checksum
        dd(0x00101000)              ;header_addr
        dd(0x00101000)              ;load_addr
        dd(0x00102FFF)              ;load_end_addr
        dd(0x0010583A)              ;bss_end_addr
        dd(0x00101020)              ;entry_addr
        //Wird nur gebraucht wenn flags & 3
        /*
        dd(0x00000000)              ;mode_type
        dd(0x00000000)              ;width
        dd(0x00000000)              ;height
        dd(0x00000000)              ;depth
        */
kernel_entry:
        mov esp, 0x00105000
        push eax
        push ebx
        call main
stop:
        cli
        hlt
        jmp stop
    }
}


Der Stack ist einfach ein 8 kByte großes Array in der .data Section und startet bei 0x00103000.
Gero_Programmierstil_de
Mitglied

Benutzerprofil
Anmeldungsdatum: 20.08.2012
Beiträge: 34
Beitrag Gero_Programmierstil_de Mitglied 19:12:54 21.08.2012   Titel:              Zitieren

Hast den bug inzwischen genau investigiert und gefunden?

100%ig ist für mich daran noch nicht ersichtlich, was exakt schief läufft, dafür bräucht ich dissassembly+mapping. Aber irgenwie denk ich an bildschirmspeicher zerschossen.

Hier ein paar Hinweise:
Du solltest überall bedenken, dass cursorPosition deine Position am bildschirm ohne die farbe präsentiert, nicht das exakte offset (was %2 wäre)
C++:
        if(cursorPosition > 4000)
            cursorPosition -= 4000; // ->2000

Dieser check muss ausserdem auch unter das switch.

auserdem sollte das '\r', soweit ich das sehen kann, eher so lauten:
C++:
        case '\r':
            cursorPosition -= cursorPosition % (80 - 1);
            continue;


funktionirt der code auch bei print("Hello World\r\n"); also ohne ausrufezeichen? (ungerade anzahl zeichen geht rein, nur so zum test).

wenn das 3. \r\n hinzukommt, überschreitest du überschlagen 50 byte, die in print reingegangen sind.
Dennis G.
Mitglied

Benutzerprofil
Anmeldungsdatum: 10.08.2012
Beiträge: 4
Beitrag Dennis G. Mitglied 21:15:10 22.08.2012   Titel:              Zitieren

Gero_Programmierstil_de schrieb:

C++:
        if(cursorPosition > 4000)
            cursorPosition -= 4000; // ->2000

Dieser check muss ausserdem auch unter das switch.


Oh, das ist mir gar nicht aufgefallen. Aber da muss natürlich 2000 stehen.
Und warum muss das unter das switch? Wenn ich so drüber nachdenke, dann fällt mir kein Grund ein, warum das unbedingt drunter muss. Das wäre hier sogar ein Fehler, da Steuerungszeichen wie z.B. \t den Cursor verschieben und danach wird die Schleife mit einem continue fortgesetzt. Sprich, der Teil würde nach dem Switch niemals aufgerufen werden und somit würde ein String wie "\tfoo" kurz vor Ende des Puffers des Puffers überlaufen.

Gero_Programmierstil_de schrieb:

auserdem sollte das '\r', soweit ich das sehen kann, eher so lauten:
C++:
        case '\r':
            cursorPosition -= cursorPosition % (80 - 1);
            continue;


Das siehst du leider falsch.

Gero_Programmierstil_de schrieb:

funktionirt der code auch bei print("Hello World\r\n"); also ohne ausrufezeichen? (ungerade anzahl zeichen geht rein, nur so zum test).

Ja.

Gero_Programmierstil_de schrieb:

wenn das 3. \r\n hinzukommt, überschreitest du überschlagen 50 byte, die in print reingegangen sind.

Könntest du das bitte Begründen? Ich habe den Code auserhalb des Kernels getestet und nach allen Funktionsaufrufen befindet sich der Cursor dort, wo er sein sollte. Ich sehe wohl den Wald vor lauter Bäumen nicht.


Aber da es scheinbar noch immer an Informationen und definitiv an Lösungsansätze mangelt, gebe ich Euch noch den Auszug aus dem Disassembler.
http://pastebin.com/JQMumBm5

Das ist aber so viel, dass ich mich fast nicht traue, es hier zu posten, geschweige denn zu fragen, ob sich das jemand ansieht.
Gero_Programmierstil_de
Mitglied

Benutzerprofil
Anmeldungsdatum: 20.08.2012
Beiträge: 34
Beitrag Gero_Programmierstil_de Mitglied 21:59:19 22.08.2012   Titel:              Zitieren

habs im debugger ma durchgespielt inem array statt bildschirmspeicher.
sieht alles gut aus. sehr seltsam, der bug.

Dennis G. schrieb:
Und warum muss das unter das switch?

ich hab die "continue"s übersehen, dein code stimmt.
Gero_Programmierstil_de schrieb:

auserdem sollte das '\r', soweit ich das sehen kann, eher so lauten:
C++:
        case '\r':
            cursorPosition -= cursorPosition % (80 - 1);
            continue;


Das siehst du leider falsch.
[/quote]
ok, wegen dem ++cursorPosition im for() konstrukt.

aber funktioniert folgendes?
C++:
EXTERN void main(uint32 magic, MultibootInfo*)
{
    clearScreen();
    hideCursor();
    print("\r\r\r\r\r\r\r");
    print("funktioniert das?");
}


mit den 50 bytes war eher laut gedacht, weil 50*80==4000, usw...

hast mal nen bisschen rumprobiert mit anderen ähnlichen inputs?
wie is cursorPosition und magic eigentlich deklariert? wieso funktioniert eigentlich: print((int)magic);
Dennis G.
Mitglied

Benutzerprofil
Anmeldungsdatum: 10.08.2012
Beiträge: 4
Beitrag Dennis G. Mitglied 12:34:02 26.08.2012   Titel:              Zitieren

Es liegt nicht an einem bestimmten Aufruf und auch nicht daran was ich der Funktion übergebe. Es liegt daran, dass ich nur x Funktionen aufrufen kann, danach spinnt es rum.
Ich kann genauso gut folgendes machen:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    clearScreen();
    print("A");
    clearScreen();
    print("B");
    clearScreen();
    print("C");
    clearScreen();
    print("D");
    clearScreen();
    print("E");
    clearScreen();
    print("F");
    clearScreen();
    print("G");
    clearScreen();
    print("H");


Rufe ich jetzt nochmal print auf, dann bekomme ich wieder eine falsche Ausgabe.

Zitat:

hast mal nen bisschen rumprobiert mit anderen ähnlichen inputs?

Nein. Ich frage hier, weil ich noch kein bisschen rumprobiert habe und mir die Ursache des Problemes vollkommen klar ist. :rolleyes:

Zitat:

wie is cursorPosition und magic eigentlich deklariert? wieso funktioniert eigentlich: print((int)magic);


uint16 cursorPosition = 0; //global
Magic legt mir der Bootloader ins eax register, bevor er den Kernel aufruft. eax wird vorm Aufrufen der Main Funktion gepusht.
print((int)magic) funktioniert, weil es - wie bereits gesagt - nichts mit den Parametern der Funktion zu tun hat.


Ich habe noch etwas herumprobiert und das scheint mit der jump table des switches zusammenzuhängen.
Code:
1
2
3
4
5
6
7
8
möglichkeiten im switch     aufrufbare funktionen
11                          13
10                          17
 9                          17
 8                          21
 7                          25
 6                          29
 5                          33


Das ist sehr merkwürdig.


Könntet ihr euch den Assembly Code der Funktion ansehen? Ich kann da keinen Fehler ausmachen.
Assembler:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
print PROC
  var_18 = dword ptr -18h
  videomemory = dword ptr -14h
  bufferSize = word ptr -10h
  numRows = word ptr -0Ch
  numColumns = word ptr -8
  step = word ptr -4
  ptr = dword ptr  8
  color = dword ptr  0Ch
 
  push    ebp
  mov     ebp, esp
  sub     esp, 18h
  mov     [ebp+videomemory], 0B8000h
  mov     eax, 4
  mov     [ebp+step], ax
  mov     ecx, 50h
  mov     [ebp+numColumns], cx
  mov     edx, 19h
  mov     [ebp+numRows], dx
  mov     eax, 7D0h
  mov     [ebp+bufferSize], ax
  jmp     for
 
for:
  mov     eax, [ebp+ptr]
  movsx   ecx, byte ptr [eax]
  test    ecx, ecx
  jz      ende
 
  movzx   edx, cursorPosition
  cmp     edx, 2000
  jl      cursorValid
 
  movzx   eax, cursorPosition
  sub     eax, 2000
  mov     cursorPosition, ax
 
cursorValid:
  mov     ecx [ebp+ptr]
  movsx   edx, byte ptr[ecx]
  mov     [ebp+var_18], edx
  mov     eax, [ebp+var_18]
  add     eax, 3Ch
  mov     [ebp+var_18], eax
  cmp     [ebp+var_18], 50
  ja      caseDefault
 
  mov     ecx, [ebp+var_18]
  movzx   edx, ds:byte_101B18[ecx]
  jmp     ds:off_10B00[edx*4]
 
caseDefault:
  movzx   eax, cursorPosition
  mov     ecx, [ebp+videomemory]
  mov     edx, [ebp+ptr]
  mov     dl, [edx]
  mov     [ecx+eax*2], dl
  movzx   eax, cursorPosition
  mov     ecx, [ebp+videomemory]
  mov     dl, byte ptr [ebp+color]
  mov     [ecx+eax*2+1], dl
  jmp     loc_101AF2
 
;case Ä
  movzx   eax, cursorPosition
  mov     ecx, [ebp+videomemory]
  mov     byte ptr [ecx+eax*2], 8Eh
  movzx   edx, cursorPosition
  mov     eax, [ebp+videomemory]
  mov     cl, byte ptr [ebp+color]
  mov     [eax+edx*2+1], cl
  jmp     jmptblEnde
 
;case ö
  movzx   edx, cursorPosition
  mov     eax, [ebp+videomemory]
  mov     byte ptr [eax+edx*2], 94h
  movzx   ecx, cursorPosition
  mov     edx, [ebp+videomemory]
  mov     al, byte ptr [ebp+color]
  mov     [edx+ecx*2+1], al
  jmp     jmptblEnde
 
;case Ö
  movzx   ecx, cursorPosition
  mov     edx, [ebp+videomemory]
  mov     byte ptr [edx+ecx*2], 99h
  movzx   eax, cursorPosition
  mov     ecx, [ebp+videomemory]
  mov     dl, byte ptr [ebp+color]
  mov     [ecx+eax*2+1], dl
  jmp     jmptblEnde
 
;gefolgt von zwei weiteren cases, die den selben code jedoch mit anderen zeichen beinhalten (Ü und ü)
 
jmptblEnde:
  mov     ecx, [ebp+ptr]
  add     ecx, 1
  mov     [ebp+ptr], ecx
  mov     dx, cursorPosition
  add     dx, 1
  mov     cursorPosition
  jmp     for
 
ende:
  mov esp, ebp
  pop ebp
  retn 8
print ENDP



Ich hoffe jemand findet da was.
c++.de :: Projekt: OS-Development  ::  Mehrmaliges aufrufen von Funktionen verursacht Fehler   Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.de ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info und www.c-plusplus.net enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.