GCC 预处理 编译 汇编 链接全过程及其含义 程序的开始不是main函数
来源:互联网 发布:日上免税店 mac 编辑:程序博客网 时间:2024/06/08 05:11
下面对c语言程序的实现过程做简单的总结:
首先咱写一个简单的程序 test.c test.h main.c
tset.h:
#ifndef _TEST_H_ #define _TEST_H_ int add(int,int); #endiftest.c
#include"test.h" int add(int a,int b){ return a+b; }main.c
#include<stdio.h> #include"test.h" int main(){ int a=6,b=4; printf("%d+%d=%d\n",a,b,add(a,b)); return 0; }
首先对test.c main.c 进行预处理
采用gcc -E test.c -o test.i
gcc -E main.c -o main.i
将程序中用到的printf函数及头文件翻译成c语言(-o的意思是将翻译后的文件命名为test.i/main.i)
再使用gcc -S test.i -o test.s
gcc -S main. -o main.s
把翻译后的文件翻译成汇编文件(汇编语言),这个过程叫做编译
在使用gcc -c main.s
gcc -c test.s
把编译后的汇编文件(汇编语言)汇编成机器语言(计算机识别的语言)会生成 main.o test.o文件
以上是从你编写的程序到计算机能识别的语言的一个过程,只有从汇编语言到机器语言的过程才叫汇编。
下面演示连接的过程:
先介绍一个命令:nm(被用于显示二进制目标文件的符号表) 什么事符号表:表里的内容包括函数的名字 全局变量的名字 静态局部变量的名字等
先运行 nm main.o 结果如下:
U add0000000000000000 T main U printf
nm test.o 结果如下
0000000000000000 T addT的意思是 该函数已在文件中被定义,有这个函数的二进制代码
U的意思是 该函数在文件中被调用,没有这个函数的二进制代码
可以看出在main.o中只有main函数的二进制代码,add 函数和printf函数都只是被调用
在add函数中只有add函数的二进制代码
下面运行gcc main.o test.o
会生成a.out 文件
我们在nm a.out 结果如下:
0000000000600e50 d _DYNAMIC0000000000600fe8 d _GLOBAL_OFFSET_TABLE_0000000000400638 R _IO_stdin_used w _Jv_RegisterClasses0000000000600e30 d __CTOR_END__0000000000600e28 d __CTOR_LIST__0000000000600e40 D __DTOR_END__0000000000600e38 d __DTOR_LIST__0000000000400740 r __FRAME_END__0000000000600e48 d __JCR_END__0000000000600e48 d __JCR_LIST__0000000000601020 A __bss_start0000000000601010 D __data_start00000000004005f0 t __do_global_ctors_aux0000000000400460 t __do_global_dtors_aux0000000000601018 D __dso_handle w __gmon_start__0000000000600e24 d __init_array_end0000000000600e24 d __init_array_start00000000004005e0 T __libc_csu_fini0000000000400550 T __libc_csu_init U __libc_start_main@@GLIBC_2.2.50000000000601020 A _edata0000000000601030 A _end0000000000400628 T _fini00000000004003c8 T _init0000000000400410 T _start000000000040053c T add000000000040043c t call_gmon_start0000000000601020 b completed.65310000000000601010 W data_start0000000000601028 b dtor_idx.653300000000004004d0 t frame_dummy00000000004004f4 T main U printf@@GLIBC_2.2.5红色背景的部分是我需要观察的部分:
可以看出 在a.out文件中add 函数 main 函数为T ,表示在阿。a.out中有两个函数的二进制代码了。这个过程叫做静态连接!
printf 前面的U表示:printf在代码执行时,代码装进内存的时候会再次进行连接,这个连接过程在代码执行的时候完成。这个过程叫做动态连接。
根据咱上面说的 我来推一下程序的开始是不是main函数!
首先使用 gcc main.o -v(加-v 显示编译或连接整个过程的信息)
部分结果如下:
gcc 版本 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.6/:/usr/lib/gcc/x86_64-linux-gnu/4.6/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.6/:/usr/lib/gcc/x86_64-linux-gnu/LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.6/:/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../:/lib/:/usr/lib/COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64' /usr/lib/gcc/x86_64-linux-gnu/4.6/collect2 --sysroot=/ --build-id --no-add-needed --as-needed --eh-frame-hdr -m elf_x86_64 --hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -z relro /usr/lib/gcc/x86_64-linux-gnu/ 4.6/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crti.o /usr/li b/gcc/x86_64-linux-gnu/4.6/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.6/. ./../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../ lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../.. main.o -lgcc --a s-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.6/ crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crtn.omain.o: In function `main':main.c:(.text+0x21): undefined reference to `add'collect2: ld 返回 1
我们在nm /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crti.o (只要是.o结尾的文件就可以)
得到结果如下:
0000000000000000 R _IO_stdin_used0000000000000000 D __data_start U __libc_csu_fini U __libc_csu_init U __libc_start_main0000000000000000 T _start0000000000000000 W data_start U maine可以看出 main函数前是U main函数被调用了!!
而 _start 前是T!
在我们nm a.out 时第一个红色背景也是 T _start
所以我认为main函数仅仅是一个框架!程序的开始因该是 _start函数
最后说一个学到的隐藏main.c 的方法:
alias函数可以给命令起别名 类似于 typedef
输入 alisa haha="gcc main.c" haha为别名
然后 haha tset.c 就可以生成a.out文件了。
最后谢谢查阅!有问题欢迎指出,咱们共同探讨!
- GCC 预处理 编译 汇编 链接全过程及其含义 程序的开始不是main函数
- gcc 从语言编译全过程 预处理---->编译---->汇编----->链接
- gcc 从语言编译全过程 预处理---->编译---->汇编----->链接
- 程序的预处理、编译、汇编和链接
- 预处理,编译,汇编,链接程序的区别
- GCC编译的背后( 预处理和编译 汇编和链接 )
- GCC编译的背后( 预处理和编译 汇编和链接)
- GCC编译的背后( 预处理和编译 汇编和链接 )
- GCC编译的背后( 预处理和编译 汇编和链接 )
- GCC编译的背后( 预处理和编译 汇编和链接 )
- gcc编译的背后(预处理、编译、汇编和链接) 一
- GCC编译的背后( 预处理和编译 汇编和链接 )
- gcc 编译的四大过程(预处理-编译-汇编-链接 )
- GCC编译的四个过程 预处理 编译 汇编 链接
- GCC编译的背后( 预处理和编译 汇编和链接 )
- GCC编译的背后( 预处理和编译 汇编和链接 )
- GCC编译的背后( 预处理和编译 汇编和链接 )
- GCC编译的背后( 预处理和编译 汇编和链接 )
- 成分分析(Principal components analysis)-最大方差解释
- K&R学习1
- 几个编程问题非递归解决
- 扩增子分析神器USEARCH简介
- C语言----数据类型
- GCC 预处理 编译 汇编 链接全过程及其含义 程序的开始不是main函数
- Git--安装
- 深入解析深拷贝和浅拷贝
- Ubuntu 16.04虚拟机安装 桌面大小自适应
- 认识浏览器
- WPS 快捷键
- 两个高效的cp 命令用法!
- 【SDOI2008】Sandy的卡片 DP
- mysql 主键 外键