了解ARM ASM中的函数调用
Understanding function calls in ARM ASM
我正在拆解本机Android库(armeabi-v7a),这些库很可能是从C++或C代码创建的,并被剥离。目标是创建一个函数调用树,以便以后进行分析。
我在理解分解后的输出时遇到问题。
以arm-linux-androideabi-objdump -d libledger.so > output.txt
创建的以下汇编程序片段为例
00014988 <_ZSt10__pop_heapIN9__gnu_cxx17__normal_iteratorIPSsSt6vectorISsSaISsEEEENS0_5__ops15_Iter_less_iterEEvT_S9_S9_T0_>:
...
149e0: 4620 mov r0, r4
149e2: f030 fadd bl 44fa0 <_ZNK10__cxxabiv120__si_class_type_info11__do_upcastEPKNS_17__class_type_infoEPKvRNS1_15__upcast_resultE+0x2a7ec>
149e6: e7ff b.n 149e8 <_ZSt10__pop_heapIN9__gnu_cxx17__normal_iteratorIPSsSt6vectorISsSaISsEEEENS0_5__ops15_Iter_less_iterEEvT_S9_S9_T0_+0x60>
149e8: 4628 mov r0, r5
149ea: f030 fad9 bl 44fa0 <_ZNK10__cxxabiv120__si_class_type_info11__do_upcastEPKNS_17__class_type_infoEPKvRNS1_15__upcast_resultE+0x2a7ec>
149ee: f004 fe55 bl 1969c <__cxa_end_cleanup>
149f2: bf00 nop
149f4: b154 cbz r4, 14a0c <_ZSt16__introsort_loopIN9__gnu_cxx17__normal_iteratorIPSsSt6vectorISsSaISsEEEEiNS0_5__ops15_Iter_less_iterEEvT_S9_T0_T1_+0x14>
149f6: 0005 movs r5, r0
000149f8 <_ZSt16__introsort_loopIN9__gnu_cxx17__normal_iteratorIPSsSt6vectorISsSaISsEEEEiNS0_5__ops15_Iter_less_iterEEvT_S9_T0_T1_>:
149f8: e92d 4ff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
149fc: 1d07 adds r7, r0, #4
149fe: b085 sub sp, #20
14a00: 4604 mov r4, r0
14a02: 4690 mov r8, r2
14a04: 460e mov r6, r1
14a06: 1b35 subs r5, r6, r4
14a08: 2d43 cmp r5, #67 ; 0x43
14a0a: f340 8095 ble.w 14b38 <_ZSt16__introsort_loopIN9__gnu_cxx17__normal_iteratorIPSsSt6vectorISsSaISsEEEEiNS0_5__ops15_Iter_less_iterEEvT_S9_T0_T1_+0x140>
14a0e: f1b8 0f00 cmp.w r8, #0
14a12: d13f bne.n 14a94 <_ZSt16__introsort_loopIN9__gnu_cxx17__normal_iteratorIPSsSt6vectorISsSaISsEEEEiNS0_5__ops15_Iter_less_iterEEvT_S9_T0_T1_+0x9c>
14a14: 10ad asrs r5, r5, #2
14a16: 4b4a ldr r3, [pc, #296] ; (14b40 <_ZSt16__introsort_loopIN9__gnu_cxx17__normal_iteratorIPSsSt6vectorISsSaISsEEEEiNS0_5__ops15_Iter_less_iterEEvT_S9_T0_T1_+0x148>)
14a18: 1eaf subs r7, r5, #2
14a1a: f10d 090c add.w r9, sp, #12
在这里描述的分支指令中,BL
家族的指令最类似于函数调用,5.3子程序调用中也暗示了这一点。然后还有通过SWI
的系统调用。然而,我想到了一些问题:
- 我能确定对于
BL
指令,要跳转到的标签总是指向C函数的开头吗?这意味着它们的行为就像调用一个C函数 - C函数调用还使用了哪些指令
- 在上面的例子中,这意味着在
149e2:
有一个函数调用。不过我不理解<XY+0x2a7ec>
部分。这是否意味着。。。- 被调用的函数从
addressoff(XY) + 0x2a7ec
开始,但不在.dynsym
表中,因此没有可供反汇编程序参考的友好名称 - 这是否意味着
XY
在调用时会有巨大的偏移量 - 或者两者都有可能
- 被调用的函数从
- 如何识别函数的开始?在我看来,像
00014988 <...>
这样地址完整的部分是函数。尽管我担心这只适用于动态符号表中的函数,这将解释上面的巨大偏移 - 在
149f4
也有一个分支,这次是通过CBZ
。这看起来也像是对另一个函数的函数调用,同样带有偏移量。当00014988
和000149f8
都是函数时,此CBZ
调用将直接跳转到函数中,而不是一开始。这是什么意思
对于BL指令,我能确定要跳转到的标签总是指向C函数的开头吗?这意味着它们的行为就像调用一个C函数。
是的,大多数时候分支都会到函数的开头。
C函数调用还使用了哪些指令?
任何可以更改程序计数器的内容
我看到了BX, LDR PC,
和POP
的说明。
在上面的例子中,这意味着在149e2:有一个函数调用。不过我不理解这个部分。这是否意味着
被调用的函数从addressoff(XY)+0x2a7ec开始,但不在.dynsym表中,因此没有可供反汇编程序参考的友好名称?
并非每个地址都与来源行号对齐。偏移量是与映射文件中的已知符号(通常是函数名)的距离。
这是否意味着XY被称为具有巨大的偏移量?
没有。分支的目的地位于公共符号的偏移处。在许多情况下,许多函数都不是公共的,因此它们被引用到地图文件中最近的公共符号。
或者两者都有可能?
请参见上文。
如何识别函数的开始?
没有一般规则
这是一个过程:
- 打开列表文件(包含汇编语言)
- 在汇编语言列表中查找偏移量
- 或者找到资金,然后添加偏移量并查找该地址
在149f4也有一个分支,这次是通过CBZ。这看起来也像是对另一个函数的函数调用,同样带有偏移量。当00014988和000149f8都是函数时,此CBZ调用将直接跳转到函数中,而不是一开始。这是什么意思?
CBZ
不是子程序或函数调用。它是另一个地址的分支。预计不会返回。
分支与链接(BL
)和分支与交换(BX
)指令将LR
寄存器设置为返回地址(通常是BL
或BX
之后的下一条指令)。为了返回,LR
寄存器中的值被复制到程序计数器(PC
)寄存器中,导致执行转移到LR中的地址。这是函数或子程序调用的返回。
- 函数调用中参数的顺序重要吗
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 变量没有改变?通过向量的函数调用
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数
- 我知道函数调用中存在歧义.有没有办法调用foo()函数
- 模板函数调用
- 获取从C++中同一类中的构造函数调用的方法返回的值
- 析构函数调用
- 成员函数调用和C++对象模型
- 使用共享指针的函数调用,其对象应为 const
- C++:编译时检查匹配的函数调用对?
- 函数调用C++中的参数太少
- 来自 DLL 的函数调用 [表观调用的括号前面的表达式必须具有(指向-)函数类型]
- 返回指向对象的指针的函数调用是否为 prvalue?
- C++ 如何重载 [] 运算符并进行函数调用
- 内联asm编译器屏障(内存阻塞器)是算作外部函数,还是算作静态函数调用
- 了解ARM ASM中的函数调用
- 在c++中调用ASM函数
- 在c++中调用ASM函数