| Autor |
Nachricht |
Dennis G.
Mitglied
Benutzerprofil
Anmeldungsdatum: 10.08.2012
Beiträge: 4
|
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:
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
|
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
|
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
|
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
|
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
|
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
|
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.
| 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. |
|
|
|
 |
|
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.
|
|
|
|
|