Autor Thema: VM86 Will nicht wie ich es will  (Gelesen 14266 mal)

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #20 am: 16. September 2010, 16:09 »
Hallo,


Ich glaube, so langsam sollte ich mich doch von meiner Aussage distanzieren und sie klar und deutlich als Ironie kennzeichnen… :-D
Bevor noch irgendwelche Leute Dinge wie "ich programmiere gerade ein kleines OS, wer möchte mir dabei helfen DOOM4 [oder irgendein anderes tolles 3D-Spiel] zu portieren?" äußern wäre dieser Schritt sicher ratsam.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

Programm Noob

  • Gast
Gespeichert
« Antwort #21 am: 16. September 2010, 23:28 »
Also VM86 fasse ich so schell nicht mehr an. Ich hab meinen Kernel noch immer nicht zum laufen bekommen. Ich überlege sogar gerade, ob ich nicht nochmal alles in die Tonne trete und neu anfange. In Assembler. Das eizigste, wo ich mit Assembler probleme habe, ist if else, da weiß ich nicht wie das in Assembler geht, wenn mir das vieleicht mal einer erklären könnte, wäre das Super.
Der gedanke an Assembler kam, als ixh gesehen habe, was GCC mir beim PIC initialisieren für Code produziert hat. Der übersetze C Code, als binary 315 Bytes und mein in NASM geschriebenes stück um den PIC zu initialisieren war 48 Bytes groß.
Ich habe gesehen, das gcc bei outb immer ein nop dahintergesetzt hat, sollte man das machen? Wenn ja, wie sieht das bei solchen sachen, wie pic aus, sollte dort auch lieber ein nop hin oder nicht, weil man dort doch nicht auf ältere hardware warten muss. Oder?

Programm Noob(PNoob)

DerHartmut

  • Beiträge: 236
    • Profil anzeigen
    • Mein Blog
Gespeichert
« Antwort #22 am: 17. September 2010, 00:05 »
Ok, du kommst nicht mit VM86 klar, weil du es nicht verstehst, du schreibst deinen Kernel nun zum dritten Mal neu, weil du nicht verstehst, was du da zusammenschreibst/kopierst, du schreibst den jetzt in Assembler, weil du C nicht verstehst, und du meidest if/else-Konstrukte, weil du das Grundkonzept der Programmierung scheinbar nicht verstehst.

Sorry, aber so bringst dir doch auch nichts. Lern noch ein wenig C, schraub' ein bisschen am Linux-Kernel herum und dann fang' mit deinem neuen Kernel an. Nun liest du aber alle Tutorials und Artikel gründlich und denkst nicht mal annähernd daran, STRG+C und STRG+V zu machen.

Nur so als Tipp von mir.
$_="krJhruaesrltre c a cnp,ohet";$_.=$1,print$2while s/(..)(.)//;
Nutze die Macht, nutze Perl ;-)

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #23 am: 17. September 2010, 02:44 »
Der gedanke an Assembler kam, als ixh gesehen habe, was GCC mir beim PIC initialisieren für Code produziert hat. Der übersetze C Code, als binary 315 Bytes und mein in NASM geschriebenes stück um den PIC zu initialisieren war 48 Bytes groß.
Das liegt daran das nicht beide das selbe tun. Dein C-Code ruft (per Call) outb Funktionen auf und pushed 3 Parameter auf den Stack von denen einer völlig nutzlos ist. Das macht dein handgeschriebener ASM code mit Sicherheit nicht. Aber das würde mein C Code auch nicht machen  :-D. in/outb sind Mini-Funktionen die sich auf einen ASM-Befehl (+Parameter übergabe) beschränken und sollten auf jeden Fall ge-inlined werden(Stichwort: static inline). Bei jedem Port-Zugriff manuell auf Berechtigung zu prüfen ist Performance mäßig ein Betonklotz am Bein. Das hatten wir glaub ich schon mal in einem anderen Thread, aber trotzdem noch mal: Deinem Kernel solltest du trauen können, das würdest du in deinem Assembler Code auch tun, oder? -- Und schon macht gcc -O2/-O3 Assembler Code den du quasi nicht mehr schlagen kannst.(Wenn es dir um die Größe der binary geht musst du mit -Os compilieren)

