在x86_64上组装i386代码

时间:2013-02-20 16:22:15

标签: assembly x86 offset gas i386

以下代码无法按预期工作:

.intel_syntax noprefix
.arch i386
.data
hello_world:
.ascii "Hello world!\n"
hello_world_end:
.equ hello_world_len, hello_world_end - hello_world
.text
.global _start
_start:
mov ebx, 1
mov ecx, hello_world
mov edx, hello_world_len
mov eax, 4
int 0x80

mov ebx, 0
mov eax, 1
int 0x80

跑过时:

as test.s -o test.o
ld test.o -o test
./test

它什么也没输出。当我改变这一行时:

mov ecx, offset hello_world ; added offset

工作正常。我尝试使用--32 -march=i386编译原始代码并链接到-m elf_i386,但它仍然没有输出任何内容。

$ uname -a
Linux ubuntu 3.2.0-38-generic #60-Ubuntu SMP Wed Feb 13 13:22:43 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

我猜这是因为内存模型不像i386那样平坦。我能以某种方式模仿这个吗?

1 个答案:

答案 0 :(得分:2)

这不是关于内存模型。

气体语法mov ecx, hello_world表示读取内存地址 hello_world,可以通过检查使用ndisasm完成的反汇编来确认:

00000000  BB01000000        mov ebx,0x1
00000005  8B0C25D4104000    mov ecx,[0x4010d4]
0000000C  BA0D000000        mov edx,0xd
00000011  B804000000        mov eax,0x4
00000016  CD80              int 0x80

您想要的是存储hello_world的内存地址。在气体中,实现这一目标的方法是mov ecx, offset hello_world,可以从反汇编中确认:

00000000  BB01000000        mov ebx,0x1
00000005  B9D4104000        mov ecx,0x4010d4
0000000A  BA0D000000        mov edx,0xd
0000000F  B804000000        mov eax,0x4
00000014  CD80              int 0x80

顺便说一句,另一种将内存地址加载到寄存器的方法是lea ecx, hello_world

其他一些汇编程序(例如NASM和YASM)具有不同的语法,这种差异可能会引起混淆,如小表所示:

gas                           NASM/YASM                ndisasm disassembly
mov ecx,hello_world           mov ecx,[hello_world]    mov ecx,[0x4010d4]
mov ecx,[hello_world]         mov ecx,[hello_world]    mov ecx,[0x4010d4]
mov ecx,offset hello_world    mov ecx,hello_world      mov ecx,0x4010d4