2013-08-11 25 views
6

Tôi đang cố gắng in một cái gì đó trên màn hình bằng chức năng in của mình.Truyền mảng ký tự làm tham số (mã hạt nhân C)

tôi đã vấp vào một vấn đề nhỏ - khi tôi vượt qua các mảng nhân vật như thế này:

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

Nó hoạt động tốt, nhưng khi tôi gọi nó là như thế này không có hiệu lực.

print("abc"); 

Đây là khai báo hàm của tôi

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

Am tôi thiếu cái gì? printf hoạt động theo cùng một cách, và bạn có thể truyền chuỗi theo cách thứ hai.

EDIT:

định nghĩa

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 của kernel.o

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

Tháo lắp phần .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:

Vì đây có thể là một cái gì đó với cách tôi initilising các môi trường, đây là 2 file đáp trả:

pmode.asm -initializes phân đoạn, và nhảy để bắt đầu của 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 

đây là cách tôi tạo 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

Và chức năng của bạn ** được xác định ** (i. E. Implement)? –

+0

@ H2CO3 đã thêm định nghĩa –

+0

bạn nên sử dụng 'const char *', nhưng điều đó có lẽ không liên quan. – Dave

Trả lời

1

Tôi đã tìm thấy câu trả lời, sau khi xem xét việc tháo gỡ bằng một chuỗi lớn hơn nhiều.

Lý do là cách tôi liên kết hạt nhân. Đây là những lệnh tôi được khuyên là nên sử dụng:

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

nhưng kể từ khi tôi đã có một cửa sổ gcc, và asm của tôi và các tập tin C là ở định dạng elf, tôi đã phải sử dụng thủ thuật này:

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

Điều này chỉ sao chép phần văn bản của đối tượng, vì vậy tôi đã được trái với phiên bản nhị phân. Vì tôi chỉ sao chép phần .text của đối tượng, các chuỗi của tôi được giữ trong các phần .rdata bị mất.Vì vậy, nó chỉ đơn giản là một vấn đề của việc thêm này để objcopy:

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

Khi bạn nói (các) bản in, bạn chuyển nó thành mảng char beacuse bạn đã khai báo "s". Nhưng khi bạn vượt qua như in ("abc"). Loại "abc" là gì. Nó không được xác định. Tôi đoán đây là vấn đề của bạn. Tôi cũng khuyên bạn nên đổi char s [] thành char * s. Hi vọng điêu nay co ich.

+0

Kiểu dữ liệu của "abc" (một chuỗi chữ) được định nghĩa rõ ràng là một con trỏ ký tự. Không có gì không xác định về nó. Và không có sự khác biệt giữa char s [], và char * s; – amrith

+0

@amrith: char s [] và char * không thực sự giống nhau. Xin vui lòng đi qua một số tài liệu tham khảo. Đây là một ví dụ. Hãy xem. Char * s = "hello", ở đây s có thể trỏ bất kỳ chuỗi nào khác vào thời gian chạy, nghĩa là nó không phải là con trỏ hằng, bạn có thể gán một giá trị khác tại thời gian chạy p = "Nishant", trong khi s [] ở đây s là hằng số con trỏ .... nó không thể được reasign chuỗi khác nhưng chúng tôi có thể gán một giá trị ký tự khác tại s [index]. – Sunny

+0

Sự khác biệt ở đây là char * s = "Hello world"; sẽ đặt Hello world vào phần chỉ đọc của bộ nhớ và tạo một con trỏ tới đó, làm cho bất kỳ hoạt động viết nào trên bộ nhớ này bất hợp pháp. Khi đang thực hiện: char s [] = "Xin chào thế giới"; đặt chuỗi ký tự trong bộ nhớ chỉ đọc và sao chép chuỗi vào bộ nhớ mới được cấp phát trên ngăn xếp. Đặt s [0] = 'J'; hợp pháp. – Sunny

Các vấn đề liên quan