2016-07-06 9 views
1

GCC 및 작은 어셈블러 부트 스트랩 루틴을 사용하여 부트 로더를 작성하고 있습니다. 문자열을 제대로 기록하는 것으로 보이지 않는 BIOS 인터럽트를 사용하여 디스플레이에 문자열을 인쇄하는 puts 루틴을 작성했습니다.내 puts 함수가 16 비트 코드에서 작동하지 않습니다.

내 부트 스트랩 어셈블러 파일 boot.s에는 다음이 포함

/* 
* A 16 bit bootloader. 
*/ 

void putchar_bios(unsigned char ch); 
void set_videomode(unsigned short mode); 
void puts(char str[]); 

#define set_stack(ss, size)          \ 
{                \ 
    __asm__ __volatile__ (          \ 
      "mov  %%ax,  %%ss\n"       \ 
      "mov  $512,  %%sp\n" : : "a" (ss), "r" (size)\ 
     );              \ 
} 

#define set_videomode(mode)          \ 
{                \ 
    __asm__ __volatile__ (          \ 
      "int $0x10\n" : : "a" (mode)      \ 
     );              \ 
} 

void putchar_bios(unsigned char ch) 
{ 
    __asm__ __volatile__ (
      "int $0x10\n" : : "a" (0x0E | ch) 
     ); 
} 

void puts(char *str) 
{ 
    while(*str) 
     putchar_bios(*str++); 
} 

void main() 
{ 
    set_stack(0x07C0, 512); 
    set_videomode(0x03); 

    char name[] = "00"; 
    puts(name); 

    //This works fine. 
    // for(i=0; i<15; i++) 
    //  putchar_bios(name[i]); 
    while(1); 
} 

내가 성공적으로 전체 어셈블리에 이런 짓을했는지,하지만 지금은 내가하려고 해요 :

.code16 .section .text 

.extern main 
.globl start 
start: 

    mov  $0x7c0,  %ax 
    mov  %ax,  %ds 
    mov  %ax,  %es 
    mov  %ax,  %fs 
    mov  %ax,  %gs 

    jmp  main 

here: 
    hlt 
    jmp here 

main.c 나의 C 코드는 그것을 GCC으로 마이그레이션하십시오. 나는 크로스 컴파일러 (i386-gcc)를 사용 중이며 -m16 플래그도 사용했습니다. 나는 커스텀 링커 스크립트를 사용했다.

OUTPUT_FORMAT("binary"); 
ENTRY(start); 
SECTIONS 
{ 
    . = 0x7C00; 
    .text : AT(0x7C00) { 
     *(.text); 
    } 
    .data : SUBALIGN(0) { 
     *(.data); 
     *(.rodata); 
    } 
    .bss : SUBALIGN(4) { 
     __bss_start = .; 
     *(.COMMON); 
     *(.bss) 
     . = ALIGN(4); 
     __bss_end = .; 
    } 
    __bss_sizel = SIZEOF(.bss)>>2; 
    __bss_sizeb = SIZEOF(.bss); 

    /* Boot signature */ 
    .sig : AT(0x7DFE) { 
     SHORT(0xaa55); 
    } 
} 

내가 QEMU를, 링크를 컴파일하고 에서 실행하는 데 사용되는 스크립트는 다음과 같습니다

i386-elf-gcc -m16 -static -ffreestanding -nostdlib -c boot/boot.s 
i386-elf-gcc -m16 -static -ffreestanding -nostdlib -c boot/main.c 
i386-elf-ld -T link.ld -o b.bin -nostdlib --nmagic boot.o main.o 
dd if=b.bin of=HD.img conv=notrunc 
#add some noticable garbage to second sector since I also try to read it next 
echo "This is the second sector..................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................." | dd seek=512 bs=1 of=HD.img 

qemu-system-i386 -hda HD.img # -boot a -s -S 

왜 내 프로그램이 제대로 내 puts 기능을 통해 문자열을 표시하지 않는 이유는 무엇입니까?

+0

'puts'라는 빌트인 컴파일러와 충돌 할 가능성이 있습니다. 즉, 다른 이름으로 바꾸면 작동합니까? 또한 int 0x10 아아 = 0x13 당신이 한 번에 문자열을 인쇄하는 대신 사용할 수 있습니다. – Rup

+0

크로스 컴파일러를 사용하고 있기 때문에 이름이 충돌하지 않으며 [표준 라이브러리가 전혀 없습니다.]. 그리고 나는 BIOS를 사용하지 않고 자립 할 것이므로 BIOS 기능을 사용하지 않았다. –

+2

OK. 문서에서'-nostdlib'가 자동으로'-fno-builtin'을 의미한다는 것은 확실하지 않습니다. – Rup

답변

1

세그먼트 레지스터의 값을 일부 가비지 (0x7c0)로 설정하여이 문제가 발생 함을 알았습니다. 어셈블리 파일을 수정하여 세그먼트 레지스터를 0으로 만듭니다. 코드는 이제 다음과 같이 보입니다 :

.code16 
.section .text 

.extern main 
.globl start 
start: 

    xor  %ax,  %ax 
    mov  %ax,  %ds 
    mov  %ax,  %es 
    mov  %ax,  %fs 
    mov  %ax,  %gs 

    jmp  main 

here: 
    hlt 
    jmp here 

컴파일러가 세그먼트 레지스터를 자동으로 초기화 할 것으로 예상했지만 그렇지 않았습니다.