最近追查一个崩溃问题,反汇编根据调用栈一层层查找,到了某一函数后竞找不到对应代码行,后进入其调用的某一个函数才将其调用顺序串起来。由此做了一个小实验,从汇编层面看看编译器如何处理。
C代码:
#include <stdio.h>
static void myfunc(void)
{
printf("myfunc in\n");
printf("myfunc out\n");
}
int main(int argc, char *argv[])
{
printf("main in\n");
myfunc();
printf("main out\n");
return 0;
}
用 arm-none-linux-gnueabi-gcc main.c 编译,再用arm-none-linux-gnueabi-objdump -d a.out 反汇编输出,从下面汇编片段,可以看出main函数对myfunc的调用: bl 842c <myfunc>
0000842c <myfunc>:
842c: e92d4800 push {fp, lr}
8430: e28db004 add fp, sp, #4
8434: e59f000c ldr r0, [pc, #12] ; 8448 <myfunc+0x1c>
8438: ebffffcd bl 8374 <_init+0x44>
843c: e59f0008 ldr r0, [pc, #8] ; 844c <myfunc+0x20>
8440: ebffffcb bl 8374 <_init+0x44>
8444: e8bd8800 pop {fp, pc}
8448: 0000856c .word 0x0000856c
844c: 00008578 .word 0x00008578
00008450 <main>:
8450: e92d4800 push {fp, lr}
8454: e28db004 add fp, sp, #4
8458: e24dd008 sub sp, sp, #8
845c: e50b0008 str r0, [fp, #-8]
8460: e50b100c str r1, [fp, #-12]
8464: e59f001c ldr r0, [pc, #28] ; 8488 <main+0x38>
8468: ebffffc1 bl 8374 <_init+0x44>
846c: ebffffee bl 842c <myfunc>
8470: e59f0014 ldr r0, [pc, #20] ; 848c <main+0x3c>
8474: ebffffbe bl 8374 <_init+0x44>
8478: e3a03000 mov r3, #0
847c: e1a00003 mov r0, r3
8480: e24bd004 sub sp, fp, #4
8484: e8bd8800 pop {fp, pc}
8488: 00008584 .word 0x00008584
848c: 0000858c .word 0x0000858c
然后再用 arm-none-linux-gnueabi-gcc -O1 main.c 进行1级优化编译, 用arm-none-linux-gnueabi-objdump -d a.out 反汇编输出,从汇编中找不到myfunc,main函数中也没有对其调用, 实际是myfunc较小,将myfunc嵌入到main函数中去了,8438-8444 即myfunc中两个printf调用。
0000842c <main>:
842c: e92d4008 push {r3, lr}
8430: e59f0020 ldr r0, [pc, #32] ; 8458 <main+0x2c>
8434: ebffffce bl 8374 <_init+0x44>
8438: e59f001c ldr r0, [pc, #28] ; 845c <main+0x30>
843c: ebffffcc bl 8374 <_init+0x44>
8440: e59f0018 ldr r0, [pc, #24] ; 8460 <main+0x34>
8444: ebffffca bl 8374 <_init+0x44>
8448: e59f0014 ldr r0, [pc, #20] ; 8464 <main+0x38>
844c: ebffffc8 bl 8374 <_init+0x44>
8450: e3a00000 mov r0, #0
8454: e8bd8008 pop {r3, pc}
8458: 00008544 .word 0x00008544
845c: 0000854c .word 0x0000854c
8460: 00008558 .word 0x00008558
8464: 00008564 .word 0x00008564
----------------------------------------
8438: e59f001c ldr r0, [pc, #28] ; 845c <main+0x30>
843c: ebffffcc bl 8374 <_init+0x44>
pc, #28 即845c, 此处存了个内存地址854c, 将(内存指针)854c指向的数据取出来放到 r0, 即"myfunc in\n"的内存首地址,然后调用printf函数。 按照函数调用约定, r0放第一个参数, r1, r2次之,再多的要放在栈上。
printf是C动态库里的函数, 这里没有bl printf之类的语句,实际是bl 8374 <_init+0x44> 这样的做法,然后再跳到真正的打印函数里。