【发布时间】:2015-03-02 17:18:33
【问题描述】:
我正在尝试实现一个函数,该函数试图以 QEmu 上看到的 16 位模式打印字符串:
kernel.c 文件:
void main()
{
char* str = "Hello World!";
printString(str);
}
printString 函数在另一个文件 printString.c 中定义:
int printString(char* string)
{
int i = 0;
while (*(string + i) != '\0')
{
char al = *(string + i);
char ah = 0xe;
int ax = ah * 256 + al;
interrupt(0x10,ax,0,0,0);
i++;
}
return i;
}
中断函数调用 BIOS 中断,函数的第一个参数给出,其他参数分别指定 ax、bx、cx 和 dx 寄存器的内容。这是代码
.global _interrupt
_interrupt:
push bp
mov bp, sp
push si
push ds
mov ax, #0x100
mov ds, ax
mov ax, [bp + 0x4]
mov si, #intr
mov [si + 1], al
pop ds
mov ax, [bp + 0x6]
mov bx, [bp + 0x8]
mov cx, [bp + 0xa]
mov dx, [bp + 0xc]
intr: int #0x0
pop si
pop bp
ret
我使用以下命令编译 .c 文件:
bcc -ansi -c -o <name.o> <name.c>
并使用以下方法链接它们:
ld86 -o kernel -d kernel.o interrupt.o printString.o
程序在屏幕上打印“S”,而不是打印“Hello World!”。我在地址 0x1000 加载了 kernel.c 文件。看到代码的反汇编:
0x1000: push %bp
0x1001: mov %sp,%bp
0x1003: push %di
0x1004: push %si
0x1005: dec %sp
0x1006: dec %sp
0x1007: mov $0xc8,%bx
0x100a: mov %bx,-0x6(%bp)
0x100d: pushw -0x6(%bp)
0x1010: call 0x1058
对于要传递给 printString 函数的指针(在 kernel.c 文件中),传递的参数是 0xc8,其中包含 0xf000ff53。因此,S 的 ASCII 码 53 会打印在屏幕上。
我应该如何将字符串传递给 printString 函数,为什么上面的代码不起作用?
如果需要更多解释,请告诉我。
【问题讨论】:
-
听起来
ds设置不正确。 -
天啊! 16位汇编!!!带回 90 年代的糟糕回忆!
-
@Jester 你对 ds 电阻器是正确的,并将其设置为 0x100 使其工作。但我不明白为什么这会奏效。即使我将 ds 寄存器更改为 0x100,上面的 mov 指令,即 mov $c8, %bx 也没有改变,写入 %bx 寄存器的值又是 0xc8。这些代码有什么区别?