gcc链接时打桩

发布时间 2023-04-08 13:38:08作者: zwlwf

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执行时的地址。