二进制方式修改libpthread.so中的pthread_attr_setstacksize最小限

2019-07-13 07:08发布

       最近有个mips平台的嵌入式linux项目,官方提供了工具链,但发现他们所提供的libpthread.so库对线程的最小栈空间设置的是128K,造成程序运行时显示虚拟内存占用很高,虽然没太大影响,但是对我这样有洁癖的人感觉很不爽,所以我想把它改小,重新编译glibc感觉麻烦,好像也不安全,所以就想着直接修改库的二进制文件,下面是修改过程:先写个测试代码如下:#include #include #include static void *func(void *arg) { printf("I am a thread "); 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 ",stacksize); ret = pthread_attr_init(&attr); if (ret != 0){ printf("pthread_attr_init fail "); return -1; } ret = pthread_attr_setstacksize(&attr, stacksize); if(ret != 0){ printf("pthread_attr_setstacksize fail "); return -1; } ret = pthread_create (&thread_id, &attr, &func, NULL); if(ret != 0){ printf("pthread_create fail "); return -1; } ret = pthread_attr_destroy(&attr); if(ret != 0){ printf("pthread_attr_destroy fail "); return -1; } pthread_join(thread_id, NULL); printf("exit "); }编译测试程序:注意,建议使用-fno-omit-frame-pointer参数,不然gdb可能无法进入函数pthread_attr_setstacksizemips-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 -lpthreadGDB调试测试程序:
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 ",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,完美收工。谢谢观赏!