当我在 Linux Box 上时,我使用 bash 作为 shell。现在我想知道 bash 如何处理 ELF 文件的执行,即当我输入 ./program 并且 program 是一个 ELF 文件时。我搜索了 bash-4.3.tar.gz,似乎没有某种幻数解析器来确定文件是否为 ELF,也没有找到 exec() 系统调用。
整个进程如何运作?bash 如何将 ELF 的执行传递给操作系统?
Linux系统加载共享库时,共享库的内存布局是怎样的?
例如,原始内存布局如下:
+-----------+
|heap(ori) |
+-----------+
|stack(ori) |
+-----------+
|.data(ori) |
+-----------+
|.text(ori) |
+-----------+
Run Code Online (Sandbox Code Playgroud)
当我 dlopen 时foo.so,内存布局是 A 还是 B?
A
+-----------+
|heap(ori) |
+-----------+
|stack(ori) |
+-----------+
|.data(ori) |
+-----------+
|.text(ori) |
+-----------+
|heap(foo) |
+-----------+
|stack(foo) |
+-----------+
|.data(foo) |
+-----------+
|.text(foo) |
+-----------+
Run Code Online (Sandbox Code Playgroud)
或者
B
+-----------+
|heap(ori) |
+-----------+
|heap(foo) |
+-----------+
|stack(foo) |
+-----------+
|stack(ori) |
+-----------+
|.data(foo) |
+-----------+
|.data(ori) |
+-----------+
|.text(foo) |
+-----------+
|.text(ori) |
+-----------+
Run Code Online (Sandbox Code Playgroud)
或者除了A和B之外的任何东西......?
在每次加载 lib 时,我都会收到错误消息:
没有可用的版本信息
这个库是在另一台 PC (ubuntu 10.04) 上编译的,而不是运行它的 PC (mandriva 2010.2)。
$ ldd /usr/local/gnu-eabi-4.5.2/i686-pc-linux-gnu/arm-eabi/lib/libbfd-2.21.so
/usr/local/gnu-eabi-4.5.2/i686-pc-linux-gnu/arm-eabi/lib/libbfd-2.21.so: /lib/libz.so.1: no version information available (required by /usr/local/gnu-eabi-4.5.2/i686-pc-linux-gnu/arm-eabi/lib/libbfd-2.21.so)
linux-gate.so.1 => (0xffffe000)
libz.so.1 => /lib/libz.so.1 (0xb77a7000)
libc.so.6 => /lib/i686/libc.so.6 (0xb7655000)
/lib/ld-linux.so.2 (0xb787a000)
Run Code Online (Sandbox Code Playgroud)
编辑:解决方法不起作用。
我想找到从内核的角度来看可执行的文件类型。据我所知,Linux 上的所有可执行文件都是 ELF 文件。因此,我尝试了以下操作:
find * | file | grep ELF
但是这不起作用;有人有其他想法吗?
在如何从 vmlinux.bin 中提取文件系统映像?和https://wiki.gentoo.org/wiki/Custom_Initramfs#Salvaging提供了获取和解包内核映像中包含的嵌入式 initramfs/initrd 的方法。
现在我想将修改后的文件系统(cpio+ 可能使用 eg 打包lzma)插入到内核可执行文件中,而不必重新编译它。是否可以通过这种方式修改内核的 ELF 映像?如果是,那么如何?如果我只是就地替换字节(也许是一些哈希?),我是否需要保留一些东西?
objdump-h 输出:
vmlinux.64.orig: file format elf64-big
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 004162b8 ffffffff80100000 ffffffff80100000 00010000 2**7
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 __ex_table 000063a0 ffffffff805162c0 ffffffff805162c0 004262c0 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .notes 00000024 ffffffff8051c660 ffffffff8051c660 0042c660 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .rodata 0041f700 ffffffff8051d000 ffffffff8051d000 0042d000 2**8
CONTENTS, ALLOC, LOAD, …Run Code Online (Sandbox Code Playgroud) 您还可以选择控制符号的 ELF 可见性。只需添加可见性关键字之一:
default、internal、hidden或protected。default当然是默认的。
这些是在哪里定义的?以及如何ld使用它们?我看到C++ 中经常提到的访问级别包括protected、public和 private,但我不知道这是否是 ELF 所引用的?
我的用例是 C 和汇编,因此如果您能让这与这两种语言和链接器相关,那就加分了。
我一直在做练习,试图了解程序背后发生的一些事情。我编写了一个小 C 程序,并在 i386 Linux (Ubuntu 12.04) 上使用gcc. 然后我hexdump -C对输出到文本文件做了一个。我注意到偏移量上有一些间隙*:
00000670 00 3f 1a 3b 2a 32 24 22 1c 00 00 00 40 00 00 00 |.?.;*2$"....@...|
00000680 94 fd ff ff 05 01 00 00 00 41 0e 08 85 02 42 0d |.........A....B.|
00000690 05 03 01 01 c5 0c 04 04 38 00 00 00 60 00 00 00 |........8...`...|
000006a0 80 fe ff ff 61 00 00 00 00 …Run Code Online (Sandbox Code Playgroud) 我试图了解符号表如何与 ELF 中的 .data 部分相关。首先是一些我作为基础的假设。
符号是映射到实际二进制值(CPU 对其进行操作)的函数或变量的人类可读(或“写在源文件中”)表示。
这是一个例子
//simple.c
int var_global_init = 5;
int main(void)
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
让我们构建它并检查二进制文件:
$ gcc simple.c -o simple
$ objdump -t simple | grep var_global_init
0000000000201010 g O .data 0000000000000004 var_global_init
Run Code Online (Sandbox Code Playgroud)
它列出了.dataELF 文件部分中的符号。ELF 文档的第 20 页
将该.data部分定义为:
这些部分保存有助于程序内存映像的初始化数据。
好吧,这样的搭配。那么我问自己Does this mean that the symbol table is
embedded in the .data section?。但这似乎被下面的例子反驳了:
$ readelf -s simple
Symbol table '.symtab' contains 66 entries:
....
50: 0000000000201010 4 …Run Code Online (Sandbox Code Playgroud) 当linux有execve()一个ELF时,它会将该ELF映射到进程的内存空间中,并从入口点开始运行代码。但是内核是如何决定ELF的加载地址和入口点的呢?
如果禁用 ASLR,它将查找.p_vaddr每个 PT_LOAD 段并使用.e_entryELF 标头作为入口点。
但是如果启用 ASLR 会怎样呢?内核是否会简单地向上述所有内容添加随机移位,但保持它们的相对位置?
ELF的内容会影响内核的行为吗?就像.p_vaddrPT_LOAD 段的最小值是零还是非零?比如.e_typeELF header是ET_DYN还是ET_EXEC?
我特别谈论的是 x86_64。
我有一个 ELF 二进制文件,它只包含程序头表中的两个 LOAD 段,一个用于代码,一个用于数据。readelf -a告诉我没有节标题。
如果我尝试使用 ARM cross binutils 在我的 amd64 机器上反汇编 ARM 二进制文件,它不会给我正确的输出。然而,据我了解,二进制文件的架构不应该与这个问题相关,因为这个问题与 ELF 相关。
$ file ./binary
./binary: ELF 32-bit LSB executable, ARM, EABI5 version 1 (GNU/Linux), statically linked, stripped
$ arm-linux-gnueabi-objdump -d ./binary
./binary: file format elf32-littlearm
$ arm-linux-gnueabi-objdump -x ./binary
./binary: file format elf32-littlearm
./binary
architecture: arm, flags 0x00000102:
EXEC_P, D_PAGED
start address 0x0004c8d8
Program Header:
LOAD off 0x00000000 vaddr 0x00010000 paddr 0x00010000 align 2**16
filesz 0x0003d27e memsz 0x0003d27e flags r-x
LOAD off …Run Code Online (Sandbox Code Playgroud)