首页
社区
课程
招聘
未解决 [求助][C语言]栈上的变量布局问题
发表于: 2023-11-19 00:54 1992

未解决 [求助][C语言]栈上的变量布局问题

2023-11-19 00:54
1992

大家好,如下所示,我有一段源代码main.c:

#include <stdio.h>
#include <stdint.h>

typedef uint32_t U32;

int main() {

    U32 Btm = 0xDEADBEAF;
    U32 Stuff[4] = {0xFFF0FFFF,
                    0xFF0FFFFF,
                    0xF0FFFFFF,
                    0x0FFFFFFF};
    U32 Top = 0xDEADBEAF;

    for(U32* Ptr = &Btm; Ptr >= &Top; Ptr--){
        printf("0x%08X:0x%08X\n",Ptr,*Ptr);
    }

    return 0;
}

我希望借助这段程序观察C语言如何在内存中安排栈上的变量

学校里,《8086汇编》告诉我,栈中的变量从高地址向低地址增长

于是,我定义了栈顶变量Top,栈底变量Btm,并赋值为0xDEADBEAF.

然而,程序的运行结果和我的预期存在了差异


我预期看到:

0xF81BFA38:0xDEADBEAF // Btm

0xF81BFA34:0x0FFFFFFF

0xF81BFA30:0xF0FFFFFF

0xF81BFA2C:0xFF0FFFFF

0xF81BFA28:0xFFF0FFFF

0xF81BFA24:0xDEADBEAF // Top


但实际上的输出结果:

0xF81BFA38:0xDEADBEAF  //Btm

0xF81BFA34:0x00000000   //谜之数据

0xF81BFA30:0x00000001   //迷之数据

0xF81BFA2C:0x0FFFFFFF    //Stuff[3]

0xF81BFA28:0xF0FFFFFF    //Stuff[2]

0xF81BFA24:0xFF0FFFFF    //Stuff[1]

0xF81BFA20:0xFFF0FFFF    //Stuff[0]

0xF81BFA1C:0xDEADBEAF //Top


可以看到,实际运行中,在Btm和Stuff中间,多了8个Byte的谜之数据,这令我感到困惑

因此,我对main.c进行了汇编,得到main.S:


    .text
    .def   @feat.00;
    .scl   3;
    .type  0;
    .endef
    .globl @feat.00
.set @feat.00, 0
    .intel_syntax noprefix
    .file  "main.c"
    .def   main;
    .scl   2;
    .type  32;
    .endef
    .globl main                            # -- Begin function main
    .p2align   4, 0x90
main:                                   # @main
.seh_proc main
# %bb.0:
    push   rbp
    .seh_pushreg rbp
    sub    rsp, 80
    .seh_stackalloc 80
    lea    rbp, [rsp + 80]
    .seh_setframe rbp, 80
    .seh_endprologue
    call   __main
    mov    dword ptr [rbp - 4], 0          # 这是什么???
    mov    dword ptr [rbp - 8], -559038801 # imm = 0xDEADBEAF
    mov    rax, qword ptr [rip + .L__const.main.Stuff]
    mov    qword ptr [rbp - 32], rax
    mov    rax, qword ptr [rip + .L__const.main.Stuff+8]
    mov    qword ptr [rbp - 24], rax
    mov    dword ptr [rbp - 36], -559038801 # imm = 0xDEADBEAF
    lea    rax, [rbp - 8]
    mov    qword ptr [rbp - 48], rax
.LBB0_1:                                # =>This Inner Loop Header: Depth=1
    lea    rax, [rbp - 36]
    cmp    qword ptr [rbp - 48], rax
    jb .LBB0_4
# %bb.2:                                #   in Loop: Header=BB0_1 Depth=1
    mov    rdx, qword ptr [rbp - 48]
    mov    rax, qword ptr [rbp - 48]
    mov    r8d, dword ptr [rax]
    lea    rcx, [rip + .L.str]
    call   printf
# %bb.3:                                #   in Loop: Header=BB0_1 Depth=1
    mov    rax, qword ptr [rbp - 48]
    add    rax, -4
    mov    qword ptr [rbp - 48], rax
    jmp    .LBB0_1
.LBB0_4:
    xor    eax, eax
    add    rsp, 80
    pop    rbp
    ret
    .seh_endproc
                                        # -- End function
    .section   .rdata,"dr"
    .p2align   4, 0x0                          # @__const.main.Stuff
.L__const.main.Stuff:
    .long  4293984255                      # 0xfff0ffff
    .long  4279238655                      # 0xff0fffff
    .long  4043309055                      # 0xf0ffffff
    .long  268435455                       # 0xfffffff

.L.str:                                 # @.str
    .asciz "0x%08X:0x%08X\n"

    .addrsig
    .addrsig_sym printf

汇编得到的结果同样令我不解

对于数组的赋值,汇编器并没有实现为四句: mov dword ptr [rbp - offset], imm

并且,在Btm赋值之前,还安插了一个值为0的U32

此外,有若干语法我并没有在《8086汇编》上看到过,例如:

".LBB0_4:"

".L__const.main.Stuff:"

".L.str:"

.text
    .def   @feat.00;
    .scl   3;
    .type  0;
    .endef
    .globl @feat.00
.set @feat.00, 0
    .intel_syntax noprefix
    .file  "main.c"
    .def   main;
    .scl   2;
    .type  32;
    .endef
    .globl main

总结起来,有如下几个问题:

  1. 在变量Btm和Stuff中间安插的4个Byte是什么?

  2. 程序运行时,栈上的变量布局是否总是与源码一致?

  3. ".L__const.main.Stuff"是什么,这看起来仿佛一个路径结构,那么,这个串的构成是否遵循某种规范?

  4. ".text"后到"main"之前的这段代码是什么?起怎样的作用?遵循怎样的语法?

补充信息:

  1. 编译器名称:x86_64-w64-mingw32-clang

  2. 编译器版本: 17.0.5

  3. 编译参数:-S -O0 -mllvm --x86-asm-syntax=intel


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2023-11-19 01:06 被mb_hkuiesml编辑 ,原因:
收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 4984
活跃值: (2896)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
8086汇编 那是 8 位处理器的教材, 你现在 拿 64位 编译器来学习。编出来的是 64位的代码。 堆栈自然变化了。64位编译器 带自身的 默认 优化, 堆栈 按 8字节 对齐。
-48        &Btm                Ptr
-40        ??
-36        0xDEADBEAF        Top
-32        0xFFF0FFFF,     Stuff[0]
-28        0xFF0FFFFF,     Stuff[1]
-24        0xF0FFFFFF,     Stuff[2]
-20        0x0FFFFFFF,  Stuff[3]
-16        
-12
-08        0xDEADBEAF        Btm
-04        0

Btm 变成 8字节 扩展,高位添0, 对应   mov    dword ptr [rbp - 4], 0          # 这是什么???
数组 按照 16字节 对齐的地址开始, 这就是  //谜之数据 多出来的 原因
2023-11-20 00:22
0
游客
登录 | 注册 方可回帖
返回
//