gcc 编译 汇编 链接
要想研究使用 gcc, gcc-multilib 这个包是一定要安装的, 它允许通过 -m32 和 -m64 选项来选择生成 32 位或者 64 的 ELF 文件.
我们知道程序的默认起点是 _start, 该函数做了一些未知/初始化的工作, 然后调用 main 函数, 如果 main 函数返回, 则由 _start 函数销毁进程.
我们可以使用 -e<symbol> 来重新设置该入口点.
观察上面的程序, 无论在32位下还是64位下均出现错误, 是什么原因?
没错, 就是因为没有销毁进程, 导致 ret(q) 指令(x86-64)继续执行, 该指令从调用者栈帧中取指令地址, 导致 main 函数返回到未知的内存地址取指令, 可能这个内存地址无法访问, 当然, 即使成功取址, 也极可能是无效的指令, 导致崩溃. 这件事告诉我们: 有些函数是不能返回的(实际上是计算机指令必须严格有序地按人类设计执行, 差之毫厘, 谬之千里).
编译
cpp 预处理, gcc -S 生成特定体系结构的汇编代码, 这个过程称为编译.
参数主要配置头文件搜索路径, 选择体系结构(-m32 -m64), 生成位置无关代码(-fPIC, 共享库必须要使用位置无关的目标文件, 而不是可重定位目标文件, 共享库不能重定位, 因为不知道, 也不能假设共享库的加载位置.)
汇编
as. 识别汇编代码, 生成可重定位或位置无关的目标文件, 什么区别? 毕竟复杂, 一言难弊.
链接
组织各目标文件, 生成可执行文件或共享库, 修改需要重定位的指令, 使其地址从0x0变为对应的线性地址, 共享库基本使用偏移寻址, 对外部符号的访问则采取 PLT 技术, 该技术使用成为 GOT 的偏移表, GOT 是运行时数据.
运行
现在我们有必要来研究一下什么是 "位置无关目标文件" 了
现在我们正常编译为 a.s, 查看之:
加上 -fPIC 选项, 编译为 b.s, 查看之:
使用 diff 查看差异:
编译后的目标文件具有显著差异:
请看一下汇编代码:
可见, 涉及地址的指令均需要链接器"细细商榷", 我们再看可执行文件:
想也知道, 直接寻址比偏移寻址快些, 这项技术主要用于共享库.
盗了一张图, 惊天大秘密:
图片来源:
https://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/
本文皆小儿之见, 文思迂腐, 切莫计较.
gcc 编译 汇编 链接的更多相关文章
- GCC编译和链接过程
GCC(GNU Compiler Collection,GNU编译器套件),是由 GNU 开发的编程语言编译器.它是以GPL许可证所发行的自由软件,也是 GNU计划的关键部分.GCC原本作为GNU操作 ...
- Linux | GCC如何实现代码编译&&汇编&&链接过程
正文: 每次我们程序员所写的 代码 是给程序员看的呢?还是给电脑看的?其实我们所写的代码只是我们程序员之间交流的一样特殊语言,电脑是看不懂的.那么我们如何实现人机交流呢?这就不得不请出我们我们今天 ...
- GCC编译和链接多个文件(包括源文件、目标文件、汇编文件等)
编译多个源代码文件会生成多个目标文件,每个目标文件都包含一个源文件的机器码和相关数据的符号表.除非使用-c选项指示 GCC 只编译不链接,否则 GCC 会使用临时文件作为目标文件输出: $ gcc - ...
- C语言预处理 编译 汇编 链接四个阶段
c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接. 编译过程 编译过程又可以分成两个阶段:编译和会汇编. 编译 编译是读取源程序(字符流),对之进行词法和语法的分析,将高 ...
- C/C++程序编译流程(预处理->编译->汇编->链接)
程序的基本流程如图: 1. 预处理 预处理相当于根据预处理指令组装新的C/C++程序.经过预处理,会产生一个没有宏定义,没有条件编译指令,没有特殊符号的输出文件,这个文件的含义同原本的文件无异,只是内 ...
- gcc编译动态和静态链接库
我们通常把一些公用函数制作成函数库,供其它程序使用.函数库分为静态库和动态库两种.静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库.动态库在程序编译时并不会被连接到目标代码中,而是 ...
- gcc 编译和链接
1.现在对两个文件生成可执行文件 //thanks.c #include <stdio.h> int main(void) { printf("Hello World\n&quo ...
- gcc编译 汇编 选项
gcc生成main.out的步骤分解:<blockquote>main.c-----(-S 编译)-------->main.s-------(-c 汇编)------->ma ...
- GCC编译动态和静态链接库例子
我们通常把一些公用函数制作成函数库,供其它程序使用.函数库分为静态库和动态库两种.静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库.动态库在程序编译时并不会被连接到目标代码中,而是 ...
随机推荐
- 【LOJ#6066】「2017 山东一轮集训 Day3」第二题(哈希,二分)
[LOJ#6066]「2017 山东一轮集训 Day3」第二题(哈希,二分) 题面 LOJ 题解 要哈希是很显然的,那么就考虑哈希什么... 要找一个东西可以表示一棵树,所以我们找到了括号序列. 那么 ...
- Codeforces | CF1029C 【Maximal Intersection】
论Div3出这样巨水的送分题竟然还没多少人AC(虽说当时我也没A...其实我A了D...逃) 这个题其实一点都不麻烦,排序都可以免掉(如果用\(priority \_ queue\)的话) 先考虑不删 ...
- centos7破解安装fisheye和Crucible
背景介绍: Atlassian的东西相信大家都不陌生,JIRA.Confluence……虽然说这些产品都要收费,也可以申请试用: FishEye 可以方便地查看代码,而Crucible 则是进行Cod ...
- Typescript学习笔记(二)枚举
跟随handbook的脚步,详细介绍一下枚举. enum Direction { Up = 1, Down, Left, Right } 一个枚举类型可以包含零个或多个枚举成员,每个枚举成员可以是一个 ...
- C# Winform多窗体&&构造函数传值
一.多窗体:三种打开窗体的状态: 最最基础的弹窗: //写在按钮的点击事件内: //实例需要弹出的窗口的类: Form2 f2 = new Form2(); f2.Show(); 1.弹窗窗口: // ...
- [luogu4626][一道水题2]
题目链接 思路 这个首先想到质因数分解.然后发现只要对于每个质数将ans乘以这个质数在从1到n中出现过的最高指数次就行了. 这个\(10^8\)令人发指.一直tle,最后发现吸口氧才能过.. 代码 # ...
- RabbitMQ入门-队列
先建工程 下一步,输入坐标 下一步,输入工程名 先看一下最终目录 修改pom文件 <?xml version="1.0" encoding="UTF-8" ...
- Luogu P2613 【模板】有理数取余
题目链接 \(Click\) \(Here\) 真心没啥东西,只要能\(Get\)到在数字输入的时候按位取模,以及除数也可以直接取模就可以了.(把每个数看做乘法原理和加法原理构造起来的即可.) #in ...
- Qt ------ QDir 路径
QDir::currentPath() 获取当前路径 QDir::toNativeSeparators 把windows下的路径转换为Qt可以识别的路径,如"C:/Users/Adminis ...
- 剑指Offer_编程题_18
题目描述 操作给定的二叉树,将其变换为源二叉树的镜像. 输入描述: 二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树 8 / \ 10 6 / \ / \ ...