硬汉嵌入式论坛

 找回密码
 立即注册
查看: 3139|回复: 17
收起左侧

[有问必答] KEIL5.26编译问题

[复制链接]

1

主题

10

回帖

13

积分

新手上路

积分
13
发表于 2019-3-16 13:40:06 | 显示全部楼层 |阅读模式
最近编译工程时发现一个奇怪的现象,发到这里,看看有没有高手知道为什么
问题是:函数内的局部变量(结构体),在使用时,应该占用当前栈空间,
也就是说,进入函数后,会有一句类似"00008a  b093              SUB      sp,sp,#0x4c" 这样的语句,给局部变量申请空间
但出现问题时没有这句话,导致此变量占用的就是当前栈顶的空间,在进行结构体赋值时就会出现覆写栈空间,有可能导致函数返回错误
下面有2张图多下对比
下面是编译出现问题的:
       2.png

下面是编译正常的:
           

3.png



使用的是keil版本如下
1.png

这个是编译选项

4.png


回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107049
QQ
发表于 2019-3-16 14:03:36 | 显示全部楼层
帮你测试了,MDK生成的就是这样的,应该是xxx.txt文件并没有反应出全部细节
QQ截图20190316142344.jpg
回复

使用道具 举报

36

主题

2040

回帖

2148

积分

至尊会员

积分
2148
发表于 2019-3-16 14:33:57 | 显示全部楼层
直接调试状态查看几个变量的栈地址是否有分配,so easy
Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.
回复

使用道具 举报

1

主题

10

回帖

13

积分

新手上路

积分
13
 楼主| 发表于 2019-3-16 16:12:58 | 显示全部楼层
就是调试发现这样,所以才查看了这个文件
回复

使用道具 举报

36

主题

2040

回帖

2148

积分

至尊会员

积分
2148
发表于 2019-3-16 16:18:50 | 显示全部楼层
kksion 发表于 2019-3-16 16:12
就是调试发现这样,所以才查看了这个文件

不是让你看反汇编,是让你看local stack。。。
Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.
回复

使用道具 举报

1

主题

10

回帖

13

积分

新手上路

积分
13
 楼主| 发表于 2019-3-16 16:19:10 | 显示全部楼层
跟进去看的时候,会发现在调用GPIO_StructInit(&GPIO_InitStructure);时 直接传递的是当前堆栈指针
00000a  4668              MOV      r0,sp
00000c  f7fffffe          BL       GPIO_StructInit
这个在函数里会按照GPIO_InitStructure起始地址进行赋值,这样就有问题了
回复

使用道具 举报

36

主题

2040

回帖

2148

积分

至尊会员

积分
2148
发表于 2019-3-16 16:23:01 | 显示全部楼层
kksion 发表于 2019-3-16 16:19
跟进去看的时候,会发现在调用GPIO_StructInit(&GPIO_InitStructure);时 直接传递的是当前堆栈指针
00000a ...

兄dei,看local stack。。。,肯定没问题


你用IAR生成,IAR也是这样的,不信你试试
Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.
回复

使用道具 举报

1

主题

10

回帖

13

积分

新手上路

积分
13
 楼主| 发表于 2019-3-16 16:23:53 | 显示全部楼层
byccc 发表于 2019-3-16 16:18
不是让你看反汇编,是让你看local stack。。。

肯定分配了啊,上面可以看到地址就是SP的地址
我说的错误就是SP本身是从高地址->低地址,应该预先偏移出结构体的空间出来
而现在没有
回复

使用道具 举报

36

主题

2040

回帖

2148

积分

至尊会员

积分
2148
发表于 2019-3-16 16:27:31 | 显示全部楼层
kksion 发表于 2019-3-16 16:23
肯定分配了啊,上面可以看到地址就是SP的地址
我说的错误就是SP本身是从高地址->低地址,应该预先偏移出 ...

专业词汇叫向下生长的满栈

让你看local stack就是让你看地址分配到那里了,只是反汇编代码没有体现而已。。

你的明白?

Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.
回复

使用道具 举报

1

主题

10

回帖

13

积分

新手上路

积分
13
 楼主| 发表于 2019-3-16 16:37:49 | 显示全部楼层
byccc 发表于 2019-3-16 16:27
专业词汇叫向下生长的满栈

让你看local stack就是让你看地址分配到那里了,只是反汇编代码没有体现而 ...

你说的都是根据汇编生成的,你看好了第一张图是汇编
1.png
第二张图是你说的callstack 自己看看地址是不是一样
2.png
回复

使用道具 举报

36

主题

2040

回帖

2148

积分

至尊会员

积分
2148
发表于 2019-3-16 17:19:00 | 显示全部楼层
本帖最后由 byccc 于 2019-3-16 17:34 编辑
kksion 发表于 2019-3-16 16:37
你说的都是根据汇编生成的,你看好了第一张图是汇编

第二张图是你说的callstack 自己看看地址是不是一 ...

他就是通过简单的PUSH操作,来开辟的空间,你不服
QQ截图20190316171714.jpg
1.jpg






Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.
回复

使用道具 举报

1

主题

10

回帖

13

积分

新手上路

积分
13
 楼主| 发表于 2019-3-16 21:34:26 | 显示全部楼层
byccc 发表于 2019-3-16 17:19
他就是通过简单的PUSH操作,来开辟的空间,你不服

你跟我这杠什么? 写过汇编没有? PUSH保存的现场,传递当前SP作为结构体指针,地址空间正好相反。保存的信息被修改。我不服你能咋地?
回复

使用道具 举报

1

主题

10

回帖

13

积分

新手上路

积分
13
 楼主| 发表于 2019-3-16 21:35:38 | 显示全部楼层
kksion 发表于 2019-3-16 21:34
你跟我这杠什么? 写过汇编没有? PUSH保存的现场,传递当前SP作为结构体指针,地址空间正好相反。保存的 ...

当然,最终我知道为什么编译器出现这样的问题
回复

使用道具 举报

36

主题

1445

回帖

1553

积分

至尊会员

积分
1553
发表于 2019-3-16 21:51:48 | 显示全部楼层
kksion 发表于 2019-3-16 21:34
你跟我这杠什么? 写过汇编没有? PUSH保存的现场,传递当前SP作为结构体指针,地址空间正好相反。保存的 ...

我说这位大哥,你是来问问题的,你要是都懂,就不用在这里问了。别人回答你,是尊敬你,想帮助你。就算别人的答复没能帮你解决问题,你也不能以这个口气说话吧?
回复

使用道具 举报

36

主题

2040

回帖

2148

积分

至尊会员

积分
2148
发表于 2019-3-16 22:26:41 | 显示全部楼层
本帖最后由 byccc 于 2019-3-16 22:33 编辑
kksion 发表于 2019-3-16 21:34
你跟我这杠什么? 写过汇编没有? PUSH保存的现场,传递当前SP作为结构体指针,地址空间正好相反。保存的 ...

说你不服,你还就是不服,这个是MDK编译器的处理机制,你知道什么时候才需要寄存器入栈吗?

是你新进入的子函数里要用到这几个寄存器才需要入栈,你都用不到你入什么栈(而MDK反汇编这里就用了,跟你用SUB开辟空间一个道理),你再仔细看看你的子函数对应的汇编,完全没用到这几个寄存器,特别注意那个lr寄存器,这个地址是不会被改动的。只是用的r2,r3, r4

你用IAR测测,也是这个样子,今天非让你服了为止。

Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.
回复

使用道具 举报

36

主题

1445

回帖

1553

积分

至尊会员

积分
1553
发表于 2019-3-17 00:13:00 | 显示全部楼层
byccc 发表于 2019-3-16 22:26
说你不服,你还就是不服,这个是MDK编译器的处理机制,你知道什么时候才需要寄存器入栈吗?

是你新进 ...

牛掰
回复

使用道具 举报

1

主题

10

回帖

13

积分

新手上路

积分
13
 楼主| 发表于 2019-3-17 03:59:05 | 显示全部楼层
byccc 发表于 2019-3-16 22:26
说你不服,你还就是不服,这个是MDK编译器的处理机制,你知道什么时候才需要寄存器入栈吗?

是你新进 ...

子函数没用到就没有问题了?
void fun1()
{
    fun2();
}
1.子函数fun2() push r2-r4寄存器(的确fun2()里没调用)
2.fun2()里进行局部结构体赋值操作后,可以看到SP堆栈地址保存的r2-r4寄存器值已经改变
3.这个时候fun2()返回 pop r2-r4
4.这时 fun1()的r2-r4寄存器值已经改变
好,问题就在这!这个本来不应该发生,即调用fun2()返回后,所有寄存器值应该恢复成调用fun2()前,以防止这些寄存器在fun1()后面还要使用
======================================================
上面是我调试出的问题,但从实际使用角度确实没有出现什么异常,我没有仔细考量,应该是fun1()也没有使用这几个寄存器。从程序角度来说 这有风险。
当然这种情况不会导致函数返回地址异常,我问题提的不是很严谨
最后,上面有位朋友说的是,我的语气有点问题,在这里感谢你和版主对问题的回复
回复

使用道具 举报

36

主题

2040

回帖

2148

积分

至尊会员

积分
2148
发表于 2019-3-17 11:54:51 | 显示全部楼层
kksion 发表于 2019-3-17 03:59
子函数没用到就没有问题了?
void fun1()
{

这就是商业IDE策略,都让你们读懂了,还怎么卖钱。

你可以继续深入研究,开启各种优化等级,开启时间优化,又是一种玩法。
Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-16 02:19 , Processed in 0.225456 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表