2013-08-11 10 views
6

Próbuję wydrukować coś na ekranie za pomocą funkcji drukowania.Przekazywanie tablicy znaków jako parametru (kod jądra C)

ja natknęliśmy się na mały problem - kiedy mijam tablicę znaków takiego:

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

to działa dobrze, ale gdy zgłoszę to tak nie ma efektu.

print("abc"); 

Oto moja deklaracja funkcji

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

Am I czegoś brakuje? printf działa w ten sam sposób i możesz przekazać ciąg znaków w drugą stronę.

Edycja:

definicje

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 z kernel.o

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

demontaż sekcji .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:

Ponieważ to może być coś z okazji jestem initilising rodowiska, tutaj są 2 pliki odpowiedzialna:

pmode.asm -initializes segmenty i przeskakuje do początku jądra

[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 

tutaj jak mogę zbudować 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

Jaka jest twoja funkcja ** zdefiniowana ** (tzn. Zaimplementowana)? –

+0

@ H2CO3 dodane definicje –

+0

powinieneś używać 'const char *', ale to prawdopodobnie nie ma związku. – Dave

Odpowiedz

1

Znalazłem odpowiedź, patrząc na demontaż z dużo większym ciągiem.

Powodem był sposób, w jaki połączyłem jądro. Były to polecenia byłem zaleca się stosowanie:

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

ale ponieważ miałem gcc Windows, a moja ASM i pliki C były w formacie elf, musiałem skorzystać z tej sztuczki:

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

To skopiowało tylko tekstową część obiektu, więc zostałem z wersją binarną. Ponieważ skopiowałem tylko część obiektu obiektu .text, moje ciągi, które były przechowywane w sekcjach .rdata, zostały utracone.Tak więc była to po prostu kwestia dodania tego do objcopy:

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

Kiedy powiesz "print", przekazujesz go jako tablicę znaków, ponieważ zadeklarowałeś "s". Ale kiedy przejdziesz jako print ("abc"). Jaki jest typ "abc". To nie jest zdefiniowane. Chyba to twój problem. Chciałbym również polecić zmianę char [] na char * s. Mam nadzieję że to pomoże.

+0

Typ danych "abc" (łańcuch literowy) jest wyraźnie zdefiniowany jako wskaźnik znaku. Nie ma w tym nic nieokreślonego. I nie ma ŻADNEJ różnicy między char s [] i char * s; – amrith

+0

@amrith: char s [] i char * nie są w rzeczywistości takie same. Proszę przejść przez kilka odniesień. Oto przykład. Spójrz. Pozdrawiam! Char * s = "hello", tutaj można wskazać każdy inny ciąg w czasie wykonywania, co oznacza, że ​​nie jest stałym wskaźnikiem, można przypisać inną wartość w czasie wykonywania p = "Nishant", podczas gdy s [] tutaj jest stała wskaźnik .... nie można go ponownie przypisać do innego ciągu, ale możemy przypisać inną wartość znaku w s [indeks]. – Sunny

+0

Różnica polega na tym, że char * s = "Witaj świecie"; umieszcza Hello world w częściach pamięci przeznaczonych tylko do odczytu i czyni z tego wskaźnik, co powoduje, że operacja zapisu w tej pamięci jest nielegalna. Robiąc: char s [] = "Witaj świecie"; umieszcza literalny ciąg w pamięci tylko do odczytu i kopiuje ciąg do nowo przydzielonej pamięci na stosie. Wykonywanie s [0] = "J"; legalne. – Sunny

Powiązane problemy