6 Stimmen

Übergabe eines Zeichenarrays als Parameter (C-Kernelcode)

Ich versuche, etwas auf dem Bildschirm mit meiner Druckfunktion auszudrucken.

Ich bin auf ein kleines Problem gestoßen - wenn ich das Zeichenarray so übergebe:

char s[] = "abc";
print(s);

Funktioniert es gut, aber wenn ich es so aufrufe, gibt es keinen Effekt.

print("abc");

Hier ist meine Funktionsdeklaration

//Druckfunktion 
void print(char* message);

Feht mir etwas? printf funktioniert genauso, und man kann den String auf die zweite Weise übergeben.

BEARBEITEN:

Definitionen

void print_at(char* message, int col, int row){
    if(col >= 0 && row >= 0){
        set_cursor(get_screen_offset(col,row));
    }
    int i = 0;
    while(message[i] != 0){
        print_char(message[i++],-1,-1,WHITE_ON_BLACK);
    }
}
void print(char* message){
    print_at(message, -1,-1);
}

BEARBEITEN2: objdump von kernel.o

void start(){
    clear_screen();
    char s[] = "abc";
    print("abc");
    print(s);
    while(1);
}

Disassembly des Abschnitts .text:

00000000 <_start>:
   0:   55                      push   ebp
   1:   89 e5                   mov    ebp,esp
   3:   83 ec 28                sub    esp,0x28
   6:   e8 00 00 00 00          call   b <_start+0xb> //clear_screen()

   b:   c7 45 f4 61 62 63 00    mov    DWORD PTR [ebp-0xc],0x636261 //"bca"
  12:   c7 04 24 00 00 00 00    mov    DWORD PTR [esp],0x0
  19:   e8 00 00 00 00          call   1e <_start+0x1e> //print()

  1e:   8d 45 f4                lea    eax,[ebp-0xc]
  21:   89 04 24                mov    DWORD PTR [esp],eax
  24:   e8 00 00 00 00          call   29 <_start+0x29> //print()

  29:   eb fe                   jmp    29 <_start+0x29>
  2b:   90                      nop

BEARBEITEN3:

Da dies möglicherweise etwas mit der Art und Weise ist, wie ich die Umgebung initialisiere, sind hier die 2 Dateien verantwortlich:

pmode.asm -initialisiert Segmente und springt zum Start des Kernels

[bits 16]
switch_to_pm:

    cli     ; schalte die Unterbrechungen aus
    lgdt [gdt_descriptor] ; global descriptor table laden

    mov eax, cr0 ; setze die Steuerregister auf den ersten Bit im geschützten Modus
    or eax, 0x1
    mov cr0, eax 

    jmp CODE_SEG:init_pm ;leeren Cache durch einen weit entfernten Sprung

[bits 32]
init_pm:
    mov ax, DATA_SEG
    mov ds, ax
    mov ss, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov ebp, 0x90000
    mov esp, ebp

    call BEGIN_PM

so baue ich die gdt:

; GDT

gdt_start: 

gdt_null: ; der obligatorische Null-Descriptor 
    dd 0x0      ; ' dd ' bedeutet define double word ( d.h. 4 Bytes ) 
    dd 0x0 

gdt_code: ; der Code-Segment-Descriptor 
    ; Basis =0 x0 , Grenze =0 xfffff , 
    ; 1. Flags : ( vorhanden )1 ( Privileg )00 ( Deskriptortyp )1 -> 1001 b 
    ; Typen-Flags : ( Code )1 ( konform )0 ( lesbar )1 ( zugegriffen )0 -> 1010 b 
    ; 2. Flags : ( Granularität )1 ( 32- Bit-Standard )1 ( 64- Bit-Seg )0 ( AVL )0 -> 1100 b 
    dw 0xffff       ; Grenze ( Bits 0-15) 
    dw 0x0          ; Basis ( Bits 0-15) 
    db 0x0          ; Basis ( Bits 16-23) 
    db 10011010b    ; 1. Flags , Typen-Flags 
    db 11001111b    ; 2. Flags , Grenze ( Bits 16-19) 
    db 0x0          ; Basis ( Bits 24-31) 
gdt_data: ; der Datensegment-Descriptor 
    ; Wie das Code-Segment, jedoch für die Typenflaggen : 
    ; Typen-Flags : ( Code )0 ( expand down )0 ( beschreibbar )1 ( zugegriffen )0 -> 0010 b 
    dw 0xffff       ; Grenze ( Bits 0-15) 
    dw 0x0          ; Basis ( Bits 0-15) 
    db 0x0          ; Basis ( Bits 16-23) 
    db 10010010b    ; 1. Flags , Typen-Flags 
    db 11001111b    ; 2. Flags , Grenze ( Bits 16-19) 
    db 0x0          ; Basis ( Bits 24-31) 

gdt_end:    ; Der Grund, warum wir ein Label am Ende der 
            ; GDT setzen, ist, dass der Assembler dann die Größe der 
            ; GDT für den GDT-Deskriptor berechnen kann ( unten ) 
            ; GDT-Deskriptor 
gdt_descriptor:
    dw gdt_end - gdt_start - 1  ; Größe unserer GDT, immer eins weniger als die tatsächliche Größe 
    dd gdt_start                ; Startadresse unserer GDT 

    ; Definiere einige praktische Konstanten für die GDT-Segment-Deskriptor-Offsets, die 
    ; anzeigen, welche Werte die Segmentregister im geschützten Modus enthalten müssen. Zum Beispiel, 
    ; wenn wir DS = 0 x10 in PM setzen, weiß die CPU, dass wir wollen, dass sie das ; Segment an Offset 0 x10 ( d.h. 16 Bytes ) in unserer GDT verwenden soll, das in unserem 
    ; Fall das DATA-Segment ist (0 x0 -> NULL ; 0 x08 -> CODE ; 0 x10 -> DATA ) 
    CODE_SEG equ gdt_code - gdt_start 
    DATA_SEG equ gdt_data - gdt_start

1voto

Bartlomiej Lewandowski Punkte 10381

Ich habe die Antwort gefunden, nachdem ich mir eine Disassembly mit einem viel größeren String angesehen habe.

Der Grund war die Art und Weise, wie ich den Kernel verlinkt habe. Diese waren die Befehle, die mir empfohlen wurden zu verwenden:

ld -o kernel.bin -Ttext 0x1000 $^ --oformat binary

aber da ich einen Windows gcc hatte und meine Asm- und C-Dateien im elf-Format waren, musste ich diesen Trick verwenden:

ld -o kernel.out -Ttext 0x1000 $^ 
objcopy -O binary -j .text kernel.out $@

Dies kopierte nur den Textteil des Objekts, sodass ich mit der binären Version zurückblieb. Da ich nur den .text-Teil des Objekts kopiert habe, gingen meine Strings, die in den .rdata-Abschnitten aufbewahrt wurden, verloren. Also war es einfach eine Frage, dies zu objcopy hinzuzufügen:

objcopy -O binary -j .text -j .rdata kernel.out $@

-1voto

Sunny Punkte 49

Wenn Sie print(s) sagen, übergeben Sie es als char-Array, weil Sie "s" deklariert haben. Aber wenn Sie es als print("abc") übergeben. Was ist der Typ von "abc". Es ist nicht definiert. Ich vermute, das ist Ihr Problem. Ich würde Ihnen auch empfehlen, Ihr char s[] in char *s zu ändern. Hoffentlich hilft das.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X