5.3 ARM:3个参数

习惯上,ARM传递参数的规则(参数调用)如下:前4个参数传递给了R0-R3寄存器,其余的参数则在栈中。这和fastcall或者win64传递参数很相似

5.3.1 Non-optimizing Keil + ARM mode(非优化keil编译模式 + ARM环境)

  1. .text:00000014 printf_main1
  2. .text:00000014 10 40 2D E9 STMFD SP!, {R4,LR}
  3. .text:00000018 03 30 A0 E3 MOV R3, #3
  4. .text:0000001C 02 20 A0 E3 MOV R2, #2
  5. .text:00000020 01 10 A0 E3 MOV R1, #1
  6. .text:00000024 1D 0E 8F E2 ADR R0, aADBDCD ; "a=%d; b=%d; c=%d
  7. "
  8. .text:00000028 0D 19 00 EB BL __2printf
  9. .text:0000002C 10 80 BD E8 LDMFD SP!, {R4,PC}

所以 前四个参数按照它们的顺序传递给了R0-R3, printf()中的格式化字符串指针在R0中,然后1在R1,2在R2,3在R3. 到目前为止没有什么不寻常的。

5.3.2 Optimizing Keil + ARM mode(优化的keil编译模式 + ARM环境)

  1. .text:00000014 EXPORT printf_main1
  2. .text:00000014 printf_main1
  3. .text:00000014 03 30 A0 E3 MOV R3, #3
  4. .text:00000018 02 20 A0 E3 MOV R2, #2
  5. .text:0000001C 01 10 A0 E3 MOV R1, #1
  6. .text:00000020 1E 0E 8F E2 ADR R0, aADBDCD ; "a=%d; b=%d; c=%d
  7. "
  8. .text:00000024 CB 18 00 EA B __2printf

表5.7: Optimizing Keil + ARM mode

这是在针对ARM optimized (-O3)版本下的,我们可以B作为最后一个指令而不是熟悉的BL。另外一个不同之处在optimized与之前的(compiled without optimization)对比发现函数prologue 和 epilogue(储存R0和LR值的寄存器),B指令仅仅跳向另一处地址,没有任何关于LR寄存器的操作,也就是说它和x86中的jmp相似,为什么会这样?因为代码就是这样,事实上,这和前面相似,主要有两点原因 1)不管是栈还是SP(栈指针),都有被修改。2)printf()的调用是最后的指令,所以之后便没有了。完成之后,printf()函数就返回到LR储存的地址处。但是指针地址从函数调用的地方转移到了LR中!接着就会从printf()到那里。结果,我们不需要保存LR,因为我们没有必要修改LR。因为除了printf()函数外没有其他函数了。另外,除了这个调用外,我们不需要再做别的。这就是为什么这样编译是可行的。

5.3.3 Optimizing Keil + thumb mode

  1. .text:0000000C printf_main1
  2. .text:0000000C 10 B5 PUSH {R4,LR}
  3. .text:0000000E 03 23 MOVS R3, #3
  4. .text:00000010 02 22 MOVS R2, #2
  5. .text:00000012 01 21 MOVS R1, #1
  6. .text:00000014 A4 A0 ADR R0, aADBDCD ; "a=%d; b=%d; c=%d
  7. "
  8. .text:00000016 06 F0 EB F8 BL __2printf
  9. .text:0000001A 10 BD POP {R4,PC}

表5.8:Optimizing Keil + thumb mode

和non-optimized for ARM mode代码没什么明显的区别