我的 puts 函数在 16 位代码中不起作用
My puts function is not working in 16-bit code
我正在使用 GCC 和一个小型汇编程序 bootstrap 例程编写引导加载程序。我编写了一个 puts
例程,该例程使用 BIOS 中断将字符串打印到显示器上,但似乎无法正确写入字符串。
我的 bootstrap 汇编文件 boot.s
包含:
.code16 .section .text
.extern main
.globl start
start:
mov [=10=]x7c0, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
jmp main
here:
hlt
jmp here
我的 C 在 main.c
中的代码是:
/*
* 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 2, %%sp\n" : : "a" (ss), "r" (size)\
); \
}
#define set_videomode(mode) \
{ \
__asm__ __volatile__ ( \
"int [=11=]x10\n" : : "a" (mode) \
); \
}
void putchar_bios(unsigned char ch)
{
__asm__ __volatile__ (
"int [=11=]x10\n" : : "a" (0x0E | ch)
);
}
void puts(char *str)
{
while(*str)
putchar_bios(*str++);
}
void main()
{
set_stack(0x07C0, 512);
set_videomode(0x03);
char name[] = "0001234567890";
puts(name);
//This works fine.
// for(i=0; i<15; i++)
// putchar_bios(name[i]);
while(1);
}
我已经完全在汇编中成功地做到了这一点,但现在我正试图将它迁移到 GCC 。我正在使用交叉编译器 (i386-gcc) 并且还使用了 -m16
标志。我使用了自定义 linker 脚本。
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中的link和运行是:
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
函数正确显示字符串?
我意识到我将段寄存器的值设置为一些垃圾 (0x7c0),这导致了这种情况的发生。我修改了我的汇编文件以将段寄存器清零。代码现在看起来像:
.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
我原以为编译器会自动初始化段寄存器,但事实并非如此。
我正在使用 GCC 和一个小型汇编程序 bootstrap 例程编写引导加载程序。我编写了一个 puts
例程,该例程使用 BIOS 中断将字符串打印到显示器上,但似乎无法正确写入字符串。
我的 bootstrap 汇编文件 boot.s
包含:
.code16 .section .text
.extern main
.globl start
start:
mov [=10=]x7c0, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
jmp main
here:
hlt
jmp here
我的 C 在 main.c
中的代码是:
/*
* 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 2, %%sp\n" : : "a" (ss), "r" (size)\
); \
}
#define set_videomode(mode) \
{ \
__asm__ __volatile__ ( \
"int [=11=]x10\n" : : "a" (mode) \
); \
}
void putchar_bios(unsigned char ch)
{
__asm__ __volatile__ (
"int [=11=]x10\n" : : "a" (0x0E | ch)
);
}
void puts(char *str)
{
while(*str)
putchar_bios(*str++);
}
void main()
{
set_stack(0x07C0, 512);
set_videomode(0x03);
char name[] = "0001234567890";
puts(name);
//This works fine.
// for(i=0; i<15; i++)
// putchar_bios(name[i]);
while(1);
}
我已经完全在汇编中成功地做到了这一点,但现在我正试图将它迁移到 GCC 。我正在使用交叉编译器 (i386-gcc) 并且还使用了 -m16
标志。我使用了自定义 linker 脚本。
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中的link和运行是:
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
函数正确显示字符串?
我意识到我将段寄存器的值设置为一些垃圾 (0x7c0),这导致了这种情况的发生。我修改了我的汇编文件以将段寄存器清零。代码现在看起来像:
.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
我原以为编译器会自动初始化段寄存器,但事实并非如此。