Zitat
Ich habe gesehen, das gcc bei outb immer ein nop dahintergesetzt hat, sollte man das machen?
gcc weiß nicht was du  asm("hier stehen hast"); von daher hat das nop nichts mit dem outb zu tun, sondern ist eine Optimierung die gcc macht um Sprungadressen auszurichten.

Zitat
wo ich mit Assembler probleme habe, ist if else, da weiß ich nicht wie das in Assembler geht
Wie du sicher schon öfter hier gelesen hast. Besseren Code als gcc zu schreiben setzt schon voraus das man sich mit der Assembler und der Architektur sehr gut auskennt. Jcc, SETcc, cmp, add, and, xor... um nur einige der x86 Befehle zu nennen mit denen man if/else realisiert.
Es schadet zwar nicht, wenn du dich diesbezüglich weiter bildest, aber ich rate dir wirklich ab deinen Kernel in Assembler zu schreiben bzw. es zu versuchen. Es lohnt sich weit mehr wenn du dich mit einer Hochsprache(C) beschäftigst und beim Programmieren über Performance Gedanken machst: Ist der Algorithmus die richtige Wahl? Kann der Compiler die Funktion falls nötig Inlinen? Könnte etwas den Compiler daran hindern etwas weg zu optimieren? Weiß der Compiler das die Funktion bei gleichen Parametern immer das selbe Ergebnis liefert(z.B. sqrt)? …
Dann hast du gute Performance und flexiblen Code, und hast keine Probleme wenn du merkst dass es vielleicht besser wäre die String-länge als zusätzlichen Parameter zu übergeben, weil du sie sowieso beim Aufruf immer schon weißt und sie in der Funktion so nicht immer wieder neu berechnen musst. In Assembler bist du da mit Sicherheit eine weile beschäftigt bis du das umgebogen hast, in C fixt du schnell mal den Header, und lässt gcc die stellen finden wo du schnell mal triviale Änderungen vornehmen musst.
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

Programm Noob

  • Gast
Gespeichert
« Antwort #24 am: 17. September 2010, 04:59 »
DerHartmut If else versteh ich in C, nur in Assembler habe ich damit Probleme. Ich habe diesesmal auch nicht kopiert. Ich hab nur wegen VM86 über ein wenig was geändert und das ergebnis ist ein Kernel mit Wirtschaftlichem Totalaschaden.

MNemo: Irgendwie hast du ja recht, Ich kann ja Assembler und C mischen.

Bezüglich des PIC Codes, ich habe testweise die Funktion auf ein minimum reduziert, also sämtliche bitmap geschichten auskommentiert und die funktion auch mal inlinen lassen. Was ich in Assembler Geschrieben habe, ist mit Sicherheit schneller und kleiner.

Programm Noob

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #25 am: 17. September 2010, 08:12 »
Hallo,


Das eizigste, wo ich mit Assembler probleme habe, ist if else, da weiß ich nicht wie das in Assembler geht, wenn mir das vieleicht mal einer erklären könnte, wäre das Super.
Wenn Dir das jetzt jemand erklären würde würde Dich das am Ende nur dazu verleiten Deinen Kernel tatsächlich in Assembler zu programmieren und dann würdest Du bloß noch härter auf der Nase landen, befolge lieber die Ratschläge der anderen und lerne richtiges C.

Der übersetze C Code, als binary 315 Bytes und mein in NASM geschriebenes stück um den PIC zu initialisieren war 48 Bytes groß.
Dann hast Du eindeutig schlechten C-Code geschrieben.

wie pic aus, [....], weil man dort doch nicht auf ältere hardware warten muss.
Der PIC ist die "ältere Hardware" (der ist doppelt so alt wie Du)! Aber NOPs musst Du da nicht hinter tun, bei IO-Befehlen serialisiert die CPU von ganz alleine und wartet auch immer bis der IO-Befehl komplett fertig ist. Wenn Du die IO-Befehle in gcc-Inline-Assembler packst dann darf man das memory, bei den geänderten Dingen, nicht vergessen damit dieser Inline-Assembler-Block zu einer Barriere wird über die der gcc nicht hinweg optimiert.


