2013-08-11 12 views
6

私の印刷機能を使って画面に何かを印刷しようとしています。文字配列をパラメータとして渡す(Cカーネルコード)

私は小さな問題につまずいてきた - 私はこのような文字列渡すとき:

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

をそれが正常に動作しますが、私はこのようにそれを呼び出したときの影響はありません。ここで

print("abc"); 

私の関数宣言は

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

私は何かが足りないのですか? printfも同じように動作し、2番目の方法で文字列を渡すことができます。

EDIT:

定義

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:

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:

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

分解部の.textのkernel.oの objdumpは:

これは、私はここに、的環境をinitilisingい方法で何かあるかもしれないので、責任の2つのファイルは、以下のとおりです。

pmode.asmは、セグメントを-initializes、ここでカーネル

[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 

の先頭にジャンプどのように私は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

そして、あなたの関数**はどのように定義されていますか?つまり、実装されていますか? –

+0

@ H2CO3の定義が追加されました –

+0

あなたは 'const char *'を使うべきですが、それはおそらく無関係です。 – Dave

答えて

1

もっと大きな文字列で逆アセンブリを見た後、私は答えを見つけました。

理由は私がカーネルをリンクした理由でした。これらは私が使用するように助言されたコマンドました:

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

が、私は、WindowsのGCCを持っていたし、私のASMとCファイルは、ELF形式であったため、私はこのトリックを使用する必要がありました:

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

これはオブジェクトのテキスト部分だけをコピーしたので、私はバイナリバージョンを残しました。 .textオブジェクトの一部しかコピーしていないため、.rdataセクションに保存されていた文字列は失われました。したがって、objcopyにこれを追加するだけでした。

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

print(s)と言ったら、あなたは "s"と宣言したchar配列として渡しています。しかし、あなたがプリントとして渡すとき( "abc")。 "abc"のタイプは何ですか?それは定義されていません。私はこれがあなたの問題だと思います。また、char []をchar *に変更することをお勧めします。お役に立てれば。

+0

"abc"(リテラル文字列)のデータ型は、文字ポインタとして明確に定義されています。それについては何も定義されていません。 char s []とchar * sの間には違いはありません。 – amrith

+0

@amrith:char s []とchar *は実際には同じではありません。参考にしてください。ここに例があります。見てみましょう。 Cheers !! char * s = "hello"、ここでは実行時に別の文字列を指すことができますそれは実行時に別の値を割り当てることができる定数ポインタではないことを意味しますp = "Nishant"、s [ポインタ....別の文字列を再割り当てすることはできませんが、s [index]に別の文字値を割り当てることができます。 – Sunny

+0

ここでの違いは、 char * s = "Hello world"です。 は、メモリの読み取り専用部分にHello Worldを置き、そのメモリへのポインタを作成し、このメモリ上の書き込み操作を不正にします。実行中: char s [] = "Hello world"; は、リテラル文字列を読み取り専用メモリに置き、その文字列をスタック上の新しく割り当てられたメモリにコピーします。 s [0] = 'J'; は法律です。 – Sunny

関連する問題