打印

有谁知道 函数内部的局部变量汇编在哪里?

[复制链接]
3871|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
born|  楼主 | 2009-7-8 17:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
沙发
yoyofair| | 2009-7-8 17:34 | 只看该作者

貌似在栈里

ARM在栈里,不过C51好像把局部变量当全局变量来整的.

使用特权

评论回复
板凳
born|  楼主 | 2009-7-8 17:42 | 只看该作者

51的堆栈深度不够 吧

如果有个大局部变量 数组,  岂不要益出 了?

使用特权

评论回复
地板
ayb_ice| | 2009-7-8 21:14 | 只看该作者

取决于编译器

可能在堆栈中,可能是固定地址,还可能直接是寄存器...

使用特权

评论回复
5
zyboy| | 2009-7-9 10:34 | 只看该作者

这个问题有点意思,谈点自己想法

 我的测试环境KEIL(有感ARM中堆和栈的不同,感觉单片常说的堆栈好像只是栈,我下面叙述一律采用栈)

 我比较赞同yoyofair,但也不完全正确。因为如果我如果在函数体调用很少的变量,看反汇编,会发现它直接用的寄存器,如果临时变量比较大的话就会存储在RAM空间,没有用到栈。而在ARM中,临时变量比较大的时候,就放在栈中。
 这点有意思的地方,可能体现在函数重入上。在ARM下,函数的局部变量(如果不特别指定为static),函数都是可重入的。但在单片机下,函数的局部变量并不是存放在栈中,而是想全局变量一样存放在RAM空间,这样函数就不是可重入的。这一定区别体现在跑操作系统,或中断和主程序同时调用某函数上,这时候KEIL在C51下会提示告警,在ARM不会提示。KEIL还挺聪明的。所以我在编程序时候,一般要保证0警告(忽略警告有时候是很危险的!)。

但好像意识到这个问题,reentrant这个来帮忙,它可以模拟栈指针,这样函数就可以重入了。 

说了一堆,也是自己开发的想的,没什么理论根据,也没怎么深入。最近很烦躁,什么事也不想做,感觉自己就是个废物,哎。。。

使用特权

评论回复
6
ayb_ice| | 2009-7-9 20:58 | 只看该作者

KEIL这样做完全是为了提高程序的执行效率

任何MCU寻址直接地址都比寻址间接寻址效率要高,当然51也不大适合在堆栈中分配局部变量,但MCS251是完全高效支持标准C语言的,但KEIL默认仍然在固定地址中分配局部变量,当然也可以选择产生标准的C重入代码,这种做法可以非常高效的代码,其实底层应用重入用的不是很多,因为多数是与硬件打道,而硬件一般本身不可能重入,重入一般适合纯数学算法.

使用特权

评论回复
7
zyboy| | 2009-7-10 09:29 | 只看该作者

重入问题是值得注意的!

WARNING L15: MULTIPLE CALL TO SEGMENT(转--感觉讲的不错)

这个问题必须注意,可能引起程序冲突,假设你用于自动化领域,则可能导致信号产生尖峰。 产生这一警告的一个根源是:你在主循环里调用了一个函数(如aaa),而在中断服务函数里,你用调用了这个函数(如aaa)。这样当主循环运行到该函数中是,一旦产生中断,则在中断里又再次调用该函数!这时,很可能出错! 避免这种情况的方法很多:如,在进中断的时候置需调用该函数的标志,而在主循环中调用该函数
Keil C -WARNING L15: MULTIPLE CALL TO SEGMENT

1.第一种错误信息

***WARNING L15: MULTIPLE CALL TO SEGMENT
SEGMENT:   ?PR?_WRITE_GMVLX1_REG?D_GMVLX1
CALLER1:   ?PR?VSYNC_INTERRUPT?MAIN
CALLER2:   ?C_C51STARTUP

    该警告表示连接器发现有一个函数可能会被主函数和一个中断服务程序(或者调用中断服务程序的函数)同时调用,或者同时被多个中断服务程序调用。
    出现这种问题的原因之一是这个函数是不可重入性函数,当该函数运行时它可能会被一个中断打断,从而使得结果发生变化并可能会引起一些变量形式的冲突(即引起函数内一些数据的丢失,可重入性函数在任何时候都可以被ISR打断,一段时间后又可以
运行,但是相应数据不会丢失)。
    原因之二是用于局部变量和变量(暂且这样翻译,arguments,[自变量,变元一数值,用于确定程序或子程序的值])的内存区被其他函数的内存区所覆盖,如果该函数被中断,则它的内存区就会被使用,这将导致其他函数的内存冲突。
    例如,第一个警告中函数WRITE_GMVLX1_REG 在D_GMVLX1.C 或者D_GMVLX1.A51被定义,它被一个中断服务程序或者一个调用了中断服务程序的函数调用了,调用它的函数是VSYNC_INTERRUPT,在MAIN.C中。
解决方法:
    如果你确定两个函数决不会在同一时间执行(该函数被主程序调用并且中断被禁止),并且该函数不占用内存(假设只使用寄存器),则你可以完全忽略这种警告。
    如果该函数占用了内存,则应该使用连接器(linker)OVERLAY指令将函数从覆盖分析(overlay analysis)中除去,例如:
OVERLAY (?PR?_WRITE_GMVLX1_REG?D_GMVLX1 ! *)
   上面的指令防止了该函数使用的内存区被其他函数覆盖。如果该函数中调用了其他函数,而这些被调用在程序中其他地方也被调用,你可能会需要也将这些函数排除在覆盖分析(overlay analysis)之外。这种OVERLAY指令能使编译器除去上述警告信息。
   如果函数可以在其执行时被调用,则情况会变得更复杂一些。这时可以采用以下几种方法:
1.主程序调用该函数时禁止中断,可以在该函数被调用时用#pragma disable语句来实现禁止中断的目的。必须使用OVERLAY指令将该函数从覆盖分析中除去。
2.复制两份该函数的代码,一份到主程序中,另一份复制到中断服务程序中。
3.将该函数设为重入型。例如:
void myfunc(void) reentrant 
{
...
}

   这种设置将会产生一个可重入堆栈,该堆栈被被用于存储函数值和局部变量,用这种方法时重入堆栈必须在STARTUP.A51文件中配置。
这种方法消耗更多的RAM并会降低重入函数的执行速度。

使用特权

评论回复
8
arm_fan168| | 2009-7-10 18:15 | 只看该作者

问题很笼统

编译器不同,处理器种类不同,答案会很不一样。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

13

主题

100

帖子

1

粉丝