gcc链接时打桩
gcc 链接时打桩
链接时打桩简单分析
链接时打桩本质是在重定位解析符号的时候,做了手脚。
假设main.o用到外部符号malloc,malloc的定义本来在libc中,直接链接给定-L/path/to/libc.so -lc
, main.o中malloc的地址就链接到了libc.so中的符号。
链接时打桩,解析main.o中符号引用时,某个点重定位用到malloc的符号,偷梁换柱成用___wrap_malloc
函数。而链接过程中需要使用__real_malloc
函数进行重定位时会用到malloc
的定义点。
一个小试验
这里利用链接时打桩技术,将awk的默认分割符修改为逗号,以方便awk对的解析。
首先从https://github.com/onetrueawk/awk下载awk源码(这个程序很小),然后make构建一下。假设目录为~/software/awk
.
然后,写一个wrap_main函数,在执行真正的main之前,对输入的参数进行修饰。逻辑是若通过-F
指定了分隔符,就使用指定的,否则添加-F ,
来指定逗号为分割符。
//wrap_main.c
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
int __real_main(int argc, char**argv);
void render_argmuments(int argc, char**argv, int *arg_num, char*** arg_value) {
bool hasDelimiter = false;
for(int i=1; i<argc; i++) {
if(strcmp(argv[i], "-F")==0) hasDelimiter = true;
}
if(hasDelimiter) {
*arg_num = argc;
*arg_value = argv;
} else {
*arg_num = argc+2;
*arg_value = (char**)malloc(*arg_num*sizeof(char*));
char** tmp = *arg_value;
tmp[0] = argv[0];
tmp[1] = "-F";
tmp[2] = ",";
for(int i=1; i<argc; i++) tmp[i+2] = argv[i];
}
}
int __wrap_main(int argc, char**argv) {
int arg_num;
char** arg_value;
render_argmuments(argc, argv, &arg_num, &arg_value);
printf("check args:\n");
for(int i=0; i<arg_num; i++) printf("arg[%d] = %s\n",i,arg_value[i]);
return __real_main(arg_num, arg_value);
}
Makefile
app : wrap_main.c
echo ${PWD}
cd ~/path/to/awk/build && gcc -g -Wall -Wl,--wrap,main -pedantic -Wcast-qual -O2 ${PWD}/wrap_main.c awkgram.tab.o b.o main.o parse.o proctab.o tran.o lib.o run.o lex.o -lm -o ${PWD}/app
test : app
echo 1,2,3 | ./app '{print $1,$2}'
注意Makefile中, 其中app target的第二条命令,cd改变工作目录之后,${PWD}
返回的是make执行时的地址。
参考
- 《gcc指定入口函数》https://blog.csdn.net/skertone/article/details/38088205
- 《linux x86程序启动,main函数是怎么被执行的》https://zhuanlan.zhihu.com/p/52054044