2

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

.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 那样平坦。我可以以某种方式模仿吗?

4

1 回答 1

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. 在gas中实现的方式是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

顺便说一句,将内存地址加载到寄存器中的另一种方法是.leaecx, 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
于 2013-02-20T16:26:38.057 回答