返回介绍

5.4 ARM: 8 arguments

发布于 2025-02-22 14:00:42 字数 6915 浏览 0 评论 0 收藏 0

我们再用之前 9 个参数的那个例子

#!bash
void printf_main2()
{
    printf("a=%d; b=%d; c=%d; d=%d; e=%d; f=%d; g=%d; h=%d
", 1, 2, 3, 4, 5, 6, 7, 8);
};

5.4.1 Optimizing Keil: ARM mode

#!bash
.text:00000028      printf_main2
.text:00000028
.text:00000028      var_18 = -0x18
.text:00000028      var_14 = -0x14
.text:00000028      var_4 = -4
.text:00000028
.text:00000028 04 E0 2D E5      STR     LR, [SP,#var_4]!
.text:0000002C 14 D0 4D E2      SUB     SP, SP, #0x14
.text:00000030 08 30 A0 E3      MOV     R3, #8
.text:00000034 07 20 A0 E3      MOV     R2, #7
.text:00000038 06 10 A0 E3      MOV     R1, #6
.text:0000003C 05 00 A0 E3      MOV     R0, #5
.text:00000040 04 C0 8D E2      ADD     R12, SP, #0x18+var_14
.text:00000044 0F 00 8C E8      STMIA   R12, {R0-R3}
.text:00000048 04 00 A0 E3      MOV     R0, #4
.text:0000004C 00 00 8D E5      STR     R0, [SP,#0x18+var_18]
.text:00000050 03 30 A0 E3      MOV     R3, #3
.text:00000054 02 20 A0 E3      MOV     R2, #2
.text:00000058 01 10 A0 E3      MOV     R1, #1
.text:0000005C 6E 0F 8F E2      ADR     R0, aADBDCDDDEDFDGD ; "a=%d; b=%d; c=%d; d=%d;
e=%d; f=%d; g=%"...
.text:00000060 BC 18 00 EB      BL      __2printf
.text:00000064 14 D0 8D E2      ADD     SP, SP, #0x14
.text:00000068 04 F0 9D E4      LDR     PC, [SP+4+var_4],#4

这些代码可以分成几个部分:

Function prologue:

最开始的”STR LR, [SP,#var_4]!”指令将 LR 储存在栈中,因为我们将用这个寄存器调用 printf()。

第二个” SUB SP, SP, #0x14”指令减了 SP(栈指针),为了在栈上分配 0x14(20)bytes 的内存,实际上我们需要传递 5 个 32-bit 的数据通过栈传递给 printf() 函数,而且每个占 4bytes,也就是 5*4=20。另外 4 个 32-bit 的数据将会传递给寄存器。

通过栈传递 5,6,7 和 8:

然后,5,6,7,8 分别被写入了 R0,R1,R2 及 R3 寄存器。然后 ”ADD R12, SP,#0x18+var_14” 指令将栈中指针的地址写入,并且在这里会向 R12 写入 4 个值,var14 是一个汇编宏,相当于 0x14,这些都由 IDA 简明的创建表示访问栈的变量,var?在 IDA 中表示栈中的本地变量,所以 SP+4 将被写入 R12 寄存器。下一步的” STMIA R12, R0-R3 ”指令将 R0-R3 寄存器的内容写在了 R2 指向的指针处。STMIA 指令指 Store Multiple Increment After, Increment After 指 R12 寄存器在有值写入后自增 4。

通过栈传递 4:

4 存在 R0 中,然后这个值在” STR R0, [SP,#0x18+var_18] ”指令帮助下,存在了栈上,var_18 是 0x18,偏移量为 0.所以 R0 寄存器中的值将会写在 SP 指针指向的指针处。

通过寄存器传递 1,2,3:

开始 3 个数(a,b,c)(分别是 1,2,3) 正好在 printf() 函数调用前被传递到了 R1,R2,R3 寄存器中。 然后另外 5 个值通过栈传递。

printf() 调用

Function epilogue:

ADD SP, SP, #0x14 ”指令将 SP 指针返回到之前的指针处,因此清除了栈,当然,栈中之前写入的数据还在那,但是当后来的函数被调用时那里则会被重写。 “ LDR PC, [SP+4+var_4],#4 "指令将 LR 中储存的值载入到 PC 指针,因此函数结束。

5.4.2 Optimizing Keil: thumb mode

#!bash
.text:0000001C      printf_main2
.text:0000001C
.text:0000001C      var_18 = -0x18
.text:0000001C      var_14 = -0x14
.text:0000001C      var_8 = -8
.text:0000001C
.text:0000001C 00 B5        PUSH    {LR}
.text:0000001E 08 23        MOVS    R3, #8
.text:00000020 85 B0        SUB     SP, SP, #0x14
.text:00000022 04 93        STR     R3, [SP,#0x18+var_8]
.text:00000024 07 22        MOVS    R2, #7
.text:00000026 06 21        MOVS    R1, #6
.text:00000028 05 20        MOVS    R0, #5
.text:0000002A 01 AB        ADD     R3, SP, #0x18+var_14
.text:0000002C 07 C3        STMIA   R3!, {R0-R2}
.text:0000002E 04 20        MOVS    R0, #4
.text:00000030 00 90        STR     R0, [SP,#0x18+var_18]
.text:00000032 03 23        MOVS    R3, #3
.text:00000034 02 22        MOVS    R2, #2
.text:00000036 01 21        MOVS    R1, #1
.text:00000038 A0 A0        ADR     R0, aADBDCDDDEDFDGD ; "a=%d; b=%d; c=%d; d=%d; e=%d; f=%d; g=%"...
.text:0000003A 06 F0 D9 F8  BL __2printf
.text:0000003E
.text:0000003E              loc_3E ; CODE XREF: example13_f+16
.text:0000003E 05 B0        ADD SP, SP, #0x14
.text:00000040 00 BD        POP {PC}

几乎和之前的例子是一样的,然后这是 thumb 代码,值入栈的确不同:先是 8,然后 5,6,7,第三个是 4。

5.4.3 Optimizing Xcode (LLVM): ARM mode

#!bash
__text:0000290C     _printf_main2
__text:0000290C
__text:0000290C     var_1C = -0x1C
__text:0000290C     var_C = -0xC
__text:0000290C
__text:0000290C 80 40 2D E9     STMFD   SP!, {R7,LR}
__text:00002910 0D 70 A0 E1     MOV     R7, SP
__text:00002914 14 D0 4D E2     SUB     SP, SP, #0x14
__text:00002918 70 05 01 E3     MOV     R0, #0x1570
__text:0000291C 07 C0 A0 E3     MOV     R12, #7
__text:00002920 00 00 40 E3     MOVT    R0, #0
__text:00002924 04 20 A0 E3     MOV     R2, #4
__text:00002928 00 00 8F E0     ADD     R0, PC, R0
__text:0000292C 06 30 A0 E3     MOV     R3, #6
__text:00002930 05 10 A0 E3     MOV     R1, #5
__text:00002934 00 20 8D E5     STR     R2, [SP,#0x1C+var_1C]
__text:00002938 0A 10 8D E9     STMFA   SP, {R1,R3,R12}
__text:0000293C 08 90 A0 E3     MOV     R9, #8
__text:00002940 01 10 A0 E3     MOV     R1, #1
__text:00002944 02 20 A0 E3     MOV     R2, #2
__text:00002948 03 30 A0 E3     MOV     R3, #3
__text:0000294C 10 90 8D E5     STR     R9, [SP,#0x1C+var_C]
__text:00002950 A4 05 00 EB     BL      _printf
__text:00002954 07 D0 A0 E1     MOV     SP, R7
__text:00002958 80 80 BD E8     LDMFD   SP!, {R7,PC}

几乎和我们之前遇到的一样,除了 STMFA(Store Multiple Full Ascending) 指令,它和 STMIB(Store Multiple Increment Before) 指令一样,这个指令直到下个寄存器的值写入内存时会增加 SP 寄存器中的值,但是反过来却不同。

另外一个地方我们可以轻松的发现指令是随机分布的,例如,R0 寄存器中的值在三个地方初始,在 0x2918,0x2920,0x2928。而这一个指令就可以搞定。然而,optimizing compiler 有它自己的原因,对于如何更好的放置指令,通常,处理器尝试同时执行并行的指令,例如像” MOVT R0, #0”和” ADD R0, PC,R0”就不能同时执行了,因为它们同时都在修改 R0 寄存器,另一方面”MOVT R0, #0”和”MOV R2, #4”指令却可以同时执行,因为执行效果并没有任何冲突。 大概,编译器就是这样尝试编译的,可能。

5.4.4 Optimizing Xcode (LLVM): thumb-2 mode

#!bash
__text:00002BA0     _printf_main2
__text:00002BA0
__text:00002BA0     var_1C = -0x1C
__text:00002BA0     var_18 = -0x18
__text:00002BA0     var_C = -0xC
__text:00002BA0
__text:00002BA0 80 B5           PUSH    {R7,LR}
__text:00002BA2 6F 46           MOV     R7, SP
__text:00002BA4 85 B0           SUB     SP, SP, #0x14
__text:00002BA6 41 F2 D8 20     MOVW    R0, #0x12D8
__text:00002BAA 4F F0 07 0C     MOV.W   R12, #7
__text:00002BAE C0 F2 00 00     MOVT.W  R0, #0
__text:00002BB2 04 22           MOVS    R2, #4
__text:00002BB4 78 44           ADD     R0, PC ; char *
__text:00002BB6 06 23           MOVS    R3, #6
__text:00002BB8 05 21           MOVS    R1, #5
__text:00002BBA 0D F1 04 0E     ADD.W   LR, SP, #0x1C+var_18
__text:00002BBE 00 92           STR     R2, [SP,#0x1C+var_1C]
__text:00002BC0 4F F0 08 09     MOV.W   R9, #8
__text:00002BC4 8E E8 0A 10     STMIA.W LR, {R1,R3,R12}
__text:00002BC8 01 21           MOVS    R1, #1
__text:00002BCA 02 22           MOVS    R2, #2
__text:00002BCC 03 23           MOVS    R3, #3
__text:00002BCE CD F8 10 90     STR.W   R9, [SP,#0x1C+var_C]
__text:00002BD2 01 F0 0A EA     BLX     _printf
__text:00002BD6 05 B0           ADD     SP, SP, #0x14
__text:00002BD8 80 BD           POP     {R7,PC}

几乎和前面的例子相同,除了 thumb-instructions 在这里被替代使用了

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文