【问题标题】:Error while assembling the code in x86 Assembly在 x86 汇编中汇编代码时出错
【发布时间】:2015-03-15 09:13:15
【问题描述】:

我有以下代码:

.global _launchProgram
_launchProgram:
push bp
mov bp, sp
push cs
mov bx, [bp + 4]
mov cs, bx
mov es, bx
eseg
call #0x0
pop bx
mov cs, bx
pop bp
ret

在这段代码中,我试图让它跳转到另一段代码并执行它。这段代码是从 C 中调用的,如下所示:

launchProgram(segment) //Here segment is an integer which holds the 
                       //memory segment where I have loaded my code

因此,在这个函数中,我使 cs 寄存器等于段变量,并使用call 0x0 跳转到该段的开头。但是当我使用它运行它时:

as86 launchProgram.asm -o launchProgram.o

我收到以下错误:

00010 000C           E8         0000            call #0x0
***** relocation impossible.................................^

为什么会出现这个错误?

【问题讨论】:

    标签: c assembly x86 as86


    【解决方案1】:

    您的call #0x0 似乎在 as86 中指定了一个与 IP(指令指针)相关的调用(相对于下一条指令的偏移量)。那是故意的吗? as86 可能会抱怨,因为它需要一个标签或符号,如果需要,链接器将能够解析(重定位)。

    as86 手册页有以下内容:

    'near'和'far'不允许多段编程,全是'far' 操作是通过使用指令明确指定的:jmpi, jmpf、callf、retf 等。 'Near' 运算符可用于强制使用 80386 16 位条件分支。 'Dword' 和 'word' 运算符可以控制 远跳转和调用操作数的大小。

    如果我改用callf 0x12345678,0x1234,代码会进行汇编,生成以下指令:

    $ as86 a.asm -o a.o
    $ objdump -D -b binary -mi386 -Maddr16,data16,intel a.o
    ...
    3b: 8e cb                   mov    cs,bx
    3d: 8e c3                   mov    es,bx
    3f: 26 66 9a 78 56 34 12    es call 0x1234:0x12345678
    46: 34 12 
    48: 5b                      pop    bx
    48: 5b                      pop    %bx
    ...
    

    -b binary 需要,因为它是原始代码,-mi386 选择指令集,-Maddr16,data16,intel 选择 Intel 语法和 16 位代码,这似乎是 as86 默认生成的。)

    callf 的第二个操作数似乎是地址的段选择器部分(callf 的单个操作数导致 as86 抱怨)。我的 x86-fu 太弱了,不能说调用中的段覆盖是否真的有意义。当然,您的代码中需要callf #0x0,#0x0

    如果您想“欺骗” as86 生成与您尝试执行的操作相同的相对 call(不确定这是否有意义——您可能会从任何 IP 中获取随机位),那么您可以执行以下操作:

    eseg
    call zero_offset
    zero_offset: pop bx
    

    输出是

      53:   26 e8 00 00             es call 0x57
    

    ,其中00 00 部分显示偏移量为0。

    【讨论】:

    • 谢谢...但我仍然不明白如何跳到(新)cs 段的开头。我想跳到 cs:0x0 但是如果我使用 callf cs, 0x0,as86 仍然在抱怨,但是这个 callf cs 似乎正在工作。一般来说,我怎样才能使用寄存器拨打远距离电话??
    • @sarthak: callf cs 似乎生成了一条 FF 指令(参见x86.renejeschke.de/html/file_module_x86_id_26.html 中的第 3 行和第 4 行),objdump 仅显示为“(坏)”,因此使用 CS与那些可能是不合法的。我不是 x86 专家,但请尝试在 eseg 之后简单地做 callf 0x0,0x0。也许段覆盖前缀会覆盖指令中的 0x0 段选择器。
    • 你真的需要在运行时计算段地址吗?否则,您可能直接将其放入 callf (作为第二个操作数)。
    • 对了,你打算在什么环境下运行这段代码?
    • 不,我只需要跳转到段的开头,我正在使用 qemu 运行
    【解决方案2】:

    我认为在调用之前设置 cs 不是一个好主意,被调用的过程不知道如何返回。你必须执行一个远调用, 调用段:偏移量。这会将 ip 和 cs 寄存器的值压入堆栈以供返回。对于您的代码,例如:调用 cs:0x00 esag 也是 x86 指令吗?

    搜索this链接

    【讨论】:

    • 我认为您在谈论 nasm 语法。使用 as86 你不能使用像 call cs:0x0 这样的语法,而是你必须像我所做的那样将它分成两个命令,所以 eseg 后跟 call 0x0 应该是 call es:0x0
    最近更新 更多