门户网站开发如何提高产品排名保定做网站建设
news/
2025/10/9 10:12:46/
文章来源:
门户网站开发如何提高产品排名,保定做网站建设,做百科发那些网站新闻好,登录wordpress数据库吗一.栈的整体作用 (1)保存现场/上下文 (2)传递参数:汇编代码调用c函数时#xff0c;需传递参数 (3)保存临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量。 二.为什么汇编代码调用c函数需要设置栈 之前看了很多关于uboot的分析#xff0c;其中就有说要为C语…一.栈的整体作用 (1)保存现场/上下文 (2)传递参数:汇编代码调用c函数时需传递参数 (3)保存临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量。 二.为什么汇编代码调用c函数需要设置栈 之前看了很多关于uboot的分析其中就有说要为C语言的运行准备好栈。而自己在Uboot的start.S汇编代码中关于系统初始化也看到有栈指针初始化这个动作。但是从来只是看到有人说系统初始化要初始化栈即正确给栈指针sp赋值但是却从来没有看到有人解释为何要初始化栈。所以接下来的内容就是经过一定的探究试图来解释一下为何要初始化栈。要明白这个问题首先要了解栈的作用。关于栈的作用要详细讲解的话要很长的篇幅所以此处只是做简略介绍。总的来说栈的作用就是保存现场/上下文传递参数保存临时变量 1.保存现场/上下文现场/上下文意思就相当于案发现场总有一些现场的情况要记录下来的否则被别人破坏掉之后你就无法恢复现场了。而此处说的现场就是指CPU运行的时候用到了一些寄存器比如r0,r1等等对于这些寄存器的值如果你不保存而直接跳转到子函数中去执行那么很可能就被其破坏了因为其函数执行也要用到这些寄存器。因此在函数调用之前应该将这些寄存器等现场暂时保持起来(入栈push)等调用函数执行完毕返回后(出栈pop)再恢复现场。这样CPU就可以正确的继续执行了。保存寄存器的值一般用的是push指令将对应的某些寄存器的值一个个放到栈中把对应的值压入到栈里面即所谓的压栈。然后待被调用的子函数执行完毕的时候再调用pop把栈中的一个个的值赋值给对应的那些你刚开始压栈时用到的寄存器把对应的值从栈中弹出去即所谓的出栈。其中保存的寄存器中也包括lr的值因为用bl指令进行跳转的话那么之前的pc的值是存在lr中的然后在子程序执行完毕的时候再把栈中的lr的值pop出来赋值给pc这样就实现了子函数的正确的返回。 2.传递参数C语言进行函数调用的时候常常会传递给被调用的函数一些参数对于这些C语言级别的参数被编译器翻译成汇编语言的时候就要找个地方存放一下并且让被调用的函数能够访问否则就没发实现传递参数了。对于找个地方放一下分两种情况。一种情况是本身传递的参数不多于4个就可以通过寄存器传送参数。因为在前面的保存现场的动作中已经保存好了对应的寄存器的值那么此时这些寄存器就是空闲的可以供我们使用的了那就可以放参数。另一种情况是参数多于4个时寄存器不够用就得用栈了。 3.临时变量保存在栈中 包括函数的非静态局部变量以及编译器自动生成的其他临时变量。 4.举例分析C语言函数调用是如何使用栈的对于上面的解释的栈的作用显得有些抽象此处再用例子来简单说明一下就容易明白了用:arm-inux-objdump–d u-boot dump_u-boot.txt可以得到dump_u-boot.txt文件。该文件就是中包含了u-boot中的程序的可执行的汇编代码其中我们可以看到C语言的函数的源代码到底对应着那些汇编代码。下面贴出两个函数的汇编代码一个是clock_init另一个是与clock_init在同一C源文件中的另外一个函数CopyCode2Ram33d0091cCopyCode2Ram:33d0091c: e92d4070 push {r4, r5, r6, lr}33d00920: e1a06000 mov r6, r033d00924: e1a05001 mov r5, r133d00928: e1a04002 mov r4, r233d0092c: ebffffef bl 33d008f0 bBootFrmNORFlash......33d00984: ebffff14 bl 33d005dc nand_read_ll......33d009a8: e3a00000 mov r0, #0 ; 0x033d009ac: e8bd8070 pop {r4, r5, r6, pc}33d009b0clock_init:33d009b0: e3a02313 mov r2, #1275068416 ;0x4c00000033d009b4: e3a03005 mov r3, #5 ; 0x533d009b8: e5823014 str r3, ......33d009f8: e1a0f00e mov pc, lr1clock_init部分的代码可以看到该函数第一行33d009b0: e3a02313 mov r2, #1275068416 ;0x4c000000就没有我们所期望的push指令没有去将一些寄存器的值放到栈中。这是因为我们clock_init这部分的内容所用到的r2,r3等等寄存器和前面调用clock_init之前所用到的寄存器r0没有冲突所以此处可以不用push去保存这类寄存器的值不过有个寄存器要注意那就是r14即lr其是在前面调用clock_init的时候用的是bl指令所以会自动把跳转时候的pc的值赋值给lr所以也不需要push指令去将PC的值保存到栈中。而clock_init的代码的最后一行:33d009f8:e1a0f00e mov pc, lr就是我们常见的movpc,lr把lr的值即之前保存的函数调用时候的PC值赋值给现在的PC这样就实现了函数的正确的返回即返回到了函数调用时候下一个指令的位置。这样CPU就可以继续执行原先函数内剩下那部分的代码了。2CopyCode2Ram部分的代码其第一行33d0091c:e92d4070 push {r4, r5, r6, lr}就是我们所期望的用push指令保存了r4,r5,r以及lr。用push去保存r4,r5,r6那是因为所谓的保存现场以后后续函数返回时候再恢复现场而用push去保存lr那是因为此函数里面还有其他函数调用33d0092c: ebffffef bl 33d008f0 bBootFrmNORFlash......33d00984: ebffff14 bl 33d005dc nand_read_ll......也用到了bl指令会改变我们最开始进入clock_init时候的lr的值所以我们要用push也暂时保存起来。而对应地CopyCode2Ram的最后一行33d009ac:e8bd8070 pop {r4, r5, r6,pc}就是把之前push的值给pop出来还给对应的寄存器其中最后一个是将开始push的lr的值pop出来给赋给PC因为实现了函数的返回。另外我们注意到在CopyCode2Ram的倒数第二行是33d009a8:e3a00000 mov r0, #0 ;0x0是把0赋值给r0寄存器这个就是我们所谓返回值的传递是通过r0寄存器的。此处的返回值是0也对应着C语言的源码中的“return0”.对于使用哪个寄存器来传递返回值当然你也可以用其他暂时空闲没有用到的寄存器来传递返回值但是这些处理方式本身是根据ARM的APCS的寄存器的使用的约定而设计的你最好不要随便改变使用方式最好还是按照其约定的来处理这样程序更加符合规范。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/932396.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!