计算机漫游
字数
1573 字
阅读时间
7 分钟
编译系统
查看文件内容的工具
- hexdump
bash
hexdump filename # 默认格式显示
hexdump -C filename # 更易读的格式,同时显示十六进制和ASCII- xxd
bash
xxd filename # 标准十六进制显示
xxd -b filename # 以二进制方式显示我们以一个大家最最最熟悉的c语言程序来展示
c
#include<stdio.h>
int main(){
printf("hello world\n");
return 0;
}执行 hexdump -C hello.c
bash
00000000 23 69 6e 63 6c 75 64 65 3c 73 74 64 69 6f 2e 68 |#include<stdio.h|
00000010 3e 0a 69 6e 74 20 6d 61 69 6e 28 29 7b 0a 20 20 |>.int main(){. |
00000020 20 20 70 72 69 6e 74 66 28 22 68 65 6c 6c 6f 20 | printf("hello |
00000030 77 6f 72 6c 64 5c 6e 22 29 3b 0a 20 20 20 20 72 |world\n");. r|
00000040 65 74 75 72 6e 20 30 3b 20 20 20 20 0a 7d |eturn 0; .}|
0000004e
hexdump -C不直接显示中文是因为中文通常使用多字节编码(如 UTF-8、GBK 等),而hexdump的 ASCII 列默认只显示单字节可打印字符(0x20-0x7E 范围),多字节的中文字符会被拆分成多个字节,每个字节如果不在可打印范围内,就会显示为.。
hello 程序生命周期的一开始是一个高级 c 语言程序,它以文本形式保存,能被人直接理解,是程序尚未经过编译的初始状态,为了能在系统上运行 hello.c 程序,每条 c 语句都必须被其它程序转化为一系列的低级机器语言指令。
这些指令讲被按照一种成为可执行目标程序(executable object program)的格式打包好,并以二进制磁盘文件的形式存储起来。
我们可以使用 gcc 来编译 c 语言程序至可执行文件
bash
gcc -o hello hello.c编译后让我们查看文件目录
bash
ls -lah
----------
-rwxr-xr-x 1 root root 16K Sep 17 12:05 hello
-rw-r--r-- 1 root root 78 Sep 17 12:04 hello.c将 c 语言源代码翻译成可执行文件的这个过程可以分为四个阶段

- 预处理阶段:预处理器(cpp)根据以字符 # 开头的命令(directives),修改原始的C程序。比如 hello.c 中第一行的 # include<stdio.h> 指令告诉预处理器读取系统头文件 stdio.h 的内容,并把它直接插入到程序文本中去。结果就得到了另一个 C 程序,通常是以 .i 作为文件扩展名。
bash
1. 预处理,展开头文件
gcc -E hello.c -o hello.i
2. 查看处理结果
ls
hello.c hello.i
3. 查看.i文件
less hello.i
vim hello.i- 编译阶段:编译器(ccl)将文本文件 hello.i 翻译成文本文件 hello.s,它包含一个汇编语言程序。汇编语言程序中的每条语句都以一种标准的文本格式确切地描述了一条低级机器语言指令。汇编语言为不同高级语言的不同编译器提供了通用的输出语言。例如,C 编译器和 Fortran 编译器产生的输出文件用的都是一样的汇编语言。
bash
1. 将预处理后的.i文件翻译成汇编代码
gcc -S hello.i -o hello.s
2. 查看处理结果
ls
hello.c hello.i hello.s
3. 查看.s文件
cat hello.s
vim hello.s- 汇编阶段:汇编器(as)将 hello.s 翻译成机器语言指令,把这些指令打包成为一种叫做可重定位(relocatable)目标程序的格式,并将结果保存在目标文件 hello.o 中。hello.o 文件是一个二进制文件,它的字节编码是机器语言指令而不是字符。如果我们在文本编辑器中打开 hello.o 文件,呈现的将是一堆乱码。
bash
1. 将汇编代码翻译成机器码
gcc -c hello.s -o hello.o
2. 查看处理结果
ls
hello.c hello.i hello.o hello.s
3. 查看.o文件
file hello.o
hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
需要注意的是,此时的.o文件虽已包含机器指令,但因尚未经链接器处理,其内部地址仍为临时占位、未最终定位,所引用的外部符号(如 printf)也处于未解析状态,必须等链接阶段完成后才能填入真实地址并生成可执行文件。bash
hello.o 是二进制文件,不能用普通文本编辑器查看。
虽然不能直接看源代码,但可以利用工具反汇编或查看符号表
1. 反汇编
objdump -d hello.o
hello.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 8d 05 00 00 00 00 lea 0x0(%rip),%rax # b <main+0xb>
b: 48 89 c7 mov %rax,%rdi
e: e8 00 00 00 00 call 13 <main+0x13>
13: b8 00 00 00 00 mov $0x0,%eax
18: 5d pop %rbp
19: c3 ret
# lea 0x0(%rip),%rax 中的 4 字节 0——字符串常量的地址偏移
# call *0x00000000 中的 4 字节 0——printf 的相对地址偏移
2. 查看符号表
nm hello.o
0000000000000000 T main # T = text section,已定义
U puts # U = undefined,表示未解析- 链接阶段:由于我们的 hello 程序调用了 printf 函数,它是标准 C 库中的一个函数,每个 C 编译器都提供。printf 函数存在于一个名为 printf.o 的单独的预编译目标文件中,而这个文件必须以某种方式并入到我们的 hello.o 程序中。链接器(ld)亲负责处理这种并入,结果就得到 hello 文件,这个可执行文件加载到存储器后,由系统负责执行。
bash
1. 将目标文件与标准库(如 printf 所在的 libc)链接,生成可执行文件。
gcc hello.o -o hello
2. 查看处理结果
ls
hello hello.c hello.i hello.o hello.s
3. 执行目标文件
./hello
hello world
4. 查看执行文件依赖的库
ldd hello
linux-vdso.so.1 (0x00007ffe1a1d0000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8e2d166000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8e2d357000)硬件组成

总线
IO设备
主存(RAM)
CPU
查看 cpu 概述信息:
bash
lscpubash
sudo dmidecode -t processor查看每个 cpu 核心信息:
bash
cat /proc/cpuinfo
YJ