C函数在Cortex-M4处理器中的运行过程

最近离职了,找工作必然要经历面试。而每个面试官的考察,或者关心的点可能都不一样。有一个面试官很关心函数在处理器中的运行过程。当然,我这个问题没有回答好,所以才有了今天这篇文章了吧。如果有讲的不对的地方还希望多多指正!

0x00 汇编基础语法

PUSH和POP

PUSH {R0, R4-R7, R9} ; 把 R0, R4, R5, R6, R7, R9 压入栈中(stack) 
POP {R2, R3} ; 从栈(stack)中弹出数据到R2,R3

使用PUSH和POP涉及到栈指针(SP)的相关操作。例如,PUSH是先让SP = SP - N,其中N是压入栈中的寄存器数据总长度。然后把想要存储的寄存器存储到SP指向的位置。
而POP正好相反,先把栈内的数据弹出到相应寄存器,然后SP = SP + N。


栈操作

MOV和MOVS

MOV指令主要用于内核的寄存器间的数据传递。MOVS与MOV类似,但是它会改变APSR中的标志位。

MOV R4, R0;把R0拷贝到R4

LDR和STR

LDR和STR用于内存和寄存器之间的数据传递。LDR把数据从内存搬运到寄存器中,STR把数据从寄存器中搬运到内存中。

LDR R0, [R1, #0x3] ; 从地址 R1+0x3读出32bit长度的数据,把它存储到R0中
STR R0, [R1, #0x3] ; 把R0存储到地址 R1+0x3

CBNZ

CBNZ(Compare and Branch if NonZero),从字面意思理解可以看出他是比较然后不为零就跳转。

CBNZ r0,0x080010B4

如果r0不等于0,那么PC指针就跳转到0x080010B4。

B和B.W

跳转指令,如果跳转到的位置不超过+/-2KB,可以使用B。否则就要是用B.W这个32bit版本的指令。

SUBS和MULS

SUBS          r0,r4,#1

r0 的r4 减去 #1

MULS          r0,r4,r0

把r0的等于r4乘以r0

示例1-函数调用

c函数编译成汇编

//c函数
void foo(int bar,int *baz)
{
    char sink[4];
    short *why;
    why = (short *)(sink + 2);
    * why = 50;
}
void helloWorld(void)
{
    int i = 4;
    foo(i,&i);
    return ;
}
;汇编片段
foo:
0x080010BE B508      PUSH          {r3,lr}
0x080010C0 4602      MOV           r2,r0
0x080010C2 F10D0002  ADD           r0,SP,#0x02
0x080010C6 2332      MOVS          r3,#0x32
0x080010C8 8003      STRH          r3,[r0,#0x00]
0x080010CA BD08      POP           {r3,pc}
helloWorld:
0x080010CC B508      PUSH          {r3,lr}
0x080010CE 2004      MOVS          r0,#0x04
0x080010D0 9000      STR           r0,[sp,#0x00]
0x080010D2 4669      MOV           r1,sp
0x080010D4 9800      LDR           r0,[sp,#0x00]
0x080010D6 F7FFFFF2  BL.W          foo (0x080010BE)
0x080010DA BD08      POP           {r3,pc}

汇编分析

helloWorld函数

0x080010CC: 把r3和lr,压入栈中。压入lr用于函数返回,压入r3是为了开辟栈空间,用于保存局部变量i。此时的sp减少了8,因为压入了两个32bit的寄存器。
0x080010CE: 把r0赋值为0x04
0x080010D0: 把r0存到sp指向的内存地址。也就存到开辟的栈空间里。
0x080010D2: 把sp赋值r1。r1作为foo(i,&i)的第二个参数&i。
0x080010D4: 把sp指向内存的值赋值给r0,即把i赋值给r0。r0作为foo(i,&i)的第一个参数。
0x080010D6: 跳转到函数foo,即汇编的位置0x080010BE
0x080010DA: 弹出栈中一个值到r3,另一个栈中的lr值没有给lr寄存器,而是直接给了pc值,完成跳转。

foo函数

0x080010BE: 先把lr和r3保存在栈中,sp = sp - 8;lr用于函数返回,即跳转到位置0x080010DA但是实际的值是0x080010DB。这与处理器的流水线架构有关,编译器自动计算出了实际应该跳转到的位置。编译器只为sink[4]申请了栈空间,而没有给why申请空间。想必是认为没有必要,因为why最终是一个地址,且该地址是为了给sink赋值。
0x080010C0: 把r0赋值给r2,即把参数i赋值给r2。
0x080010C2: 把sp+2 赋值给r0。即把&sink[2]赋值给r0。这里为什么用了r0呢,r0难道不是用于保存参数i的么。这里编译器可能是知道在foo中并没有用到输入的参数,所以用于保存输入参数的r0被覆盖也没有关系。
0x080010C6:赋值0x32给r3。
0x080010C8:把r3存到r0指向的内存地址中。也就是把0x32存到&sink[2]的地址中。该指令没有用STR而是用了STRH。这和c代码中的强制转换(short*)有关。因为把&sink[2]转换成了两个字节的short地址类型,所以在存数据到&sink[2]用的STRH存的是半字(half word)即16bit。
0x080010CA:把栈内的数据弹出到r3,把之前PUSH指令存储的链接地址(跳转到0x080010DA,但是实际的值是0x080010DB)直接弹出给PC寄存器,完成函数返回。栈指针SP = SP + 8,回收分配给foo函数的栈空间。函数接着从0x080010DA处运行。

结尾

示例1展示的是一个常规的函数调用过程,其中主要涉及到栈相关的操作。其实理解以后也并不是很难,但是却不是一个常用技能。面试过程中如果没有做这方面的准备,一时还是很难把问题把握好的。下一次将介绍递归的调用过程,尽力做一个小程序展现栈,寄存器的运行过程,这样能方便理解函数的运行过程。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351