Was ich in Assembler Geschrieben habe, ist mit Sicherheit schneller und kleiner.
Das ist mit Sicherheit falsch (zumindest nicht "und" höchstens "oder") oder Du hast mit Sicherheit schlechten C-Code.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #26 am: 17. September 2010, 10:47 »
Das eizigste, wo ich mit Assembler probleme habe, ist if else, da weiß ich nicht wie das in Assembler geht, wenn mir das vieleicht mal einer erklären könnte, wäre das Super.
Da fällt mir wirklich nicht mehr viel anderes ein als verzweifelt zu lachen... Warum glaubst du, dass das Ergebnis besser werden würde, wenn du auf eine Sprache umsteigst, die du noch weniger kannst und die schon rein objektiv gesehen wesentlich fehleranfälliger ist?

Zitat
Der gedanke an Assembler kam, als ixh gesehen habe, was GCC mir beim PIC initialisieren für Code produziert hat. Der übersetze C Code, als binary 315 Bytes und mein in NASM geschriebenes stück um den PIC zu initialisieren war 48 Bytes groß.
Ich habe gesehen, das gcc bei outb immer ein nop dahintergesetzt hat, sollte man das machen? Wenn ja, wie sieht das bei solchen sachen, wie pic aus, sollte dort auch lieber ein nop hin oder nicht, weil man dort doch nicht auf ältere hardware warten muss. Oder?
Okay. Du verstehst nicht, was gcc macht, also ist es falsch? Meine Vermutung wäre, dass das zur Hälfte Optimierungen sind (z.B.. Alignment-Geschichten) und zur anderen Hälfte suboptimaler C-Code.

Bezüglich des PIC Codes, ich habe testweise die Funktion auf ein minimum reduziert, also sämtliche bitmap geschichten auskommentiert und die funktion auch mal inlinen lassen. Was ich in Assembler Geschrieben habe, ist mit Sicherheit schneller und kleiner.
Ich glaube nicht, dass du die Erfahrung hast, definitiv zu sagen, welche Variante schneller ist. Ansonsten: Gib mal Butter bei die Fische, wir wollen den C-Code und den Assemblercode sehen, und außerdem deinen gcc-Aufruf.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Programm Noob

  • Gast
Gespeichert
« Antwort #27 am: 17. September 2010, 11:04 »
Kann ich euch heute abend geben. Bin grad inner Schule und weiß nicht wie viel Zeit ich hab heute Mittag bis ich wegfahre.

Programm Noob

Programm Noob

  • Gast
Gespeichert
« Antwort #28 am: 17. September 2010, 14:51 »
Hier der Versprochene Code

pic.asm (Mein PIC ASM-Code)
init_pic:
    ; Master-PIC initialisieren
    mov dx, 0x20
mov al, 0x11
out dx, al ; Initialisierungsbefehl fuer den PIC
    mov dx, 0x21
mov al, 0x20
out dx, al ; Interruptnummer fuer IRQ 0
mov al, 0x04
out dx, al ; An IRQ 2 haengt der Slave
mov al, 0x01
out dx, al ; ICW 4

    ; Slave-PIC initialisieren
    mov dx, 0xA0
mov al, 0x11
out dx, al ; Initialisierungsbefehl fuer den PIC
mov dx, 0xA1
mov al, 0x28
out dx, al ; Interruptnummer fuer IRQ 8
mov al, 0x02
out dx, al ; An IRQ 2 haengt der Slave
mov al, 0x01
out dx, al ; ICW 4

; Alle IRQs aktivieren (demaskieren)
mov dx, 0x20
xor eax, eax
out dx, al

mov dx, 0xA0
out dx, al

ret

pic.c (Mein PIC C-Code)
#define PORT_PIC1_COMMAND       0x0020
#define PORT_PIC1_DATA          0x0021
#define PORT_PIC2_COMMAND       0x00A0
#define PORT_PIC2_DATA          0x00A1

