制作一个RISC-V的操作系统三-编译与链接
文章目录
- GCC
- GCC简介
- GCC的命令格式
- gcc -E
- gcc -c
- gcc -S
- gcc -g
- gcc -v
- GCC的主要执行步骤
- GCC涉及的文件类型
- 针对多个源文件的处理
- ELF
- ELF介绍
- ELF文件格式
- ELF文件处理相关工具:Binutils(binary utility)
- readlelf -h
- readelf -S或readelf -SW(加W显示变宽)
- objdump -S
- 练习 3-1
- 练习 3-2
GCC
GCC简介
GCC的命令格式
预处理: 把#define #include 这些#开头的宏语言转为标准的C语言
编译:C语言变成机器指令
链接:把编译后的指令文件与其他库链接到一块
调试需要加入调试信息
建议实战一下,观察区别
如该程序
gcc -E
当预处理该文件时并且将输出结果输出到E文件
打开E文件
可以看到代码非常多,但最后的main函数没有变化。上面的代码就是#include<stdio.h>转换为C语言的结果
gcc -c
生成的可执行文件,但还没有链接
gcc -S
打开S文件查看,为汇编语言
gcc -g
gcc -v
可以看到一大串相关信息
GCC的主要执行步骤
Linux mv(英文全拼:move file)命令用来为文件或目录改名、或将文件或目录移入其它位置。
cc1:预处理和编译
as:生成O文件 机器指令
collect中有ld 链接
将各种标准库和O文件链接在一起
GCC涉及的文件类型
小写s:不包含#开头的代码
大写S:还包含#开头的代码
可执行文件默认为a.out
针对多个源文件的处理
ELF
ELF介绍
可重定位文件:链接才能把位置定下来
核心转储文件:程序崩溃时相关信息
ELF文件格式
二进制
ELF Header: ELF文件的基本信息 (如运行在哪种体系架构 版本号)
.text: 程序的指令
.init:程序初始化的指令
4K字节对齐
Programe Header Table:运行时用到,将哪些节放到一起合成段,段放哪里
Section Header Table:节的一些信息,定位之类的
ELF文件处理相关工具:Binutils(binary utility)
ar=tar:生成静态库要用到
readlelf -h
查看文件头 ELF-header
-
Magic:魔术 没啥大用,就是给ELF做一个特殊的标志,和别的东西区分开来
-
Class:文件类型 64位还是32位
readelf -S或readelf -SW(加W显示变宽)
查看Section Header Table
PROGBITS:可执行执行的意思
RELA:可重定位的
objdump -S
-S是将汇编显示源代码部分
此时反汇编结果中没有源码部分显示
当编译时加上-g后 (生成调试信息)再反汇编发现源码和汇编指令
练习 3-1
- 使⽤ gcc 编译代码并使⽤ binutils ⼯具对⽣成的⽬标文件和可执⾏文件(ELF 格式)进⾏分析。具体要求如下:
- 编写⼀个简单的打印 “hello world!” 的程序源文件:hello.c
对源文件进⾏本地编译,⽣成针对⽀持 x86_64 指令集架构处理器的⽬标文件 hello.o。 - 查看 hello.o 的文件的文件头信息。
- 查看 hello.o 的 Section header table。
- 对 hello.o 反汇编,并查看 hello.c 的 C 程序源码和机器指令的对应关系。
练习 3-2
如下例⼦ C 语⾔代码
#include <stdio.h>
int global_init = 0x11111111;
const int global_const = 0x22222222;
void main()
{
static int static_var = 0x33333333;
static int static_var_uninit;
int auto_var = 0x44444444;
printf("hello world!\n");
return;
}
- 请问编译为可执行文件后,global_init, global_const, static_var, static_var_uninit, auto_var 这些变量分别存放在那些 section ⾥
- “hello world!\n” 这个字符串⼜在哪⾥?并尝试⽤⼯具查看并验证你的猜想
auto_var变量 和"hello world!\n" 这个字符串在栈中,需要程序运行时才会有
可以根据地址来判断从属于哪个节