码迷,mamicode.com
首页 > 其他好文 > 详细

链接(一)

时间:2019-09-26 16:10:24      阅读:119      评论:0      收藏:0      [点我收藏+]

标签:开始   block   compute   nbsp   ber   table   system   input   显示   

安装工具

我的机器环境是:macOS Mojave 10.14.4 18E226 x86_64,开始之前,得在机器上面安装一些工具:

  • gcc
  • binutils (readelf,objdump)

因为我在自己的机器上面安装了 brew这个包管理工具,以及zsh这个 Shell,所以我就通过brew install gcc binutils就安装好了gccobjdumpreadelf这3个命令,值得注意的是,由于macOS上面也提供了和binutils相同功能的工具,我们就需要手动将这两个命令的路径添加到环境变量里面:

echo ‘export PATH="/usr/local/opt/binutils/bin:$PATH"‘ >> ~/.zshrc #使用bash的话,就添加到.bashrc里面 exec $SHELL #刷新下环境变量 

如果需要让编译器找到这些命令,还需要额外添加:

export LDFLAGS="-L/usr/local/opt/binutils/lib" export CPPFLAGS="-I/usr/local/opt/binutils/include" 

因为macOS并没有使用elf作为可执行文件的格式,所以我得在linux下面编译文件,以前学jsp的使用写了个fedora的镜像构建脚本,打开了ssh,这样编译好的文件就可以通过scp来传输到宿主机器。不过为了方便我还是挂载了一个目录到fedora。

docker pull ourfor/tomcat docker run --privileged --name asm -d \ -v /sys/fs/cgroup:/sys/fs/cgroup:ro \ -v $PWD:/root:rw \ -h docker.server -p 4040:8080 -p 2020:22 \ -p 9906:3306 \ -t ourfor/tomcat 

创建一个名为asm的容器,同时将当前目录挂载到/root目录

技术图片

fedora上面的包管理工具有yumdnf,为了方便,我还是安装下gccbinutils以及vim

dnf install gcc binutils vim -y 

在fedora里面编译好,再打开一个Terminal,到挂载的共享目录就可以查看编译好的文件

技术图片

这个结果和fedora里面用readelf看到的结果是一样的:

ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 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: 0x401020 Start of program headers: 64 (bytes into file) Start of section headers: 16360 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 11 Size of section headers: 64 (bytes) Number of section headers: 28 Section header string table index: 27 

要用到的工具我们都安装完了。

链接

比如我们在Shell下面输入下面的命令来编译main.csum.c这两个文件

gcc -Og -o prog main.c sum.c 

它实际上经过了下面??几个过程:

 
main.o
 
sum.o
链接
main.c
翻译器
(cpp,ccl,as)
链接器
(ld)
sum.c
翻译器
(cpp,ccl,as)
prog
完全链接的可执行目标文件

sum.c源码:

int sum(int *a,int n){ int i, s = 0; for(i=0;i<n;i++){ s += a[i]; } return s; } 

main.c源码:

int sum(int *a,int n); int array[2] = {1,2}; int main(){ int val = sum(array,2); return val; } 

接下来使用gcc编译这两个文件为可重定位文件:

gcc -c main.c sum.c 

得到main.osum.o这两个可重定位文件,使用 -S 可以得到汇编文件(-masm=intel可以得到intel格式汇编,见118页),比如下面的main.c得到的汇编代码:

 .section __TEXT,__text,regular,pure_instructions  .build_version macos, 10, 14 sdk_version 10, 14  .intel_syntax noprefix  .globl _main ## -- Begin function main  .p2align 4, 0x90 _main: ## @main  .cfi_startproc ## %bb.0: push rbp  .cfi_def_cfa_offset 16  .cfi_offset rbp, -16 mov rbp, rsp  .cfi_def_cfa_register rbp sub rsp, 16 mov dword ptr [rbp - 4], 0 mov al, 0 call _swap xor eax, eax add rsp, 16 pop rbp ret  .cfi_endproc ## -- End function  .section __DATA,__data  .globl _buf ## @buf  .p2align 2 _buf:  .long 1 ## 0x1  .long 2 ## 0x2  .subsections_via_symbols 

目标文件

目标文件有三种格式:

  • 可重定位目标文件。 包含二进制数据,其形式可以在编译时与其他可重定位目标文件合并起来,创建一个可执行的目标文件
  • 可执行目标文件。包含二进制数据,其形式可以被直接复制到内存并执行
  • 共享目标文件。一种特殊类型的可重定位目标文件,可以在加载或者运行时被动态的加载进内存并链接

以前在编译httpd的时候就了解了这三种文件,比如Apache的模块就是共享目标文件,Apache连接tomcat的mod_jk.so就是这种类型的,可执行文件就是编译好可以直接运行的文件,在使用make命令编译的时候,如果遇到库丢失,安装好依赖后,不会再重新编译,而是在编译好的.o文件的基础上面继续编译其它没有编译的源文件。

可重定位目标文件

