assembly - 在运行时,程序集 x86 32/x86 64多语言机器代码 fragment 检测 64bit 模式?

  显示原文与译文双语对照的内容
79 1

是否可以使用相同的计算机代码来确定它们是在 32或者 64位模式下运行的,然后执行不同的操作。

i.e 。编写多语言机器代码。

通常可以在生成时使用 #ifdef 宏进行检测。 或者在C 中,可以编写一个具有编译时常数的if(),并使编译器优化它的另一端。

这对于奇怪的例子,比如代码注入,或者看看是否可以能是有用的。

另请参阅:多通道 arm/x86机器代码 on,根据哪个体系结构解码字节。

时间: 原作者:

107 0

最简单的方法是使用一个字节 inc 操作码,它被重新编译为 64bit 模式下的雷克斯前缀。 雷克斯前缀对 jcc 没有影响,因此你可以:


xor eax,eax ; clear ZF


db 0x40 ; 32bit: inc eax. 64bit: useless REX prefix


jz. 64bit_mode ; REX jcc works fine



这是一个完整的linux/nasm程序,如果运行为 64位或者以 32位运行,则使用 syscallexit(1),如果运行为位。

位 32和位 64的使用确保它以相同的方式组装到相同的机器代码。 ( 我检查了 objdump -d,以显示原始机器代码字节)

尽管如此,我使用 db 0x40 代替 inc eax,让它更加清晰。


BITS 32


global _start


_start:


 xor eax,eax ; clear ZF


 db 0x40 ; 32bit: inc eax. 64bit: useless REX prefix


 jz. 64bit_mode ; REX jcc still works



 ;jmp. 64bit_mode ; uncomment to test that the 64bit code does fault in a 32bit binary



.32bit_mode:


 xor ebx,ebx


 mov eax, 1 ; exit(0)


 int 0x80



BITS 64


.64bit_mode:


 lea rdx, [rel _start] ; An instruction that won't assemble in 32-bit mode.


 ;; arbitrary 64bit code here



 mov edi, 1


 mov eax, 231 ; exit_group(1).


 syscall ; This does SIGILL if this is run in 32bit mode on Intel CPUs




;;;;; Or as a callable function:


BITS 32


am_i_32bit: ;; returns false only in 64bit mode


 xor eax,eax



 db 0x40 ; 32bit: inc eax


 ; 64bit: REX.W=0


 ;nop ; REX nop is REX xchg eax,eax


 ret ; REX ret works normally, too



测试和工作 。 在同一机器代码中,我构建了两次以获取不同的ELF元数据。


$ yasm -felf64 -Worphan-labels -gdwarf2 x86-polyglot-32-64.asm && ld -o x86-polyglot.64bit x86-polyglot-32-64.o


$ yasm -felf32 -Worphan-labels -gdwarf2 x86-polyglot-32-64.asm && ld -melf_i386 -o x86-polyglot.32bit x86-polyglot-32-64.o


$./x86-polyglot.32bit && echo 32bit || echo 64bit


32bit


$./x86-polyglot.64bit && echo 32bit || echo 64bit


64bit



Assembling tag标签wiki中的FAQ部分,在 64位 系统( GNU工具链) 中构建来自的命令,并将它的从 FAQ 。

原作者:
...