繁体   English   中英

实模式汇编中指向.text的指针

[英]Pointer to .text in real mode assembly

关于实模式寻址,我肯定有一些误解。 我正在尝试设置一个在实模式下通过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,字节ptr [0x1000]产生相同的结果。 更糟糕的是,尝试使用16位等效项(dx,si,di)会导致程序挂起。 我尝试浏览.com文件中的机器代码,但找不到任何明显错误的东西。

我正在使用自定义链接程序脚本和objcopy调用使用gcc编译代码,以创建.com文件。 没有库链接,并且目标体系结构是386。

任何帮助将非常感激。

编辑:完整列表。

指令

.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

_printChar应该是16位函数,因此请勿将其汇编为32位。 在.s文件的顶部添加.code16gcc并将32位寄存器更改为16位:

.code16gcc
.intel_syntax
.global _printChar

_printChar:
    push bp;
    mov bp, sp

    xor dx, dx
    xor bx, bx
    xor ax, ax
    mov cx, 1

    mov ah, 10
    mov dx, 0x1000
    mov al, ds:[dx]     ; ERROR! See comments.
    int 0x10

    mov sp, bp
    pop bp
    ret

现在,它应该(希望)正常工作。

自从我上次以.com图像格式编写任何实模式代码以来,大约必须有三十年的时间,但是这里有一些观察结果:

  • 编写.com格式代码时,定义多个部分是不寻常的。 该格式仅允许一个 ,最大初始图像大小为64Kb;最大为64Kb。 按照惯例,它可能包含逻辑部分,通常称为“ CODE”和“ DATA”,或“ TEXT”和“ DATA”,但是必须将它们分组为单个物理段; 禁止使用“ STACK”类的任何显式段。
  • MS-DOS是16位操作系统,因此您必须使用16位寄存器(或其8位子寄存器)编写代码。
  • 16位处理器不允许您使用BX,SI,DI和BP以外的任何寄存器作为用于间接存储器寻址的基址寄存器。 不能为此使用DX,(如您一样),CX或AX; (您可能可以使用SP,但是通常不要理会它,保留它作为堆栈指针的预期用途)。
  • 当操作系统加载.com格式的过程映像时,它首先分配一个环境块,然后分配它后面的程序段。 然后,使用管理数据填充程序段的前256个字节(创建通常称为程序段前缀,即PSP),然后立即从地址0x100开始加载.com映像((您所提到的0x1000只是程序段中的任意偏移量,在该段中(大概是)您的数据已定义,但是它没有任何神圣不可侵犯的地方—程序代码很容易出现在其中。
  • 加载映像后,操作系统将所有四个段寄存器设置为程序段的开头,并设置CS:IP(通过执行FAR JMP或可能的FAR CALL),以在程序段开始执行进程。适当的入口地址,该地址始终位于程序段内的偏移量0x100(与您的0x1000数据地址没有 任何关系 )中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM