汇编技术内幕(4)

发布者:sclibin最新更新时间:2015-12-22 来源: eefocus关键字:汇编技术  局部变量  栈分配 手机看文章 扫描二维码
随时随地手机看文章
两个以上的局部变量的栈分配

 程序如下:
    # vi test3.c
    int main()
    {
        int i, j=2, k=4;
        i=3;
        i=++i;
        k=i+j+k;
        return k;
    }

    编译该程序后,用mdb反汇编得出如下结果:
    # gcc test3.c -o test3   
    # mdb test3
    Loading modules: [ libc.so.1 ]
    > main::dis
    main:               pushl   %ebp
    main+1:             movl    %esp,%ebp    ; main至main+1,创建Stack Frame
    main+3:            subl   $0x18,%esp     ; 为局部变量i,j,k分配栈空间,并保证栈16字节对齐
    main+6:             andl    $0xf0,%esp
    main+9:             movl    $0,%eax
    main+0xe:           subl    %eax,%esp         ; main+6至main+0xe,再次保证栈16字节对齐
    main+0x10:          movl    $2,-8(%ebp)       ; j=2
    main+0x17:          movl    $4,-0xc(%ebp)     ; k=4
    main+0x1e:          movl    $3,-4(%ebp)       ; i=3
    main+0x25:          leal    -4(%ebp),%eax     ; 将i的地址装入到EAX
    main+0x28:          incl    (%eax)            ; i++
    main+0x2a:          movl    -8(%ebp),%eax     ; 将j的值装入到 EAX
    main+0x2d:          movl    -4(%ebp),%edx     ; 将i的值装入到 EDX
    main+0x30:          addl    %eax,%edx         ; j+i,结果存入EDX
    main+0x32:          leal    -0xc(%ebp),%eax   ; 将k的地址装入到EAX
    main+0x35:          addl    %edx,(%eax)       ; i+j+k,结果存入地址ebp-0xc即k中
    main+0x37:          movl    -0xc(%ebp),%eax   ; 将k的值装入EAX,作为返回值
    main+0x3a:          leave                     ; 撤销Stack Frame
    main+0x3b:          ret                       ; main函数返回
    >


    问题:为什么3个变量分配了0x18字节的栈空间?
    在2个变量的时候,分配栈空间的指令是:subl $8,%esp
    而在3个局部变量的时候,分配栈空间的指令是:subl $0x18,%esp
    3个整型变量只需要0xc字节,为何实际上分配了0x18字节呢?
    答案就是:保持16字节栈对齐。
    gcc默认的编译是要16字节栈对齐的,subl $8,%esp会使栈16字节对齐,而8字节空间只能满足2个局部变量,如果再分配4字节满足第3个局部变量的话,那栈地址就不再16字节对齐的,而同时满足空间需要而且保持16字节栈对齐的最接近的就是0x18。
    如果,各定义一个50字节和100字节的字符数组,在这种情况下,实际分配多少栈空间呢?答案是0x8+0x40+0x70,即184字节。
    下面动手验证一下:
    # vi test4.c
    int main()
    {
        char str1[50];
        char str2[100];
        return 0;
    }
    # mdb test4
    Loading modules: [ libc.so.1 ]
    > main::dis
    main:               pushl   %ebp
    main+1:             movl    %esp,%ebp
    main+3:            subl   $0xb8,%esp   ; 为两个字符数组分配栈空间,同时保证16字节对齐
    main+9:             andl    $0xf0,%esp
    main+0xc:           movl    $0,%eax
    main+0x11:          subl    %eax,%esp
    main+0x13:          movl    $0,%eax
    main+0x18:          leave
    main+0x19:          ret
    > 0xb8=D                              ; 16进制换算10进制
                    184            
    > 0x40+0x70+0x8=X                     ; 表达式计算,结果指定为16进制
                    b8             
    >


    问题:定义了多个局部变量时,栈分配顺序是怎样的?
    局部变量栈分配的顺序是按照变量声明先后的顺序,同一行声明的变量是按照从左到右的顺序入栈的,在test2.c中,变量声明如下:
        int i, j=2, k=4;
    而反汇编的结果中:
        movl    $2,-8(%ebp)          ; j=2
        movl    $4,-0xc(%ebp)        ; k=4
        movl    $3,-4(%ebp)          ; i=3
    其中不难看出,i,j,k的栈中的位置如下图:
 +----------------------------+------> 高地址
 | EIP (_start函数的返回地址)   |
 +----------------------------+
 | EBP (_start函数的EBP)       | <------ main函数的EBP指针(即SFP框架指针)
 +----------------------------+
 | i (EBP-4)                  |
 +----------------------------+
 | j (EBP-8)                  |
 +----------------------------+
 | k (EBP-0xc)                |
 +----------------------------+------> 低地址

关键字:汇编技术  局部变量  栈分配 引用地址:汇编技术内幕(4)

上一篇:汇编技术内幕(3)
下一篇:汇编技术内幕(5)

推荐阅读最新更新时间:2024-03-16 14:41

stm32局部变量过大,导致溢出
在做一个以stm32为主控的项目时发现自己程序中一个机构体里面的数据总是一运行就被改变,刚开始以为是自己不小心在哪个地方用了extern扩展了变量的作用域,重新赋了值, 自己忘记了,后来查找了好久都没有其他地方使用这个结构体变量,于是开始单步调试,结果进入一个函数的时候(里面定义了一个200个数据float型的数组),发现只要定了一个这个数组,这时前文提到的那个结构的值就发生改变,通过在keil软件中的Memory窗口查看结构体的变量可以清楚看到结构体的地址里面的数据在这个时候发生改变, 然后修改,这个局部变量数组的大小,把它改小之后,就没有发生问题。因为局部变量是储存在栈中的,于是猜想,这种问题应该是stm32的栈的内存的溢出造
[单片机]
stm32<font color='red'>局部变量</font>过大,导致<font color='red'>栈</font>溢出
labview局部变量与全局变量
之前做上位机就想拿一个停止键控制两个并行的循环,如下 那时候拿布尔里面的停止按钮做局部变量没有成功,会出现如下的错误(当时太匆忙没有解决) 现在找到解决办法了,前面板-停止控件-属性-操作-按钮动作,里面可以选择不同的触发方式,我试了下觉得保持转换直到释放用在这里比较不错。 今天还试了下全局变量(需要点击在弹出的前面板上放需要用到的变量),建好的全局变量在程序框图-函数-选择VI里面可选。可在前面板上放不同的控件(目前还没有需要,有需要时可以试试,放一个控件的试过了,还不错,不过简单的程序没必要) 不太使用全局变量的原因之一是效率低
[测试测量]
【STM32F0】Keil 查看局部变量显示
现象: 在进行STM32F0开发的时候出现了,调试代码,添加变量Watch时,显示not in scope。 处理方式: 因为代码开了优化的处理,把优化改到Level0,就可以解决问题。
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved