最近有个mips平台的嵌入式linux项目,官方提供了工具链,但发现他们所提供的libpthread.so库对线程的最小栈空间设置的是128K,造成程序运行时显示虚拟内存占用很高,虽然没太大影响,但是对我这样有洁癖的人感觉很不爽,所以我想把它改小,重新编译glibc感觉麻烦,好像也不安全,所以就想着直接修改库的二进制文件,下面是修改过程:
先写个测试代码如下:
#include
#include
#include
static void *func(void *arg)
{
printf("I am a thread\n");
return NULL;
}
int main(int argc,char *argv[])
{
pthread_t thread_id;
int ret ,stacksize = 20480;
pthread_attr_t attr;
if(argc > 1){
stacksize = atoi(argv[1]);
}
printf("stacksize = %d\n",stacksize);
ret = pthread_attr_init(&attr);
if (ret != 0){
printf("pthread_attr_init fail\n");
return -1;
}
ret = pthread_attr_setstacksize(&attr, stacksize);
if(ret != 0){
printf("pthread_attr_setstacksize fail\n");
return -1;
}
ret = pthread_create (&thread_id, &attr, &func, NULL);
if(ret != 0){
printf("pthread_create fail\n");
return -1;
}
ret = pthread_attr_destroy(&attr);
if(ret != 0){
printf("pthread_attr_destroy fail\n");
return -1;
}
pthread_join(thread_id, NULL);
printf("exit\n");
}
编译测试程序:
注意,建议使用-fno-omit-frame-pointer参数,不然gdb可能无法进入函数pthread_attr_setstacksize
mips-linux-gnu-gcc -g -EL -mips32r2 -fno-omit-frame-pointer -o thread_test thread_test.c -I/opt/mips-linux-gnu/libc/usr/include -L/opt/target/lib -lpthread
GDB调试测试程序:
gdb用到的几条命令:
target remote 192.168.1.125:1234
#连接远程目标(gdbserver)
set solib-search-path /buildroot-6.6.1.6/output/target/lib
#设置动态库路径,方便gdb加载调试符号
set heuristic-fence-post 100000
#不设置这个单步的时候可能停不到函数上,我理解的大概的原因就是函数的标准入口格式被优化掉了,gdb不能简单识别了,它要找找看。
b pthread_attr_setstacksize
#这个大家都懂,设置断点
disassemble
#反汇编当前段代码
x /5fx 0x77fabce0
#显示内存中的内容,我用它看当前的指令字节。
当断点停下来了,用disassemble反汇编查看代码和查看寄存器内容
lui v0,0x2:这条指令是把立即数0x2放到v0的高16位,也就是0x20000,就是libpthread-2.18.so设置的最小线程栈128kBtye。
sltu v0,a1,v0:这条指令是比较我们设置的堆栈大小和0x20000进行比较,如果我们传入的值大于这个值,程序继续运行,反之返回错误。我们可以看到a1中是我们代码中传入的0x5000。
接下来我们使用x /5fx 0x77fabce0看看lui v0,0x2的指令码:
我们看到的是0x3c020002,3c02是指令码,0002是立即数。
好了,现在我们要修改这条指令了,但是我发现个问题,如果只修改后面的立即数的话,我只有两个选择,一个是改成1,一个是改成0,改1的话限制大小变成64K,还是有点大,如果是0的话完全失去了限制,这都是我不想样要的。所有要想办法把整条指令改掉,但查mips指令手册太麻烦,直接用代码测试吧 。
int main(int argc,char *argv[])
{
int a = 0;
a = 0x2800;
printf("I am a thread %d\n",a);
return 0;
}
用mips-linux-gnu-gcc编译上面的代码,然后使用mips-linux-gnu-objdump -d查看
24022800 li v0,10240
这句就是我们想要的,把立即数10240传给v0。
现在我们用UE打开libpthread-2.18.so文件,然后根据前面x /5fx 0x77fabce0看到的内容进行搜索和替换修改,注意大小端的问题,这样就搞定了。
把0200023c替换成00280224,完美收工。
谢谢观赏!