2017-02-19 108 views
1

我正在爲C構建一個裸骨執行環境,通過引導加載程序引導。引導可執行文件運行良好,但我無法從C調用asm例程。我已經在ASM中定義了一個函數'putchar',它應該可以從C調用。問題是,在調試所有對nasm的調用期間編譯後的程序集看起來只有幾個字節。用C偏移量連接的NASM

C源代碼如下:

#include "io.h" 

void kmain() { 
    putchr('!', 5); 
    while(1); 
} 

隨着io.h

extern void putchr(char c, int repeat); 

此編譯成:

│0x600 <kmain>   push 
│0x601 <kmain+1>   mov bp,sp 
│0x603 <kmain+3>   sub sp,0x18 
│0x606 <kmain+6>   mov WORD PTR [si+0x24],0x504 
│0x60b <kmain+11>  add BYTE PTR [bx+si],al 
│0x60d <kmain+13>  add bh,al 
│0x60f <kmain+15>  add al,0x24 
│0x611 <kmain+17>  and WORD PTR [bx+si],ax 
│0x613 <kmain+19>  add BYTE PTR [bx+si],al 
│0x615 <kmain+21>  call 0x625 ; Should be call to putchr 
│0x618 <kmain+24>  add BYTE PTR [bx+si],al 
│0x61a <kmain+26>  jmp 0x61a <kmain+26> ; I suppose this is while(1) 

putchr在組件定義和調用另一個內部功能有:

bits 32 

global putchr 

    nop 
    nop 
    nop 
    xor eax, eax 
    nop 
    nop 

putchr: 
    ; PutChar expects: al = character (first arg), cx = repeat (second arg) 
    push ebp 
    mov ebp, esp 

    mov eax, [ebp + 8] ; First arg 
    and eax, 0xFF  ; Only interested in lower 8 bytes (8-bit al register) 

      ; Note at this point eax = 0xc3/195 and not 0x21/33 as I'd expect 

    mov cx, [ebp + 12] ; Second arg 
    call PutChar 

的調用putchr是錯誤的,因爲putchr不在0x625,但倒數第二個我的彙編文件的頂部nop是存在的。 putchr起始於0x627。我想這也是我無法讀取傳遞的值的原因來自C.

我編譯和鏈接如下(5「!」):

nasm -f elf32 -F dwarf -g io.asm -o ../build/os/imm/asm/io.o 
gcc -ffreestanding -nostdlib -gdwarf-4 -m32 -ggdb3 -c kernel.c -o ../build/os/imm/c/kernel.o 
ld -m elf_i386 -nmagic -Tos.lds ../build/os/imm/c/kernel.o ../build/os/imm/asm/io.o -o ../build/os/os 

隨着鏈接腳本os.lds感相當基本的和直接的:

ENTRY(kmain); 

PHDRS { 
    headers PT_PHDR FILEHDR PHDRS; 
    code PT_LOAD; 
} 

SECTIONS { 
    .text 0x600: ALIGN(0x100) { *(.text) } :code 
    .data : { *(data) } 
    .bss : { *(bss) } 
    /DISCARD/ : { *(.eh_frame) } 
} 

爲什麼會出現這種奇怪的0X2的偏移,爲什麼不能在功能參數從組件實現被拾起?

+1

快速瀏覽一下,您就可以混合使用16位和32位代碼。你如何設法將'kmain'編譯爲16位並不明顯? – Jester

+0

根據命令行參數('-m32'),除彙編器文件中的位32外,所有內容都被編譯爲32位。 – Sebazzz

+0

其實我認爲你的'kmain'是32位,你只是將它錯誤地拆分爲16位。現在的問題當然是,你用什麼模式運行它?如果你還沒有切換到32位保護模式,CPU將執行代碼爲16位,這是行不通的。 – Jester

回答

0

我從來沒有發現這個問題不幸,但我使用的是16位C,因爲我想得到在擺弄了一段時間之後仍在工作。切換回32位我終於找到了問題:

mov esp, [stack] 

設置esp堆棧的地址,而不是,我將其設置爲堆棧。 OSDev wiki並沒有錯,指出操作系統的開發可能會導致數小時的調試,然後才能在面前看到答案!