ELF可执行问题

时间:2016-01-19 10:30:58

标签: linux elf

我在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),我使用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在运行SIGILL时会引发./test64-x86_64,即使程序在没有Valgrind的情况下似乎工作正常?

问题2:为什么我无法运行./test32-x86_64? Valgrind为该二进制文件提供的错误非常模糊......

2 个答案:

答案 0 :(得分:2)

首先,我无法在./test32-x86_64上重现您的错误。虽然我使用完全相同的代码和命令行来编译它。

我在Linux 4.3.3 x86_64(Debian)上运行。

  

问题1 :为什么Valgrind在运行SIGILL时会引发./test64-x86_64,即使程序在没有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。我的程序死了,在此过程中打印出这样的消息:

vex x86->IR: unhandled instruction bytes: 0x66 0xF 0x2E 0x5
     

一种可能是您的程序有错误并错误地跳转到非代码地址,在这种情况下您将获得SIGILL信号。 Memcheck可能会在此之前发出警告,但如果跳转发生在可寻址内存中,则可能不会发出警告。

     

另一种可能性是Valgrind不处理该指令。如果您使用的是旧版Valgrind,则较新版本可能会处理该指令。但是,所有指令集都有一些模糊的,很少使用的指令。此外,在amd64上,冗余指令前缀的组合数量几乎无限,其中许多没有记录,但被CPU接受。因此Valgrind将不时有解码失败。如果发生这种情况,请提交错误报告。

在我们的确切情况下,它只是意味着VEX中间语言没有将int 0x80指令识别为x86_64架构的一部分。

  

问题2 :为什么我无法运行./test32-x86_64? Valgrind为该二进制文件提供的错误非常模糊......

不幸的是,我无法用我的Valgrind重现你的错误。

答案 1 :(得分:2)

对于问题1:针对valgrind打开了一个错误,它不支持int80 instruction in x86_64。我能够在我自己的valgrind(v3.11.0)下重现这一点,并且从浏览源看起来好像它不受支持。

问题2:ELF加载程序不支持文件类型。为了在linux上提供32位二进制文​​件的兼容性,它必须在尝试执行二进制文件时对二进制文件进行一些检查。

当我们在test32-x86_64上使用readelf时,会显示一个标题:

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之所以没有看到问题是他的内核似乎是用正确的运行x32代码的选项编译的。

valgrind可能无法用二进制格式混淆 - 它不被认为特别常见。