ELF 可执行问题
ELF executable issues
linux.
上的 ELF 可执行文件出现一些奇怪的问题
这是我的系统(uname -a
):
Linux 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt20-1+deb8u2 (2016-01-02) x86_64 GNU/Linux
我有以下程序 (test.asm),我 assemble 使用 NASM:
; program just exits with code 0 using linux INT 80H
SECTION .data
SECTION .text
GLOBAL _start
_start:
MOV EAX, 1
XOR EBX, EBX
INT 0x80
我创建了三个不同的可执行文件:
nasm -f elf32 -o test32-i386.o test.asm
ld -m elf_i386 -o test32-i386 test32-i386.o
nasm -f elfx32 -o test32-x86_64.o test.asm
ld -m elf32_x86_64 -o test32-x86_64 test32-x86_64.o
nasm -f elf64 -o test64-x86_64.o test.asm
ld -m elf_x86_64 -o test64-x86_64 test64-x86_64.o
这是 file
命令的输出:
test32-i386: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped
test32-x86_64: ELF 32-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
test64-x86_64: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
对我来说很有意义。但是,运行宁可惹麻烦。
./test32-i386
:没问题,运行没问题。
./test64-x86_64
: 一样,运行没问题。
./test32-x86_64
但是,给出 bash: ./test32-x86_64: cannot execute binary file: Exec format error
另外,Valgrind 产生...有趣的结果。
valgrind ./test32-i386
: 好的
valgrind ./test64-x86_64
:加注 SIGILL
(?!)
valgrind ./test32-x86_64
: 给我 ./test32-x86_64: 1: ./test32-x86_64: Syntax error: word unexpected (expecting ")")
所以,总结一下:
问题 1:为什么 Valgrind 在 运行s ./test64-x86_64
时会引发 SIGILL
,即使程序在没有 Valgrind 的情况下似乎运行良好?
问题2:为什么我不能运行./test32-x86_64
? Valgrind 为该二进制文件给出的错误非常模糊...
首先,我无法在 ./test32-x86_64
上重现您的错误。虽然我使用完全相同的代码和命令行来编译它。
我是 运行 Linux 4.3.3 x86_64 (Debian)。
Question 1: Why does Valgrind raise SIGILL
when it runs ./test64-x86_64
even though the program seems to work fine without Valgrind?
我的 Valgrind 版本 (3.11.0) 不会对此发出 SIGILL
,但会发出此消息(然后按预期执行程序):
valgrind: wrong ELF executable class (eg. 32-bit instead of 64-bit)
但是,当 运行 text64-x86_64
Valgrind 抛出以下消息时:
vex amd64->IR: unhandled instruction bytes: 0xCD 0x80 0x0 0x0 0x0 0x0 0x0 0x0
vex amd64->IR: REX=0 REX.W=0 REX.R=0 REX.X=0 REX.B=0
vex amd64->IR: VEX=0 VEX.L=0 VEX.nVVVV=0x0 ESC=NONE
vex amd64->IR: PFX.66=0 PFX.F2=0 PFX.F3=0
如 Valgrind FAQ 中所述:
3.3. My program dies, printing a message like this along the way:
vex x86->IR: unhandled instruction bytes: 0x66 0xF 0x2E 0x5
One possibility is that your program has a bug and erroneously jumps to a non-code address, in which case you'll get a SIGILL signal. Memcheck may issue a warning just before this happens, but it might not if the jump happens to land in addressable memory.
Another possibility is that Valgrind does not handle the instruction. If you are using an older Valgrind, a newer version might handle the instruction. However, all instruction sets have some obscure, rarely used instructions. Also, on amd64 there are an almost limitless number of combinations of redundant instruction prefixes, many of them undocumented but accepted by CPUs. So Valgrind will still have decoding failures from time to time. If this happens, please file a bug report.
在我们的精确案例中,它只是意味着 VEX 中间语言没有将 int 0x80
指令识别为 x86_64
架构的一部分。
Question 2: Why can't I run ./test32-x86_64
? The error Valgrind gives for that binary is very obscure...
不幸的是,我无法用我的 Valgrind 重现您的错误。
对于问题 1:有一个针对 valgrind 的漏洞,它不支持 int80 instruction in x86_64。我能够在我自己的 valgrind (v3.11.0) 下重现它,并且通过浏览源代码,它似乎不受支持。
对于问题2:您的ELF加载器不支持该文件类型。为了在 linux 上提供 32 位二进制文件的兼容性,它必须在尝试执行时对二进制文件进行一些检查。
当我们在 test32-x86_64 上使用 readelf 时,它会显示一个 header of:
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400060
Start of program headers: 52 (bytes into file)
Start of section headers: 288 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 1
Size of section headers: 40 (bytes)
Number of section headers: 5
Section header string table index: 2
即class为32位,机器类型为x86_64。即它是一个 x32 ABI 二进制文件
问题是这需要你的内核配置CONFIG_X86_X32_ABI
,否则你会掉foul of the check:
#define compat_elf_check_arch(x) \
(elf_check_arch_ia32(x) || \
(IS_ENABLED(CONFIG_X86_X32_ABI) && (x)->e_machine == EM_X86_64))
只支持 32 位二进制文件,没有配置选项。如果您有内核选项,则会设置此选项:CONFIG_X86_X32=y 和 CONFIG_X86_X32_DISABLED 未设置(这是我正在查看的 linux 内核 4.3 源代码)。
因此,您需要为内核配置此支持才能使代码达到 运行 - perror 没有发现问题的原因是他的内核似乎是使用 [=39] 的正确选项编译的=]宁 x32 代码。
valgrind 可能被二进制格式弄糊涂了——它并不被认为特别常见。
linux.
上的 ELF 可执行文件出现一些奇怪的问题这是我的系统(uname -a
):
Linux 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt20-1+deb8u2 (2016-01-02) x86_64 GNU/Linux
我有以下程序 (test.asm),我 assemble 使用 NASM:
; program just exits with code 0 using linux INT 80H
SECTION .data
SECTION .text
GLOBAL _start
_start:
MOV EAX, 1
XOR EBX, EBX
INT 0x80
我创建了三个不同的可执行文件:
nasm -f elf32 -o test32-i386.o test.asm
ld -m elf_i386 -o test32-i386 test32-i386.o
nasm -f elfx32 -o test32-x86_64.o test.asm
ld -m elf32_x86_64 -o test32-x86_64 test32-x86_64.o
nasm -f elf64 -o test64-x86_64.o test.asm
ld -m elf_x86_64 -o test64-x86_64 test64-x86_64.o
这是 file
命令的输出:
test32-i386: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped
test32-x86_64: ELF 32-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
test64-x86_64: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
对我来说很有意义。但是,运行宁可惹麻烦。
./test32-i386
:没问题,运行没问题。./test64-x86_64
: 一样,运行没问题。./test32-x86_64
但是,给出bash: ./test32-x86_64: cannot execute binary file: Exec format error
另外,Valgrind 产生...有趣的结果。
valgrind ./test32-i386
: 好的valgrind ./test64-x86_64
:加注SIGILL
(?!)valgrind ./test32-x86_64
: 给我./test32-x86_64: 1: ./test32-x86_64: Syntax error: word unexpected (expecting ")")
所以,总结一下:
问题 1:为什么 Valgrind 在 运行s ./test64-x86_64
时会引发 SIGILL
,即使程序在没有 Valgrind 的情况下似乎运行良好?
问题2:为什么我不能运行./test32-x86_64
? Valgrind 为该二进制文件给出的错误非常模糊...
首先,我无法在 ./test32-x86_64
上重现您的错误。虽然我使用完全相同的代码和命令行来编译它。
我是 运行 Linux 4.3.3 x86_64 (Debian)。
Question 1: Why does Valgrind raise
SIGILL
when it runs./test64-x86_64
even though the program seems to work fine without Valgrind?
我的 Valgrind 版本 (3.11.0) 不会对此发出 SIGILL
,但会发出此消息(然后按预期执行程序):
valgrind: wrong ELF executable class (eg. 32-bit instead of 64-bit)
但是,当 运行 text64-x86_64
Valgrind 抛出以下消息时:
vex amd64->IR: unhandled instruction bytes: 0xCD 0x80 0x0 0x0 0x0 0x0 0x0 0x0
vex amd64->IR: REX=0 REX.W=0 REX.R=0 REX.X=0 REX.B=0
vex amd64->IR: VEX=0 VEX.L=0 VEX.nVVVV=0x0 ESC=NONE
vex amd64->IR: PFX.66=0 PFX.F2=0 PFX.F3=0
如 Valgrind FAQ 中所述:
3.3. My program dies, printing a message like this along the way:
vex x86->IR: unhandled instruction bytes: 0x66 0xF 0x2E 0x5
One possibility is that your program has a bug and erroneously jumps to a non-code address, in which case you'll get a SIGILL signal. Memcheck may issue a warning just before this happens, but it might not if the jump happens to land in addressable memory.
Another possibility is that Valgrind does not handle the instruction. If you are using an older Valgrind, a newer version might handle the instruction. However, all instruction sets have some obscure, rarely used instructions. Also, on amd64 there are an almost limitless number of combinations of redundant instruction prefixes, many of them undocumented but accepted by CPUs. So Valgrind will still have decoding failures from time to time. If this happens, please file a bug report.
在我们的精确案例中,它只是意味着 VEX 中间语言没有将 int 0x80
指令识别为 x86_64
架构的一部分。
Question 2: Why can't I run
./test32-x86_64
? The error Valgrind gives for that binary is very obscure...
不幸的是,我无法用我的 Valgrind 重现您的错误。
对于问题 1:有一个针对 valgrind 的漏洞,它不支持 int80 instruction in x86_64。我能够在我自己的 valgrind (v3.11.0) 下重现它,并且通过浏览源代码,它似乎不受支持。
对于问题2:您的ELF加载器不支持该文件类型。为了在 linux 上提供 32 位二进制文件的兼容性,它必须在尝试执行时对二进制文件进行一些检查。
当我们在 test32-x86_64 上使用 readelf 时,它会显示一个 header of:
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400060
Start of program headers: 52 (bytes into file)
Start of section headers: 288 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 1
Size of section headers: 40 (bytes)
Number of section headers: 5
Section header string table index: 2
即class为32位,机器类型为x86_64。即它是一个 x32 ABI 二进制文件
问题是这需要你的内核配置CONFIG_X86_X32_ABI
,否则你会掉foul of the check:
#define compat_elf_check_arch(x) \
(elf_check_arch_ia32(x) || \
(IS_ENABLED(CONFIG_X86_X32_ABI) && (x)->e_machine == EM_X86_64))
只支持 32 位二进制文件,没有配置选项。如果您有内核选项,则会设置此选项:CONFIG_X86_X32=y 和 CONFIG_X86_X32_DISABLED 未设置(这是我正在查看的 linux 内核 4.3 源代码)。
因此,您需要为内核配置此支持才能使代码达到 运行 - perror 没有发现问题的原因是他的内核似乎是使用 [=39] 的正确选项编译的=]宁 x32 代码。
valgrind 可能被二进制格式弄糊涂了——它并不被认为特别常见。