[关闭]
@zwh8800 2017-08-23T02:03:43.000000Z 字数 1653 阅读 191595

arm-linux 汇编(2) – 调用c函数

blog 归档 arm-linux 汇编 系统编程


上一篇学习了armlinux汇编的helloworld,用到了arm汇编的一些基本指令,如mov、ldr、swi,需要详细的arm体系架构的信息可以去arm官网下载arm_architecture_reference_manual.pdf文件,上面有很详细的信息。本文接着上次,继续讲一下如何用汇编调用c函数。

另外,如果觉得那个手册太冗长,或者是英文苦手的话,可以在本站下载这个短小精悍的reference card(中文版哦):

https://lengzzz.com/download/QRC0001_UAL.pdf


现在进入正题:

上一篇中,重点讲述了在arm-linux下的系统调用的方法,但是更多时候,我们可能会与一些c库进行交互,今天学习了汇编调用c库函数的方法。

先上例子:

  1. .section .rodata
  2. fmt:
  3. .asciz "2 * 4 = %d\n" @.ascizNULL结尾的字符串
  4. .section .text
  5. .global _start
  6. _start:
  7. mov r2, #2
  8. mov r3, #4
  9. mul r1, r2, r3 @乘法指令, r1=r2*r3
  10. ldr r0, =fmt
  11. bl printf @bl为函数调用, 跳转到printf并将当前pc保存到lr寄存器
  12. exit:
  13. mov r0, #1
  14. mov r7, #1
  15. swi #0

例子很简单, 功能就是计算2*4并输出2 * 4 = 8. 先使用mul指令计算出2*4的值放在r1寄存器中, 然后将printf的格式串fmt放到r0中, 然后调用printf函数.

要汇编这个程序不能用昨天简单的指令了. 因为, printf是libc库中的函数, 必须要和c库进行连接:

  1. as mul.s -o mul.o
  2. ld -dynamic-linker /lib/ld-linux-armhf.so.3 mul.o -o mul -lc

相比较上一篇中的连接指令, 多了两条, 一个是-dynamic-linker /lib/ld-linux-armhf.so.3`另一个是-lc

第一个是指令在man pages中的介绍是:

–dynamic-linker=file
Set the name of the dynamic linker. This is only meaningful when
generating dynamically linked ELF executables. The default dynamic
linker is normally correct; don’t use this unless you know what you
are doing.

是用来设置动态链接器的, 在不同的设备上ld-linux-armhf.so.3的名字可能都不一样, 但一般都在lib文件夹中并且以ld开头. 如果没有这条指令的话, 运行程序的时候会提示file not found

第二条是-lc, 和gcc的用法一样, 表示连接libc库. 如果不加这个指令的话连接时会提示undefined “printf”.

现在介绍一下bl指令. bl是branch(分支) link(连接)的缩写(和x86架构的call ret相比意思太含糊了), branch的意思就是跳转(分支)到其他地方执行, link的意思是将当前的pc(Program Counter程序计数器, 保存着当前程序运行到哪里了)寄存器保存到lr(Link Register连接寄存器), 以便调用函数之后函数可以返回回来. 当printf函数运行结束时, 会调用mov pc, lr来返回.

再来说一说arm的寄存器吧. 在用户态, arm的寄存器一共有这几个:

r0 r1 r2 r3 r4 r5 r6 r7
r8 r9 r10 r11 r12 r13(sp) r14(lr) r15(pc)
CPSR

算是比较多的. 其中sp表示堆栈指针(Stack Pointer), lr代表连接寄存器(Link Register), pc表示程序计数器(Program Counter).

具体函数调用时参数传递和返回值用那些寄存器在eabi中都有介绍. 之后将会进行学习.

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注