装配在x86_64 i386的代码(Assembling i386 code on x86_64)

2019-07-20 05:48发布

预期下面的代码无法正常工作:

.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。 我能以某种方式效仿呢?

Answer 1:

这不是内存模型。

在气体语法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


文章来源: Assembling i386 code on x86_64