static inline void outb(unsigned short port, unsigned char data)
{
    __asm__ volatile ("outb %0, %1" :: "a" (data), "Nd" (port));
}

void init_pic(void)
{
    // Master-PIC initialisieren
    outb(PORT_PIC1_COMMAND, 0x11); // Initialisierungsbefehl fuer den PIC
    outb(PORT_PIC1_DATA, 0x20); // Interruptnummer fuer IRQ 0
    outb(PORT_PIC1_DATA, 0x04); // An IRQ 2 haengt der Slave
    outb(PORT_PIC1_DATA, 0x01); // ICW 4

    // Slave-PIC initialisieren
    outb(PORT_PIC2_COMMAND, 0x11); // Initialisierungsbefehl fuer den PIC
    outb(PORT_PIC2_DATA, 0x28); // Interruptnummer fuer IRQ 8
    outb(PORT_PIC2_DATA, 0x02); // An IRQ 2 hängt der Slave
    outb(PORT_PIC2_DATA, 0x01); // ICW 4

    // Alle IRQs aktivieren (demaskieren)
    outb(PORT_PIC1_COMMAND, 0x0);
    outb(PORT_PIC2_COMMAND, 0x0);
}

pic.s (ausgabe von gcc)
.file "pic.c"
.stabs "C:\\Dokumente und Einstellungen\\Admin\\Desktop/",100,0,2,.Ltext0
.stabs "pic.c",100,0,2,.Ltext0
.text
.Ltext0:
.stabs "gcc2_compiled.",60,0,0,0
.stabs "int:t(0,1)=r(0,1);-2147483648;2147483647;",128,0,1,0
.stabs "char:t(0,2)=r(0,2);0;127;",128,0,1,0
.stabs "long int:t(0,3)=r(0,3);-2147483648;2147483647;",128,0,1,0
.stabs "unsigned int:t(0,4)=r(0,4);0;037777777777;",128,0,1,0
.stabs "long unsigned int:t(0,5)=r(0,5);0;037777777777;",128,0,1,0
.stabs "long long int:t(0,6)=@s64;r(0,6);01000000000000000000000;0777777777777777777777;",128,0,1,0
.stabs "long long unsigned int:t(0,7)=@s64;r(0,7);0;01777777777777777777777;",128,0,1,0
.stabs "short int:t(0,8)=@s16;r(0,8);-32768;32767;",128,0,1,0
.stabs "short unsigned int:t(0,9)=@s16;r(0,9);0;65535;",128,0,1,0
.stabs "signed char:t(0,10)=@s8;r(0,10);-128;127;",128,0,1,0
.stabs "unsigned char:t(0,11)=@s8;r(0,11);0;255;",128,0,1,0
.stabs "float:t(0,12)=r(0,1);4;0;",128,0,1,0
.stabs "double:t(0,13)=r(0,1);8;0;",128,0,1,0
.stabs "long double:t(0,14)=r(0,1);12;0;",128,0,1,0
.stabs "void:t(0,15)=(0,15)",128,0,1,0
.align 16
.stabs "init_pic:F(0,15)",36,0,11,init_pic
.globl init_pic
.type init_pic, @function
init_pic:
.stabd 46,0,0
.stabn 68,0,12,.LM0-.LFBB1
.LM0:
.LFBB1:
pushl %ebp
.LBB22:
.LBB23:
.stabn 68,0,8,.LM1-.LFBB1
.LM1:
movb $17, %al
.LBE23:
.LBE22:
.stabn 68,0,12,.LM2-.LFBB1
.LM2:
movl %esp, %ebp
.LBB25:
.LBB24:
.stabn 68,0,8,.LM3-.LFBB1
.LM3:
/APP
/ 8 "pic.c" 1
outb %al, $32
/ 0 "" 2
/NO_APP
.LBE24:
.LBE25:
.LBB26:
.LBB27:
movb $32, %al
/APP
/ 8 "pic.c" 1
outb %al, $33
/ 0 "" 2
/NO_APP
.LBE27:
.LBE26:
.LBB28:
.LBB29:
movb $4, %al
/APP
/ 8 "pic.c" 1
outb %al, $33
/ 0 "" 2
/NO_APP
.LBE29:
.LBE28:
.LBB30:
.LBB31:
movb $1, %al
/APP
/ 8 "pic.c" 1
outb %al, $33
/ 0 "" 2
/NO_APP
.LBE31:
.LBE30:
.LBB32:
.LBB33:
movb $17, %al
/APP
/ 8 "pic.c" 1
outb %al, $160
/ 0 "" 2
/NO_APP
.LBE33:
.LBE32:
.LBB34:
.LBB35:
movb $40, %al
/APP
/ 8 "pic.c" 1
outb %al, $161
/ 0 "" 2
/NO_APP
.LBE35:
.LBE34:
.LBB36:
.LBB37:
movb $2, %al
/APP
/ 8 "pic.c" 1
outb %al, $161
/ 0 "" 2
/NO_APP
.LBE37:
.LBE36:
.LBB38:
.LBB39:
movb $1, %al
/APP
/ 8 "pic.c" 1
outb %al, $161
/ 0 "" 2
/NO_APP
.LBE39:
.LBE38:
.LBB40:
.LBB41:
xorl %eax, %eax
/APP
/ 8 "pic.c" 1
outb %al, $32
/ 0 "" 2
/NO_APP
.LBE41:
.LBE40:
.LBB42:
.LBB43:
/APP
/ 8 "pic.c" 1
outb %al, $160
/ 0 "" 2
/NO_APP
.LBE43:
.LBE42:
.stabn 68,0,28,.LM4-.LFBB1
.LM4:
popl %ebp
ret
.size init_pic, .-init_pic
.Lscope1:
.stabs "",36,0,0,.Lscope1-.LFBB1
.stabd 78,0,0
.stabs "",100,0,0,.Letext0
.Letext0:
.ident "GCC: (GNU) 4.4.0"


