2013-08-11 6 views
6

Sto tentando di stampare qualcosa sullo schermo utilizzando la funzione di stampa.Passaggio di array di caratteri come parametro (codice del kernel C)

ho inciampato su un piccolo problema - quando passo l'array di caratteri in questo modo:

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

Funziona bene, ma quando lo chiamo in questo modo non v'è alcun effetto.

print("abc"); 

Qui è la mia dichiarazione di funzione

//print function 
void print(char* message); 

mi sto perdendo qualcosa? printf funziona allo stesso modo e puoi passare la stringa dal secondo modo.

EDIT:

definizioni

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); 
} 

EDIT2: objdump di kernel.o

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

smontaggio della sezione .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 

Edit3:

Dal momento che questo potrebbe essere qualcosa con il modo in cui sto initilising l'ambiente, ecco i file di 2 responsabili:

pmode.asm -initializes segmenti, e salta per iniziare di kernel

[bits 16] 
switch_to_pm: 

    cli  ; switch interuppts off 
    lgdt [gdt_descriptor] ; load global descriptor table 

    mov eax, cr0 ; set control registers first bit to protected mode 
    or eax, 0x1 
    mov cr0, eax 

    jmp CODE_SEG:init_pm ;flush cache by far jump 

[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 

qui è come ho costruito il gdt:

; GDT

gdt_start: 

gdt_null: ; the mandatory null descriptor 
    dd 0x0  ; ' dd ' means define double word (i.e. 4 bytes) 
    dd 0x0 

gdt_code: ; the code segment descriptor 
    ; base =0 x0 , limit =0 xfffff , 
    ; 1 st flags : (present)1 (privilege)00 (descriptor type)1 -> 1001 b 
    ; type flags : (code)1 (conforming)0 (readable)1 (accessed)0 -> 1010 b 
    ; 2 nd flags : (granularity)1 (32- bit default)1 (64- bit seg)0 (AVL)0 -> 1100 b 
    dw 0xffff  ; Limit (bits 0-15) 
    dw 0x0   ; Base (bits 0-15) 
    db 0x0   ; Base (bits 16-23) 
    db 10011010b ; 1 st flags , type flags 
    db 11001111b ; 2 nd flags , Limit (bits 16-19) 
    db 0x0   ; Base (bits 24-31) 
gdt_data: ; the data segment descriptor 
    ; Same as code segment except for the type flags : 
    ; type flags : (code)0 (expand down)0 (writable)1 (accessed)0 -> 0010 b 
    dw 0xffff  ; Limit (bits 0-15) 
    dw 0x0   ; Base (bits 0-15) 
    db 0x0   ; Base (bits 16-23) 
    db 10010010b ; 1 st flags , type flags 
    db 11001111b ; 2 nd flags , Limit (bits 16-19) 
    db 0x0   ; Base (bits 24-31) 

gdt_end: ; The reason for putting a label at the end of the 
      ; GDT is so we can have the assembler calculate 
      ; the size of the GDT for the GDT decriptor (below) 
      ; GDT descriptior 
gdt_descriptor: 
    dw gdt_end - gdt_start - 1 ; Size of our GDT , always less one 
           ; of the true size 
    dd gdt_start    ; Start address of our GDT 

    ; Define some handy constants for the GDT segment descriptor offsets , which 
    ; are what segment registers must contain when in protected mode. For example , 
    ; when we set DS = 0 x10 in PM , the CPU knows that we mean it to use the ; segment described at offset 0 x10 (i.e. 16 bytes) in our GDT , which in our 
    ; case is the DATA segment (0 x0 -> NULL ; 0 x08 -> CODE ; 0 x10 -> DATA) 
    CODE_SEG equ gdt_code - gdt_start 
    DATA_SEG equ gdt_data - gdt_start 
+0

E come è definita la ** funzione ** (cioè implementata)? –

+0

@ H2CO3 ha aggiunto le definizioni –

+0

dovresti usare 'const char *', ma probabilmente non è correlato. – Dave

risposta

1

Ho trovato la risposta, dopo aver osservato uno smontaggio con una stringa molto più grande.

Il motivo era il modo in cui collegavo il kernel. Questi erano i comandi mi hanno consigliato di usare:

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

ma perché avevo un gcc finestre, e il mio file C ASM ed erano in formato ELF, ho dovuto usare questo trucco:

ld -o kernel.out -Ttext 0x1000 $^ 
objcopy -O binary -j .text kernel.out [email protected] 

Questo copiò solo la parte di testo dell'oggetto, quindi rimasi con la versione binaria. Poiché ho copiato solo la parte dell'oggetto .text, le mie stringhe che sono state mantenute nelle sezioni .rdata sono state perse.Quindi si trattava semplicemente di aggiungere questo a objcopy:

objcopy -O binary -j .text -j .rdata kernel.out [email protected] 
-1

Quando si dice print (s), lo si passa come array di caratteri in quanto dichiarato "s". Ma quando passi come stampa ("abc"). Qual è il tipo di "abc". Non è definito. Immagino che questo sia il tuo problema. Ti raccomanderei anche di cambiare i tuoi caratteri [] in caratteri *. Spero che questo ti aiuti.

+0

Il tipo di dati di "abc" (una stringa letterale) è chiaramente definito come puntatore di un carattere. Non c'è nulla di indefinito a riguardo. E NON c'è differenza tra char s [] e char * s; – amrith

+0

@amrith: char s [] e char * non sono realmente uguali. Si prega di passare attraverso alcuni riferimenti. Ecco un esempio. Guarda. Saluti !! char * s = "ciao", qui puoi puntare qualsiasi altra stringa in fase di esecuzione intendo che non è un puntatore costante puoi assegnare un altro valore in fase di esecuzione p = "Nishant", mentre s [] qui s è costante pointer .... non può essere reasign un'altra stringa, ma possiamo assegnare un altro valore di carattere a s [index]. – Sunny

+0

La differenza è che char * s = "Hello world"; posizionerà Hello world nelle parti di sola lettura della memoria e farà un puntatore a tale operazione, rendendo illegale qualsiasi operazione di scrittura su questa memoria. Durante l'esecuzione: char s [] = "Hello world"; inserisce la stringa letterale nella memoria di sola lettura e copia la stringa nella memoria appena allocata nello stack. Making s [0] = 'J'; legale. – Sunny

Problemi correlati