深入理解计算机---链接( 一)

深入理解计算机—链接深入理解计算机系统(原书第3版)(美)布赖恩特(Bryant,R.E.) 等

#include<stdio.h>
int main()
{
	printf("hello ,world!\n");
}

hello.c —> 预处理器(cpp)—>编译器—>汇编器—>链接器—>可执行
在这里插入图片描述
gcc使用

GCC编译选项
-c编译、汇编指定的源文件,但是不进行链接
-s编译指定的源文件,但是不进行汇编
-E预处理指定的源文件,不进行编译
-o选项用来指定输出文件,[infile] -o [outfile],如不使用 -o 选项,默认的输出a.out
-I directory指定 include 包含文件的搜索目录
-g生成调试信息,该程序可以被调试器调试
-save-temps生成中间文件.i、.s和.o,分别表示为预处理输出、汇编语言输出和对象文件

编译器驱动程序

linking 将不同部分的代码和数据收集组合成一个单一文件过程。该文件被加载或被拷贝到存储器并执行。链接可执行于:编译时,加载时,或运行时。使大型软件的分离编译成为可能。
关于连接器:

  • 构造大型程序
  • unix,默认下,错误定义多个全局变量的程序将通过连接器。迷惑难以调试
  • 作用域规则全局和局部变量区别,静态属性的变量或函数意义
  • 理解其他系统概念。eg.加载和运行程序,虚拟存储器,分页和存储器映射
  • 理解开发共享库

1、编译器驱动程序

/*swap.c*/
extern int buf[];
int *bufp0=&buf[0];
int *bufp1;
void swap()
{
 int temp;
 bufp1=&buf[1];
 temp=*bufp0;
 *bufp0=*bufp1;
 *bufp1=temp;
}
/*main.c*/
void swap();
int buf[2]={1,2};
int main()
{
swap();
return 0;
}
gcc -o2 -g -o p main.c swap.c
//-v 查看步奏
cpp [other argumnets] main mian.i
cc1  main.i main.c -o2[other arguments] -o mian.s

在这里插入图片描述

2、静态链接

输入:一组可重定位目标文件和命令行参数 ( 代码和数据节组成,指令在一个节中,初始化的全局变量或未初始化的变量又在另一节中)
输出:完全链接可加载和运行的可执行目标文件

两个主要任务:

  • 符号解析 ,目标文件定义和引用符号。目的:将每个符号引用和一个符号定义联系起来
  • 重定位 ,编译器和汇编器生成从地址0开始的代码和数据节。连接器通过把每个符号定义与一个存储器位置联系起来,然后修改所有对这些符号的引用,使得它们指向这个存储器位置,从而定位这些节。
    —目标文件—纯粹是字节块的集合。包含代码和数据,指导链接器和加载器的数据结构。
    —链接器将这些块链接起来,确定链接块的运行时位置,并修改代码和数据块中的各种位置。
    —链接器对目标机器了解甚少,产生目标文件的编译器和汇编器已完成大部分工作。

3、目标文件

  • 可重定位目标文件,其形式可在编译时与其他可重定位目标文件合并起来,创建一个可执行目标文件
  • 可执行目标文件,其形式可以被直接拷贝到存储器并执行
  • 共享目标文件,一种特殊的可重定位目标文件,可在加载或运行时,被动态加载到存储器并链接
  • 编译器和汇编器生成可重定位目标文件(包含共享目标文件)。链接器生成可执行目标文件。

4、可重定位目标文件
c语言的ELF文件格式学习

/*elf.c*/
#include <stdio.h>
#include <stdlib.h>

int data[100] ={0};
int bss[100];

int main()
{
	int i=0;
	for(i=0; i<100; i++)
		bss[i] = i;
	printf("the bss[3]= %d\n", bss[3]);
	return 1;

}

objdump 使用

// readelf -h
//gcc elf.c //output a.out
//readelf -h a.out
ELF Header:
  //确认读入是否是elf头。7f默认,45,4c,46 表示
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00  elf
  Class:                             ELF64
  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:               0x400430
  Start of program headers:          64 (bytes into file)
  Start of section headers:          6672 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         31
  Section header string table index: 28
   
//objdump -d a.out >assembel.txt

