memset Funktion stürzt ab
-
Hi,
ich habe einen kleinen Kernel in Assembler und C geschrieben.
Jetzt bin ich gerade dabei, die IDT zu laden. Aber jedesmal wenn ich meinen kernel wie gewohnt mit qemu öffne, stürzt dieser ab. (Vorher kompilier/assemblier und linke ich ihn natürlich)Ich konnte das Problem bereits auf eine C-Funktion einschränken:
void memset (void *pDest, char cValue, unsigned int iCount) { asm ( "push %ebp;" "movl %esp, %ebp;" "push %eax;" "push %ecx;" "push %esi;" "movl 8(%ebp), %edi;" "movl 12(%ebp), %eax;" "movl 16(%ebp), %ecx;" "rep stosb;" "pop %esi;" "pop %ecx;" "pop %eax;" "movl %ebp, %esp;" "pop %ebp;" "ret ;" ); }Die C-Funktion besteht ganz aus Inline-Assembler (daher hab ich ins Assembler-Forum gepostet; ich hoffe das ist okay so...) in AT&T-Syntax, welchen ich nicht gewohnt bin
Ich muss ihn allerdings nutzen, da ich den gcc benutzte.Wenn qemu abstürzt, bekomme ich folgendes:
qemu: fatal: triple fault
EAX=00000000 EBX=0002d8e4 ECX=0000000f EDX=00000002
ESI=00054527 EDI=00301038 EBP=001fff98 ESP=001fff98
EIP=0002d89c EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300
CS =0008 00000000 ffffffff 00cf9a00
SS =0010 00000000 ffffffff 00cf9300
DS =0010 00000000 ffffffff 00cf9300
FS =0010 00000000 ffffffff 00cf9300
GS =0010 00000000 ffffffff 00cf9300
LDT=0000 00000000 0000ffff 00008000
TR =0000 00000000 0000ffff 00008000
GDT= 00101040 00000017
IDT= 00000000 000003ff
CR0=60000011 CR2=00000000 CR3=00000000 CR4=00000000
CCS=00000000 CCD=00000053 CCO=ADDB
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
AbortedWas mich ein bisschen erstaunt ist der Instruction Pointer, denn den Wert 0002d89c kann ich keiner Code-Stelle der memtest-Funktion zuordnen.
Dissamblieren mit objdump ergab folgendes:
001003d0 <memset>:
1003d0: 55 push %ebp
1003d1: 89 e5 mov %esp,%ebp
1003d3: 83 ec 04 sub $0x4,%esp
1003d6: 8b 45 0c mov 0xc(%ebp),%eax
1003d9: 88 45 fc mov %al,-0x4(%ebp)
1003dc: 55 push %ebp
1003dd: 89 e5 mov %esp,%ebp
1003df: 50 push %eax
1003e0: 51 push %ecx
1003e1: 56 push %esi
1003e2: 8b 7d 08 mov 0x8(%ebp),%edi
1003e5: 8b 45 0c mov 0xc(%ebp),%eax
1003e8: 8b 4d 10 mov 0x10(%ebp),%ecx
1003eb: f3 aa rep stos %al,%es:(%edi)
1003ed: 5e pop %esi
1003ee: 59 pop %ecx
1003ef: 58 pop %eax
1003f0: 89 ec mov %ebp,%esp
1003f2: 5d pop %ebp
1003f3: c3 ret
1003f4: c9 leave
1003f5: c3 retWisst ihr was ich da falsch mache?
Danke im Voraus
-
boom schrieb:
Wisst ihr was ich da falsch mache?
du hast dich nicht genug im umgang mit dem gcc inline assembler beschäftigt

wozu den ganzen funktionsrahmen in assembler, wenn gcc das sowieso schon übernimmt, in dem du alles in eine funktion packst. also den ganzen stackkram rausnehmen. ein 'ret' hat da auch nichts zu suchen. copy&paste ist bei inline assembler nicht
hier mal ein beispiel wie eine swab funktion mit inline assembly aussehen kann, weil ichs gerade zur hand habe:void swab32(void* val) { asm ("mov %0, %%rsi\n" "mov %0, %%rdi\n" "lodsl\n" "bswap %%eax\n" "stosl\n" : // no output variable :"r"(val) :"%eax","%rsi","%rdi" ); }ganz wichtig ist auch am schluss die 'clobber list'. les' dich da mal ein

-
Okay, danke für den Tipp

Ich hab jetzt
void memset (void *pDest, char cValue, unsigned int iCount) { asm ( "movl %0, %%edi;" "movl %1, %%eax;" "movl %2, %%ecx;" "rep stosb;" : : "r" (pDest), "r" (cValue & 0xFFFFFFFF), "r" (iCount) : "%edi", "%eax", "%ecx"); }und das scheint zu funktionieren.
-
na also, geht doch

wobei ich das:
cValue & 0xFFFFFFFFnicht nachvollziehen kann

-
das habe ich dazugefügt, da es ohne das "& 0xFFFFFFFF" nicht geht.
Ich glaube das liegt daran, dass ich ja in das eax-Register schreibe, und da passen ja 4 Byte rein. Deshalb versuche ich mit dem "& 0xFFFFFFFF" den char länger zu machen, damit er da rein passt.
-
dann gebe doch die richtige breite beim kopieren an, entweder explizit durch movb, oder implizit dur das kopieren nach al. hier ist beides:
void memset (void *pDest, char cValue, unsigned int iCount) { asm ( "movl %0, %%edi;" "movb %1, %%al;" "movl %2, %%ecx;" "rep stosb;" : : "r" (pDest), "r" (cValue), "r" (iCount) : "%edi", "%eax", "%ecx"); }
-
gcc-inline-Assemblercode, der mit mov beginnt oder aufhört, dürfte immer suboptimal sein - damit machte man ja den größten Vorteil dieser Methode zunichte.
void memset (void *pDest, char cValue, unsigned int iCount) { asm ( "\trep stosb\n" : : "D" (pDest), "a" (cValue), "c" (iCount)); }
-
hier stand müll *schäm*
-
sothis_ schrieb:
ich kann keinen unterschied erkennen

Ich auch nicht. Ist ja auch nicht der Code, der zum inline-Assembler gehört.
-
camper schrieb:
sothis_ schrieb:
ich kann keinen unterschied erkennen

Ich auch nicht. Ist ja auch nicht der Code, der zum inline-Assembler gehört.
ich habe noch nicht genug kaffee im blut