Aufruf
nasm -fbin pic.asm -o pic
i586-elf-gcc pic.c -c -m32 -Wall -ffreestanding -fno-stack-protector -nostdinc -I include -std=c99 -Wextra -Werror -g -O3 -S
i586-elf-ld -b binary pic.o -o pic.bin -T link.ld

link.ld
ENTRY(init_pic)
SECTIONS
{
.text :
{
*(.text*)
*(.rodata*)
*(.data*)
*(.bss*)
}
}


Programm Noob

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #29 am: 17. September 2010, 15:43 »
Ich hab deine test.s mal durch den Assembler gejagt und hinterher nur die erzeugte Funktion nochmal disassembliert. Der Rest scheinen Debuginformationen und Labels zu sein. Damit kommen wir auf:

00000000 <init_pic>:
   0:   55                      push   %ebp
   1:   b0 11                   mov    $0x11,%al
   3:   89 e5                   mov    %esp,%ebp
   5:   e6 20                   out    %al,$0x20
   7:   b0 20                   mov    $0x20,%al
   9:   e6 21                   out    %al,$0x21
   b:   b0 04                   mov    $0x4,%al
   d:   e6 21                   out    %al,$0x21
   f:   b0 01                   mov    $0x1,%al
  11:   e6 21                   out    %al,$0x21
  13:   b0 11                   mov    $0x11,%al
  15:   e6 a0                   out    %al,$0xa0
  17:   b0 28                   mov    $0x28,%al
  19:   e6 a1                   out    %al,$0xa1
  1b:   b0 02                   mov    $0x2,%al
  1d:   e6 a1                   out    %al,$0xa1
  1f:   b0 01                   mov    $0x1,%al
  21:   e6 a1                   out    %al,$0xa1
  23:   31 c0                   xor    %eax,%eax
  25:   e6 20                   out    %al,$0x20
  27:   e6 a0                   out    %al,$0xa0
  29:   5d                      pop    %ebp
  2a:   c3                      ret

Der einzige Unterschied zu deinem Code ist, dass du noch mit einem zusätzlichen Register herumhantierst statt out einen Immediate-Operanden zu geben. Was genau ist an diesem Code jetzt schlechter?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

 

Einloggen