0000000000400430 <_start>:
  400430:	31 ed                	xor    %ebp,%ebp
  400432:	49 89 d1             	mov    %rdx,%r9
  400435:	5e                   	pop    %rsi
  400436:	48 89 e2             	mov    %rsp,%rdx
  400439:	48 83 e4 f0          	and    $0xfffffffffffffff0,%rsp
  40043d:	50                   	push   %rax
  40043e:	54                   	push   %rsp
  40043f:	49 c7 c0 f0 05 40 00 	mov    $0x4005f0,%r8
  400446:	48 c7 c1 80 05 40 00 	mov    $0x400580,%rcx
  40044d:	48 c7 c7 26 05 40 00 	mov    $0x400526,%rdi
  400454:	e8 b7 ff ff ff       	callq  400410 <__libc_start_main@plt>
  400459:	f4                   	hlt    
  40045a:	66 0f 1f 44 00 00    	nopw   0x0(%rax,%rax,1)
 objdump -x a.out //objdump -x a.out 显示目标文件的所有头的信息,包括ELF文件头、
 //程序头(Program Header)和节头(Section Header)。除了这些头之外,
 //还包括动态节区(Dynamic Section)和符号表(Symbol Table)内的信息。例

a.out:     file format elf64-x86-64
a.out
architecture: i386:x86-64, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x0000000000400430

//程序头表内容,记录程序需拷贝到内存的内容。
Program Header:
   //PHDR 表示要保存的内容是程序头表。offset 表示该项内容保存的起始地址与程序头地址的偏移 
    PHDR off    0x0000000000000040 vaddr 0x0000000000400040 paddr 0x0000000000400040 align 2**3
         filesz 0x00000000000001f8 memsz 0x00000000000001f8 flags r-x
 //指定程序从已经从可执行映射到内存之后,必须调用解释器。?
  INTERP off    0x0000000000000238 vaddr 0x0000000000400238 paddr 0x0000000000400238 align 2**0
         filesz 0x000000000000001c memsz 0x000000000000001c flags r--
   //表示一个二进制文件映射到虚拟地址空间的段,其中保存了常量数据(如字符串),程序的目标代码等等
    LOAD off    0x0000000000000000 vaddr 0x0000000000400000 paddr 0x0000000000400000 align 2**21
         filesz 0x000000000000073c memsz 0x000000000000073c flags r-x
    LOAD off    0x0000000000000e10 vaddr 0x0000000000600e10 paddr 0x0000000000600e10 align 2**21
         filesz 0x0000000000000228 memsz 0x0000000000000580 flags rw-
//保存其他动态链接器(即INTERP中指定的解释器,第二个)
 DYNAMIC off    0x0000000000000e28 vaddr 0x0000000000600e28 paddr 0x0000000000600e28 align 2**3
         filesz 0x00000000000001d0 memsz 0x00000000000001d0 flags rw-
    NOTE off    0x0000000000000254 vaddr 0x0000000000400254 paddr 0x0000000000400254 align 2**2
         filesz 0x0000000000000044 memsz 0x0000000000000044 flags r--
EH_FRAME off    0x0000000000000614 vaddr 0x0000000000400614 paddr 0x0000000000400614 align 2**2
         filesz 0x0000000000000034 memsz 0x0000000000000034 flags r--
   STACK off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4
         filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-
   RELRO off    0x0000000000000e10 vaddr 0x0000000000600e10 paddr 0x0000000000600e10 align 2**0
         filesz 0x00000000000001f0 memsz 0x00000000000001f0 flags r--

Dynamic Section:
  NEEDED               libc.so.6
  INIT                 0x00000000004003c8
  FINI                 0x00000000004005f4
  INIT_ARRAY           0x0000000000600e10
  //......................
  //......

Dynamic Section:
  NEEDED               libc.so.6
  INIT                 0x00000000004003c8
  FINI                 0x00000000004005f4
  INIT_ARRAY           0x0000000000600e10
  INIT_ARRAYSZ         0x0000000000000008
  FINI_ARRAY           0x0000000000600e18
  FINI_ARRAYSZ         0x0000000000000008
  GNU_HASH             0x0000000000400298
  STRTAB               0x0000000000400318
  SYMTAB               0x00000000004002b8
  STRSZ                0x000000000000003f
  SYMENT               0x0000000000000018
  DEBUG                0x0000000000000000
  PLTGOT               0x0000000000601000
  PLTRELSZ             0x0000000000000030
  PLTREL               0x0000000000000007
  JMPREL               0x0000000000400398
  RELA                 0x0000000000400380
  RELASZ               0x0000000000000018
  RELAENT              0x0000000000000018
  VERNEED              0x0000000000400360
  VERNEEDNUM           0x0000000000000001
  VERSYM               0x0000000000400358

Version References:
  required from libc.so.6:
    0x09691a75 0x00 02 GLIBC_2.2.5



//text,data,bss三个段。
//其中,text表示的是程序的代码段。

