【发布时间】:2015-10-05 17:54:17
【问题描述】:
我对实模式寻址一定有一些基本的误解。我正在尝试设置一个功能以在实模式下通过 BIOS 中断打印文本。我正在使用在 DOSBox 下执行的 .com 文件测试代码。 .text 部分结束于 0x1000(.com 文件中的 0x0F00)。所以假设我想打印该文本的第一个字母。
xor ebx, ebx
mov ecx, 1
mov ah, 10
mov al, ds:[0x1000]
int 0x10
这行得通,并打印出“H”,因为我没有想象力。但是我不希望它只打印出同一个字母。我想传入一个指针,并且我想在打印更多文本时增加该指针。在这个阶段,我很高兴能从寄存器中读取偏移量。所以我做了以下更改。
mov edx, 0x1000
mov al, ds:[edx]
并且没有字符被打印。我尝试过使用 esi 和 edi 寄存器,结果相同。使用 lea edx,byte ptr [0x1000] 产生相同的结果。更糟糕的是,尝试使用 16 位等效项(dx、si、di)会导致程序挂起。我尝试查看 .com 文件中的机器代码,但找不到任何明显错误的内容。
我正在使用自定义链接器脚本和 objcopy 调用使用 gcc 编译代码以生成 .com 文件。未链接任何库,目标架构为 386。
任何帮助将不胜感激。
编辑:完整列表。
directio.s
.intel_syntax
.global _printChar
_printChar:
push ebp;
mov ebp, esp;
xor edx, edx;
xor ebx, ebx;
xor eax, eax;
mov ecx, 1;
mov ah, 10;
mov edx, 0x1000;
mov al, ds:[edx];
int 0x10;
mov esp, ebp
pop ebp;
ret;
dirTest.c
asm
(
".code16gcc;\n" \
"call _dosmain;\n" \
"mov ah, 0x4C;\n" \
"int 0x21;\n"
);
#include "directio.h"
int dosmain(void)
{
printChar("Hello World!");
return 0;
}
com_mingw.ld
SECTIONS
{
. = 0x0100;
.text :
{
*(.text);
}
.data :
{
*(.data);
*(.bss);
*(.rodata);
}
_heap = ALIGN(4);
}
所有这些都使用以下命令行编译。
gcc -std=gnu99 -Os -nostdlib -m32 -masm=intel -march=i386 -ffreestanding -o dirTest.com -Wl,--nmagic,--script=com_mingw.ld dirTest.c directio.s
紧随其后
objcopy dirTest.com -O binary
【问题讨论】:
-
出于好奇,您是否在代码开头设置了
DS(数据段),例如mov ax, @data,后跟mov ds, ax?如果我们看到您的整个程序(如果它不是太长的话)会有所帮助。哦,我看到你使用的是 GCC,所以设置DS会有点不同。我还想看看您的链接器脚本以及您用于构建和链接的实际命令 -
我已添加完整列表。目前,我正在 DOS 环境中测试所有内容。因此 DOS 将 cs 和 ds 设置为加载 .com 文件的偏移量。这些似乎设置正确,因为从 ds:[0x1000] 加载字符有效。代码从 0x100 开始。 .text 结束于 0x1000。
-
为了确保这不是对段偏移量的奇怪限制,我尝试了以下方法: mov edx, cs add edx, 0x0100 mov ds, edx xor edx, edx 再次,鳕鱼有效mov al, ds:[0] 很好,但是 mov al, ds:[edx] 失败了。我不知道为什么这些不是一回事。
-
是的,抱歉,来晚了,一开始没有注意到它是一个 COM 程序(所以是的,CS=DS=ES)
-
令人困惑的事情。使用对 printChar 的调用将字符串传递到堆栈上。您不使用堆栈上传递的地址而不是硬编码 0x1000 的任何特殊原因?
标签: assembly mingw i386 real-mode