一个典型的ELF可重定位目标文件的格式如下表所示。ELF头以一个16字节的序列开始,这个序列描述了生成该文件的系统的字的大小和字节顺序。

ELF头
.text
.rodata
.data
.bss
.symtab
.rel.text
.rel.data
.debug
.line
.strtab
描述目标文件的节 节头部表

Computer Systems A Programmer‘s Perspective Third Edition这本书的练习题7.1里面有这样两个源文件:

m.c

void swap(); int buf[2] = {1,2}; int main(){ swap(); return 0; } 

swap.c

extern int buf[]; int *bufp0 = &buf[0]; int *bufp1; void swap(){ int temp; bufp1 = &buf[1]; temp = *bufp0; *bufp0 = *bufp1; *bufp1 = temp; } 

使用命令:gcc -c m.c swap.c得到两个可重定位的目标文件,分别是m.oswap.o,接下来用readelf来查看m.o的符号表:

Symbol table ‘.symtab‘ contains 11 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS m.c 2: 0000000000000000 0 SECTION LOCAL DEFAULT 1 3: 0000000000000000 0 SECTION LOCAL DEFAULT 3 4: 0000000000000000 0 SECTION LOCAL DEFAULT 4 5: 0000000000000000 0 SECTION LOCAL DEFAULT 6 6: 0000000000000000 0 SECTION LOCAL DEFAULT 7 7: 0000000000000000 0 SECTION LOCAL DEFAULT 5 8: 0000000000000000 8 OBJECT GLOBAL DEFAULT 3 buf 9: 0000000000000000 21 FUNC GLOBAL DEFAULT 1 main 10: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND swap 

因为swapmain是全局函数,由于m.c调用了swap.c里面定义的函数,还没有将这两个文件编译成一个可执行文件,所以在这里swap显示UND(表示未定义的符号),保存在.data这一节里面,buf是在 m.c里面初始化的全局变量,也是保存在.data里面.


同样的我们来查看下swap.o里面的信息:

Symbol table ‘.symtab‘ contains 12 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS swap.c 2: 0000000000000000 0 SECTION LOCAL DEFAULT 1 3: 0000000000000000 0 SECTION LOCAL DEFAULT 3 4: 0000000000000000 0 SECTION LOCAL DEFAULT 5 5: 0000000000000000 0 SECTION LOCAL DEFAULT 7 6: 0000000000000000 0 SECTION LOCAL DEFAULT 8 7: 0000000000000000 0 SECTION LOCAL DEFAULT 6 8: 0000000000000000 8 OBJECT GLOBAL DEFAULT 3 bufp0 9: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND buf 10: 0000000000000008 8 OBJECT GLOBAL DEFAULT COM bufp1 11: 0000000000000000 60 FUNC GLOBAL DEFAULT 1 swap 

在这里,我们可以看到bufp1Ndx显示为COM(表示未初始化的全局变量),buf是在m.c里面定义的全局变量,在swap.c里面声明时用关键字extern指出这是一个外部符号,所以它Ndx这一项显示UND

将这两个重定位文件编译成一个可执行的目标文件gcc -o prog m.o swap.o,在使用readelf查看prog的符号表:

.... 72: 0000000000404020 8 OBJECT GLOBAL DEFAULT  21 bufp0 73: 0000000000000000 0 NOTYPE WEAK  DEFAULT  UND __gmon_start__ 74: 0000000000402008 0 OBJECT GLOBAL HIDDEN 13 __dso_handle 75: 0000000000402000 4 OBJECT GLOBAL DEFAULT  13 _IO_stdin_used 76: 0000000000401160 101 FUNC GLOBAL DEFAULT  11 __libc_csu_init 77: 0000000000404040 0 NOTYPE GLOBAL DEFAULT  22 _end 78: 0000000000401050 5 FUNC GLOBAL HIDDEN 11 _dl_relocate_static_pie 79: 0000000000401020 47 FUNC GLOBAL DEFAULT  11 _start 80: 0000000000404028 8 OBJECT GLOBAL DEFAULT  21 buf 81: 0000000000404030 0 NOTYPE GLOBAL DEFAULT  22 __bss_start 82: 0000000000401142 21 FUNC GLOBAL DEFAULT  11 main 83: 0000000000404030 0 OBJECT GLOBAL HIDDEN 21 __TMC_END__ 84: 0000000000401106 60 FUNC GLOBAL DEFAULT  11 swap 85: 0000000000401000 0 FUNC GLOBAL HIDDEN 10 _init 86: 0000000000404038 8 OBJECT GLOBAL DEFAULT  22 bufp1 

可以看到这里面bufswap都可以正确显示.

符号解析

  1. 不允许有多个同名的强符号.
  2. 如果有一个强符号和多个弱符号同名,那么选择弱符号.
  3. 如果有多个弱符号同名,那么从这些弱符号中任意选择一个.
技术图片

链接(一)

标签:开始   block   compute   nbsp   ber   table   system   input   显示   

原文地址:https://www.cnblogs.com/ourfor/p/11592337.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!