20240819编译 链接 单片机执行的第一个语句
2024年8月中旬在宝鸡出差,在B站上学习了下。
在linux操作系统中,gdb是调试器,gcc是编译器。
Linux 操作系统 将main.elf文件加载到内存中以后,操作系统为其分配进程,然后main函数就开始执行了。
输入 layout asm 则显示出来汇编代码
键入 “starti”的时候
进入到程序里面的第一个指令执行 发现程序进入的第一个指令 并不是main函数 而且是一个在库文件 Lib64/ld-linux-x86-64.so.2
这个start的地址是 0x7ffff7fe32b0 并不是mian 的首地址。
然后在strat上再次打断点
然后又进入了一个start里面
这个start 的地址是 0X555555555060 应该是程序自己的一个statrt 还没有进入到main
然后在Main上打断点 。
用”ni”指令继续执行程序,程序调用了一个_GI_exit 实际上这个指令就是操作系统帮我们结束进程。
20240818学习
进行预处理
进行编译成汇编
可以看见下图 在Data 段落定义了字符传 hellow word 定义了main符号 是在代码段main 符号里面 都是X86汇编代码。
还发现:
然后我还发现了作者是不是在 B站上写文章呢,也象知乎那样?
后来我发现是在博客园写的,写的比较好看
地址:编译?汇编?链接? - yudoge - 博客园 (cnblogs.com)
例如我们刚才看到的prinf 函数的调用 实际上CALL指令后面还是符号 目前不知道去哪里找这个 puts@PLT 这个东西
实际上,打开预处理的源文件后 看见printf 也就是一个外部函数的申明,也没有函数体
综上:所以单靠main一个文件是无法编译连接出可执行文件程序的。 还需要将printf在最后的可执行文件里面找到。
下一步:汇编main.s 通过编译编译变为可重定向的目标文件 main.o
可用 gcc命令做这个事情
Gcc-c main.c -o gcc main.o
通过vim指令 可以看下 main.o 其实也看不了 因为已经是一个二进制文件
但是可以使用 objdump 命令看下里面的代码信息
通过上图可以看见 编译以后 Main函数还没有分配地址,
通过上图 可以看见 e8 应该是call call 后面也要跟地址,但是目前地址也是00 00 00 00
也不知从哪里去调用这个printf
我们可以通过-t 来看下符号表 如下图
展开后的符号表 如下图所示
通过下图可以看见 puts 符号是未定义的
现在对目标文件进行链接的话, 可执行文件是执行不了的。
用 test Ld main .o - o main 发现如下图
如下图 提示有一个未定义的引用。 “puts”
那么符号“puts” 可能存在于另外一个目标文件.obj中,需要将另外一个目标文件也链接进来。 于是下一步 将两个目标文件obj ,链接到一个目标文件里面。
2024年8月18日晚上
例如现在定义了两个C源文件 a.c 和 say.c
注意a.c文件中main()函数之前并没有包括头文件 #include“stdio.h“ 于是在下面的图10中 会提示找不到 start 符号标识。 提示了警告 cannot find entry symbol _start; default 0x0000401000
a.c |
Say.c |
Void say() Int main() { Say(); } |
Void say() { int a = 10 ; while(1); } |
希望a.c文件中调用say()函数
用gcc-c命令 生成目标文件
Gcc-c a.c -o a.o
Gcc-c say.c -o say.o
通过 objdump -d -t a.o 来查看a.o 的目标链接文件。 如下图
a.o 的目标链接文件如下图 实际下图的call函数 调用的是ssay函数 显然因为say函数没有在a.c函数中定义,所以 显示say函数是 UND undefine 没有定义。
但是 say.o 中有这say这个符号的。
于是可以把a.o 和 say.o 链接在仪器 输出一个a.out
但是提示了 cannot find entry symbol _start; default 0x0000401000
因为:注意到a.c文件中main()函数之前并没有包括头文件 #include“stdio.h“ 于是在下面的图10中 会提示找不到 start 符号标识。 提示了警告 cannot find entry symbol _start; default 0x0000401000
通过以下命令 强制的指定main () 函数 作为入口地址
Ld -e main a.o say.o -o a.out “e” 表示的是entry 即入口地址
通过上图中的 objdump -d -t a.out 可以查看a.out 中的符号表 如下图
可以看到 main 函数 和 say 函数的入口地址均已经指定了。
然后 也看见 符号表 里面也没有 出现 UNDEF 地址了。
于是 明白了链接的意义了, 即 不同文件里面的 可执行文件 .obj 合格成一个 可执行文件,把没有定义的符号,也定义了。
接下来我们回到问题, 操作系统执行的main 函数,操作系统结束了main 函数
2024年8月22日先总结到这里
百度网盘链接
我的网盘 博客园上的文章 20240817_用gdb调试器调试main找进入main 之前的函数.rar