//后面的data和bss段。.bss段在文件中是不占大小的。因为,bss段代表的是未初始化的全局变量。在C里面,未初始化的全局变量会被初始化为0
Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .interp       0000001c  0000000000400238  0000000000400238  00000238  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  0000000000400254  0000000000400254  00000254  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  0000000000400274  0000000000400274  00000274  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .gnu.hash     0000001c  0000000000400298  0000000000400298  00000298  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .dynsym       00000060  00000000004002b8  00000000004002b8  000002b8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynstr       0000003f  0000000000400318  0000000000400318  00000318  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .gnu.version  00000008  0000000000400358  0000000000400358  00000358  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version_r 00000020  0000000000400360  0000000000400360  00000360  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .rela.dyn     00000018  0000000000400380  0000000000400380  00000380  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rela.plt     00000030  0000000000400398  0000000000400398  00000398  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .init         0000001a  00000000004003c8  00000000004003c8  000003c8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 11 .plt          00000030  00000000004003f0  00000000004003f0  000003f0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .plt.got      00000008  0000000000400420  0000000000400420  00000420  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .text         000001c2  0000000000400430  0000000000400430  00000430  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .fini         00000009  00000000004005f4  00000000004005f4  000005f4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 15 .rodata       00000014  0000000000400600  0000000000400600  00000600  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .eh_frame_hdr 00000034  0000000000400614  0000000000400614  00000614  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .eh_frame     000000f4  0000000000400648  0000000000400648  00000648  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 18 .init_array   00000008  0000000000600e10  0000000000600e10  00000e10  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 19 .fini_array   00000008  0000000000600e18  0000000000600e18  00000e18  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 20 .jcr          00000008  0000000000600e20  0000000000600e20  00000e20  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 21 .dynamic      000001d0  0000000000600e28  0000000000600e28  00000e28  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 22 .got          00000008  0000000000600ff8  0000000000600ff8  00000ff8  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 23 .got.plt      00000028  0000000000601000  0000000000601000  00001000  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 24 .data         00000010  0000000000601028  0000000000601028  00001028  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 25 .bss          00000350  0000000000601040  0000000000601040  00001038  2**5
                  ALLOC
 26 .comment      00000035  0000000000000000  0000000000000000  00001038  2**0
                  CONTENTS, READONLY
SYMBOL TABLE:
0000000000400238 l    d  .interp	0000000000000000              .interp
0000000000400254 l    d  .note.ABI-tag	000000000
ELF头 (16字节序列:描述字的大小和生成该文件的系统的字节顺序)
.text —(已编译的机器代码)
.rodata — (只读数据)
.data — (已初始化的全局C变量.局部C变量在运行时被保存在栈中,不出现在.data,也不出现在.bss中)
.bss —未初始化的全局C变量
.symtab — 一个符号表存放在程序中被定义和引用的函数和全局变量的信息,注意区别与编译选项-g。.symtab符号表不包含局部变量的表目
.rel.text — 当链接器把这个目标文件和其他文件结合时,该节中许多位置都需要修改。
.rel.data — 被模块定义或引用的任何全局变量信息。一般而言,任何已被初始化全局变量的初始值是全局变量或者外部定义函数的地址都需要修改
.debug 调试符号表 — 其有些表目是程序中定义的局部变量和类型定义,
.line 原始C源程序中的行号和.text中机器指令之间的映射。只有以 -g 选项调用编译驱动程序时,才会得到这张表
.strtab 一个字符串表 ,.symtab 和.debug节中的符号表
节头部表

5、符号和符号表
每个可重定位目标模块m,都有一个符号表,包含m所定义和引用的符号的信息。在链接器上下文,有三种不同的符号;

  • 由m定义并能被其他模块引用的全局符号。 全局链接器符号对应于非静态的C函数以及被定义为不带C的static属性的全局变量
  • 由其他模块定义并被模块m引用的全局符号。这些符号称为外部符号external,对应于定义在其他模块中的C函数和变量
  • 只被模块m定义和引用的本地符号。有的本地链接器符号对应与带static属性的C函数和全局变量。在模块m中任何地方可见,但不能被其他模块引用。
    文件中对应于模块m的节和相应的源文件的名字也能获得本地符号。
    注意,本地链接器符号和本地程序变量的不同是很重要的。*.symtab中的符号表不包含对应与本地非静态程序变量的任何符号。这些符号在运行时在栈中被管理。
    定义为带有c static 属性的本地过程变量是不在栈中管理的。编译器在.data和.bss中为每个定义分配空间,并在符号表中创建一个唯一名字的本地连接器符号。
int f()
{
	static int x=0;
	return x;
}
int g()
{
	static int x =1;
	return x;
}
// 在这种情况下,编译器在.bss中为两个整数分配空间,并引用(export)
//两个唯一的本地连接器符号给汇编器。如:x.1g表示f中的定义,x.2表示函数g中的定义。

.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值