大家好,如下所示,我有一段源代码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
总结起来,有如下几个问题:
在变量Btm和Stuff中间安插的4个Byte是什么?
程序运行时,栈上的变量布局是否总是与源码一致?
".L__const.main.Stuff"是什么,这看起来仿佛一个路径结构,那么,这个串的构成是否遵循某种规范?
".text"后到"main"之前的这段代码是什么?起怎样的作用?遵循怎样的语法?
补充信息:
编译器名称:x86_64-w64-mingw32-clang
编译器版本: 17.0.5
编译参数:-S -O0 -mllvm --x86-asm-syntax=intel
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2023-11-19 01:06
被mb_hkuiesml编辑
,原因: