当前位置:  开发笔记 > 开发工具 > 正文

在ARM7TDMI上获取参数的地址时,GCC是否被破坏?

如何解决《在ARM7TDMI上获取参数的地址时,GCC是否被破坏?》经验,为你挑选了1个好方法。

我的C代码片段获取参数的地址并将其存储在易失性存储器位置(预处理代码):

void foo(unsigned int x) {
    *(volatile unsigned int*)(0x4000000 + 0xd4) = (unsigned int)(&x);
}

int main() {
    foo(1);
    while(1);
}

我使用SVN版本的GCC来编译这段代码.在函数结束时,foo我希望将值1存储在堆栈中,并且在0x40000d4指向该值的地址处.当我使用标志进行编译时没有进行优化时-O0,我得到了预期的ARM7TMDI程序集输出(为方便起见而注释):

        .align  2
        .global foo
        .type   foo, %function
foo:
        @ Function supports interworking.
        @ args = 0, pretend = 0, frame = 8
        @ frame_needed = 0, uses_anonymous_args = 0
        @ link register save eliminated.
        sub     sp, sp, #8
        str     r0, [sp, #4]     @ 3. Store the argument on the stack
        mov     r3, #67108864
        add     r3, r3, #212
        add     r2, sp, #4       @ 4. Address of the stack variable
        str     r2, [r3, #0]     @ 5. Store the address at 0x40000d4
        add     sp, sp, #8
        bx      lr
        .size   foo, .-foo
        .align  2
        .global main
        .type   main, %function
main:
        @ Function supports interworking.
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 0, uses_anonymous_args = 0
        stmfd   sp!, {r4, lr}
        mov     r0, #1           @ 1. Pass the argument in register 0
        bl      foo              @ 2. Call function foo
.L4:
        b       .L4
        .size   main, .-main
        .ident  "GCC: (GNU) 4.4.0 20080820 (experimental)"

它清楚地将参数存储在堆栈中,并从那里存储它0x40000d4.当我使用优化进行编译时-O1,我得到了一些意想不到的东西:

        .align  2
        .global foo
        .type   foo, %function
foo:
        @ Function supports interworking.
        @ args = 0, pretend = 0, frame = 8
        @ frame_needed = 0, uses_anonymous_args = 0
        @ link register save eliminated.
        sub     sp, sp, #8
        mov     r2, #67108864
        add     r3, sp, #4        @ 3. Address of *something* on the stack
        str     r3, [r2, #212]    @ 4. Store the address at 0x40000d4
        add     sp, sp, #8
        bx      lr
        .size   foo, .-foo
        .align  2
        .global main
        .type   main, %function
main:
        @ Function supports interworking.
        @ args = 0, pretend = 0, frame = 0
        @ frame_needed = 0, uses_anonymous_args = 0
        stmfd   sp!, {r4, lr}
        mov     r0, #1           @ 1. Pass the argument in register 0
        bl      foo              @ 2. Call function foo
.L4:
        b       .L4
        .size   main, .-main
        .ident  "GCC: (GNU) 4.4.0 20080820 (experimental)"

这次参数永远不会存储在堆栈中,即使堆栈中的某些内容仍然存储在堆栈中0x40000d4.

这只是预期/未定义的行为吗?我做错了什么或者我实际上发现了Compiler Bug™?



1> zaphod..:

一旦你返回foo(),x就会消失,任何指针都无效.随后使用这样的指针会导致C标准喜欢称之为"未定义的行为",这意味着绝对允许编译器假定您不会取消引用它,或者(如果您坚持要这样做)无需生成代码像你期望的那样远程做任何事情.如果你希望指针xfoo()返回后保持有效,你就不能x在foo的堆栈上分配期限 - 即使你原则上知道没有任何理由可以破坏它 - 因为在C中不允许这样做,无论多久发生一次你的期望.

最简单的解决方案可能是xmain()(或在任何其他函数中具有足够长寿的范围)中创建局部变量并将地址传递给foo.您还可以创建x一个全局变量,或者使用它在堆上分配它malloc(),或者以更奇怪的方式为它预留内存.您甚至可以尝试找出堆栈顶部的某些(希望)更便携的方式,并明确地将数据存储在堆栈的某些部分,如果您确定不需要其他任何东西而且您我确信这是你真正需要做的.但是,正如您所发现的那样,您一直使用的方法并不够可靠.

推荐阅读
无名有名我无名_593
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有