84 lines
3.2 KiB
Markdown
84 lines
3.2 KiB
Markdown
# Inline Assembly 与链接加载
|
||
|
||
## Inline Assembly
|
||
|
||
可以在 C 代码里嵌入汇编语言的骚操作。毕竟编译器本身也就是个复制,翻译,,粘贴的过程。
|
||
|
||
> C 语言是高级的汇编语言!
|
||
|
||
你可以把每一个 C 语言的语句都直译成一条一条的汇编代码。反正也是顺序执行的。
|
||
|
||
C 艹可能没那么容易了····比如说虚函数调用,那你就不太好翻译嘛。
|
||
|
||
最简单的就是用用个 asm(.....)
|
||
|
||
当然这里可以参考 c inline Asm 的教程 但是已经脱离了本文的主题了
|
||
|
||
这里给指条路 [How to Use Inline Assembly Language in C Code](https://dmalcolm.fedorapeople.org/gcc/2015-08-31/rst-experiment/how-to-use-inline-assembly-language-in-c-code.html)
|
||
|
||
> 诸如 Go 的高级语言 也可以通过 inline C 来 内链汇编
|
||
|
||
你可以写任何一个指令,他完全不会检查 也不会优化 编译器默认你知道你在干什么。
|
||
|
||
然后 C 编译器就会将这部分代码 <strong>原封不动地 </strong>拷贝进你的二进制代码当中
|
||
|
||
当然,你可以通过 RTFM 来将 C 语言的变量塞到汇编中处理。
|
||
|
||
在 Windows 平台下 VS 没有 Code 可以以 `__asm {}` 代码块来进行实验 但是注意 只能在 x86 模式下使用 x64 不支持 可以参考 [__asm](https://docs.microsoft.com/zh-tw/cpp/assembler/inline/asm?view=msvc-170)
|
||
|
||
以上两种平台的方案都其实本质是编译器特殊宏 并不包括在 C 的标准内 所以要针对不同的编译器 寻找对应的文档
|
||
|
||
## 静态链接
|
||
|
||
当你使用 GCC 生成可执行文件./a.out 时,到底发生了什么?
|
||
|
||
为什么就可以直接执行呢?当你问及这个问题时,那么就大有一番探索的空间了
|
||
|
||
## 链接器
|
||
|
||
链接器的功能:将一个可执行程序所需的目标文件和库最终整合在一起。
|
||
|
||
就是说,你调用的一些库,是必须要有外部的东西支持的
|
||
|
||
这个就是帮你和外部库连接起来的重要部分。
|
||
|
||
一个程序包含三个段:.text、.data 和 .bss 段。
|
||
|
||
而各目标文件和库都包含这三段,所以,ld 链接器的功能就是将各个目标文件和库的三段合并在一起。
|
||
|
||
当然,链接器所完成的链接工作并非只是简单地将各个目标文件和库的三段内存堆砌在一起,而是还要完成“重定位”的工作。
|
||
|
||
### 查看二进制文件的工具
|
||
|
||
使用 objdump 查看 data 节的 x,y
|
||
|
||
查看 main 对应的汇编代码
|
||
|
||
使用 readelf 查看 relocation 的信息
|
||
|
||
使用 IDA BinaryNInja 一类反汇编工具
|
||
|
||
## 动态链接
|
||
|
||
静态链接一次用那么多,实在是太大太大了
|
||
|
||
比如说一个 printf 就要几十 KB,完全没必要把 libc 代码包含到程序里面
|
||
|
||
可以等程序加载好之后再去做一个链接
|
||
|
||
Windows 下一般是 DLL 作为程序使用的 动态链接库
|
||
|
||
Linux 下一般是 .so 如果你看到了 .a 那个一般是 archive 的缩写
|
||
|
||
使用动态链接的好处在于 可以热加载和热更新
|
||
|
||
## 共享连接的加载
|
||
|
||
使用 ldd 来查看 a.out 就可以查看动态链接库
|
||
|
||
不过 ldd 这个是个神奇的脚本!!!
|
||
|
||
他做的事情就是挨个调用去试着加载 a.out
|
||
|
||
加载会读取头中的一些表 比如全局 GOT 然后根据名称查找
|