`

第3章 目标文件(ELF格式)

 
阅读更多

源文件SimpleSection.c为:

int printf(const char* format, ...);

int global_init_var=84;
int global_uninit_var;

void func1(int i){
	printf("%d\n", i);
}

int main(void){
	static int static_var=85;
	static int static_var2;

	int a=1;
	int b;
	
	func1(static_var+static_var2+a+b);
	
	return a;
}

 

经过: $ gcc -c SimpleSection.c    预处理 -> 编译(产生汇编代码) -> 汇编(产生obj文件),尚未链接。

此时得到SimpleSection.o,下面均是对SimpleSection.o的观察分析:

 

一、查看ELF文件整体

       按照ELF格式文件从前到后的顺序查看(ELF文件头,program headers, sections, section headers):

 

[hadoop@sam1 test]$ readelf -h SimpleSection.o  ==> 查看ELF格式的目标文件 "File Header"

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:                              REL (Relocatable file)

  Machine:                           Intel 80386

  Version:                           0x1

  Entry point address:               0x0

  Start of program headers:          0 (bytes into file)

  Start of section headers:          272 (bytes into file)

  Flags:                             0x0

  Size of this header:               52 (bytes)

  Size of program headers:           0 (bytes)

  Number of program headers:         0

  Size of section headers:           40 (bytes)

  Number of section headers:         11

  Section header string table index: 8

 

[hadoop@sam1 test]$ readelf -S SimpleSection.o   ==> 查看ELF格式的目标文件 "Section Header Table"

There are 11 section headers, starting at offset 0x110:

 

Section Headers:

  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al

  [ 0]                   NULL            00000000 000000 000000 00      0   0  0

  [ 1] .text             PROGBITS        00000000 000034 000050 00  AX  0   0  4

  [ 2] .rel.text         REL             00000000 000420 000028 08      9   1  4

==>.rel.text:对于必须要重定位的代码段和数据段,都会有一个相应的重定位表——因为链接器处理目标文件时,须要对目标文件中“对绝对地址引用的位置”进行重定位。

  [ 3] .data             PROGBITS        00000000 000084 000008 00  WA  0   0  4

  [ 4] .bss              NOBITS          00000000 00008c 000004 00  WA  0   0  4

  [ 5] .rodata           PROGBITS        00000000 00008c 000004 00   A  0   0  1

  [ 6] .comment          PROGBITS        00000000 000090 00002d 01  MS  0   0  1

  [ 7] .note.GNU-stack   PROGBITS        00000000 0000bd 000000 00      0   0  1

  [ 8] .shstrtab         STRTAB          00000000 0000bd 000051 00      0   0  1

==> .shstrtab段表字符串表:保存段表中用到的字符串,如“段名”

  [ 9] .symtab           SYMTAB          00000000 0002c8 0000f0 10     10  10  4

==> .symtab符号表:目标文件中的“函数”和“变量”统称为符号(Symbol)

  [10] .strtab           STRTAB          00000000 0003b8 000066 00      0   0  1

==> .strtab字符串表:保存普通的字符串

Key to Flags:

  W (write), A (alloc), X (execute), M (merge), S (strings)

  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)

  O (extra OS processing required) o (OS specific), p (processor specific)

 

还可以反汇编SimpleSection.o中的.text段或者所有段:

objdump  -d  SImpleSection.o  ==>  --disassemble: Display the contents of executable sections (i.e. [.text])

objdump  -D  SImpleSection.o  ==>  --disassemble-all: Display the contents of all sections

 

二、查看ELF文件细节

 

[hadoop@sam1 test]$ readelf -s SimpleSection.o ==> 查看ELF格式目标文件的“符号表”(符号表也是目标文件中的一个段,即.symtab这个段) 

Symbol table '.symtab' contains 15 entries:

   Num:    Value  Size Type    Bind   Vis      Ndx Name

     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 

     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS SimpleSection.c

     2: 00000000     0 SECTION LOCAL  DEFAULT    1 

     3: 00000000     0 SECTION LOCAL  DEFAULT    3 

     4: 00000000     0 SECTION LOCAL  DEFAULT    4 

     5: 00000000     0 SECTION LOCAL  DEFAULT    5 

     6: 00000004     4 OBJECT  LOCAL  DEFAULT    3 static_var.1222

     7: 00000000     4 OBJECT  LOCAL  DEFAULT    4 static_var2.1223

     8: 00000000     0 SECTION LOCAL  DEFAULT    7 

     9: 00000000     0 SECTION LOCAL  DEFAULT    6 

    10: 00000000     4 OBJECT  GLOBAL DEFAULT    3 global_init_var

    11: 00000004     4 OBJECT  GLOBAL DEFAULT  COM global_uninit_var

    12: 00000000    27 FUNC    GLOBAL DEFAULT    1 func1

    13: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND printf

    14: 0000001b    53 FUNC    GLOBAL DEFAULT    1 main

 

 理解Ndx字段
    static_var.1222为3,表示在第3个section[.data]中;
    static_var2.1223为4,表示在第4个section[.bss]中;
    global_init_var为3,表示在第3个section中[.data];
    global_uninit_var为COM,表示这个全局变量未显式初始化,下面有详解;
    func1为1,表示在第1个section[.text]中;
    printf为UND,表示这个函数在外部模块定义,下面有详解
    main为1,表示在第1个section[.text]中;


Ndx为COM的含义
    gcc treats uninitialised globals which are not explicitly declared extern as "common" symbols (hence "COM").
    Multiple definitions of the same common symbol (across multiple object files) are merged together by the linker when creating the final executable, so that they all refer to the same storage. One of the object files may initialise it to a particular value (in which case it will end up in the data section); if no object files initialise it, is will end up in the BSS; if more than one object initialises it, you'll get a linker error.
    In summary, if you have, say, two definitions of int a:

    int a; in one object and int a; in another object is OK: both refer to the same a, initialised to 0
    int a; in one object and int a = 42; in another object is OK: both refer to the same a, initialised to 42
    int a = 23; in one object and int a= 42; in another object will give a link error.

    Do note that the use of multiple definitions of the same symbol across two objects is not technically allowed by standard C; but it is supported by many compilers, including gcc, as an extension. (It's listed under "Common extensions" - no pun intended - in the C99 spec.)

 

Ndx为UND的含义

#readelf -a SimpleSection.o| grep UND

         你会看到很多熟悉的库函数(i.e. printf),但是现在还是没有确定它的地址,用的UND,当你运行这个程序的时候,loader会把这个应用装到内存,同时确定这些动态连接的函数的地址,loader会到这个应用程序头的一个字段找到这个应用程序依赖的共享库。例如:

         在另一个文件a.c中显式定义int global_uninit_var=7; 并编译gcc -c a.c产生a.o

         然后将gcc  SimpleSection.o a.o -o b

# readelf -d b(显示Dynamic section)既可以看到类似

Dynamic section at offset 0x4c4 contains 20 entries:

         Tag                     Type                                      Name/Value

0x00000001              (NEEDED)                            Shared library: [libc.so.6]

...

      可知b依赖 libc.so.6,但是loader会到哪个路径去找这个文件呢?它会到环境变量LD_LIBRARY_PATH 去找这个文件,找到之后,把共享库装入内存(如果是第一次使用这个库),把这些库函数在内存的地址反填到应用程序中,这样这个应用就可以运行了。

 

分享到:
评论

相关推荐

    Linux编程从入门到精通

    第3章 /proc文件系统 158 第4章 把/proc用于输入 162 第5章 把设备文件用于输入 170 第6章 启动参数 182 第7章 系统调用 185 第8章 阻塞处理 190 第9章 替换printk 199 第10章 任务调度 202 第11章 中断处理程序 207...

    Linux编程白皮书

    第3章 /proc文件系统 158 第4章 把/proc用于输入 162 第5章 把设备文件用于输入 170 第6章 启动参数 182 第7章 系统调用 185 第8章 阻塞处理 190 第9章 替换printk 199 第10章 任务调度 202 第11章 中断处理程序 207...

    LINUX编程白皮书 (全集)

    第3章 /proc文件系统 158 第4章 把/proc用于输入 162 第5章 把设备文件用于输入 170 第6章 启动参数 182 第7章 系统调用 185 第8章 阻塞处理 190 第9章 替换printk 199 第10章 任务调度 202 第11章 中断处理程序 207...

    Linux编程资料

    第3章 /proc文件系统 158 第4章 把/proc用于输入 162 第5章 把设备文件用于输入 170 第6章 启动参数 182 第7章 系统调用 185 第8章 阻塞处理 190 第9章 替换printk 199 第10章 任务调度 202 第11章 中断处理程序 207...

    LINUX编程白皮书

    第3章 /proc文件系统 158 第4章 把/proc用于输入 162 第5章 把设备文件用于输入 170 第6章 启动参数 182 第7章 系统调用 185 第8章 阻塞处理 190 第9章 替换printk 199 第10章 任务调度 202 第11章 中断处理程序 207...

    linux编程白皮书

    第3章 /proc文件系统 158 第4章 把/proc用于输入 162 第5章 把设备文件用于输入 170 第6章 启动参数 182 第7章 系统调用 185 第8章 阻塞处理 190 第9章 替换printk 199 第10章 任务调度 202 第11章 中断处理程序 207...

    elf-loader:在您的ps4上通过TCP运行ps4sdk elf文件

    根据他们的构建系统和要求,您可以使用sdk的ps4-lib目标来编译第三方库。 或者,您将不得不更改其构建系统,以将其编译为PIC静态链接库。例子# Build as raw binary to bin/ and then convert to ldr.js in /local ...

    链接器和加载器.PDF(链接器和加载器 Beta 2)

    第3章 目标文件 3.1 目标文件中都有什么? 3.2 空目标文件格式:MS-DOS的COM文件 3.3 代码区段:UNIX的a.out文件 3.4 重定位:MS-DOS的EXE文件 3.5 符号和重定位 3.6 可重定位的a.out格式 3.7 UNIX的ELF格式 3.8 IBM...

    Nasm中文手册Nasm中文手册

     的目标文件格式,包括Linux和'NetBSD/FreeBSD','a.out','ELF','COFF',微软16  位的'OBJ'和'Win32'。它还可以输出纯二进制文件。它的语法设计得相当的简  洁易懂,和Intel语法相似但更简单。它支持'Pentium','P6'...

    入门学习Linux常用必会60个命令实例详解doc/txt

    在第三种格式中,会创建所有指定的目录及它们的主目录。长选项必须用的参数在使用短选项时也是必须的。 3.主要参数 --backup[=CONTROL]:为每个已存在的目的地文件进行备份。 -b:类似 --backup,但不接受...

    万能游戏资源提取软件

    三国群英传1~3的PAK文件(仅限于其中的SHP格式)(注:未经严格测试,替换前请一定要备份,以避免不必要的损失) 部分支持信长12和三国志11的bin文件的导入 注: 曹操传的meff不支持导入 查找和解包支持以下游戏: ...

    LINUX 20招

    显示文件的类型 用命令file可以使你知道某个文件究竟是ELF格式的可执行文件,还是shell script文件或是其他的什么格式,例如:#file startx <br> 3.用dd命令转换数据格式 你大概知道dd命令是用来拷贝...

    自己动手写操作系统(含源代码).part2

    第三,实践类的操作系统书籍还是太少了,以至于你要想看看别人是怎么做的,除了读以《操作系统:设计与实现》为代表的极少数书籍之外,就是一头扎进源代码中,而结果有时相当令人气馁。我自己也气馁过,所以我在第二...

    自己动手写操作系统(含源代码).part1

    第三,实践类的操作系统书籍还是太少了,以至于你要想看看别人是怎么做的,除了读以《操作系统:设计与实现》为代表的极少数书籍之外,就是一头扎进源代码中,而结果有时相当令人气馁。我自己也气馁过,所以我在第二...

    宋劲彬的嵌入式C语言一站式编程

    1. 多目标文件的链接 2. 定义和声明 2.1. extern和static关键字 2.2. 头文件 2.3. 定义和声明的详细规则 3. 静态库 4. 共享库 4.1. 编译、链接、运行 4.2. 动态链接的过程 4.3. 共享库的命名惯例 5. 虚拟内存管理 21...

    ELDK使用与开发手册

    这个设置假定你使用的是主机第一个串口(/dev/ttyS0),以115200这个波特率与目标板的串口连接。 然后你可以连接目标板了: $ kermit -c Connecting to /dev/ttyS0, speed 115200. The escape character is Ctrl-\ ...

Global site tag (gtag.js) - Google Analytics