You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

栈上数组内存分配:分析两个C函数编译的x86-64汇编逻辑

Analysis of Stack Allocation for func1 and func2 in x86-64 GCC 7.3 (-O0)

Let's walk through exactly how GCC lays out the stack for these two functions. Since we're compiling with -O0 (no optimizations), the compiler generates straightforward, debug-friendly code that maps directly to your C source—no tricky reordering or optimizations to obscure what's happening.

Context First

We're working with:

  • GCC 7.3 x86-64
  • Ubuntu 16.04.1 x86-64
  • Compilation flags: -O0 -g (no optimizations, debug symbols enabled)

x86-64 uses a stack that grows downward (toward lower memory addresses), and -O0 ensures the compiler allocates stack space for every local variable exactly as declared, with minimal tweaks beyond alignment requirements.


Breakdown of func1

Your C code for func1 declares a single 2D array a[10][5] (50 bytes total, since each element is an unsigned char) plus the function parameter x.

Here's the assembly annotated to explain each step:

func1(unsigned char):
pushq %rbp          ; Save the old base pointer to the stack
movq %rsp, %rbp     ; Set the new base pointer (rbp = current stack top)
movl %edi, %eax     ; Copy the input parameter x (passed in %edi) to %eax
movb %al, -68(%rbp) ; Store the 1-byte x in the stack frame at offset -68 from rbp
movb $1, -64(%rbp)  ; Set a[0][0] = 1 — this is the first byte of array a
movb $2, -15(%rbp)  ; Set a[9][4] = 2 — this is the last byte of array a
nop                 ; Padding to align the stack frame to 16 bytes (x86-64 requirement)
popq %rbp           ; Restore the old base pointer
ret                 ; Return to the caller

Stack Layout for func1

  • The base pointer %rbp is our reference point for all stack variables.
  • -68(%rbp): Stores the function parameter x (1 byte, with 3 bytes of padding to maintain alignment).
  • -64(%rbp) to -15(%rbp): The 50-byte array a (since 64 - 15 = 49, plus the starting byte gives 50 total bytes).
  • The total stack frame size is 64 bytes, which aligns to the 16-byte x86-64 stack requirement.

Breakdown of func2

func2 adds a 10-byte array b[10] to the mix. Here's how this changes the stack layout, plus the full assembly we'd expect:

func2(unsigned char):
pushq %rbp          ; Same stack frame setup as func1
movq %rsp, %rbp
movl %edi, %eax
movb %al, -78(%rbp) ; x is now at -78 (10 bytes further from rbp than func1's x)
movb $1, -74(%rbp)  ; a[0][0] starts at -74 (shifted 10 bytes from func1)
movb $2, -25(%rbp)  ; a[9][4] ends at -25 (50 bytes total for a)
movb $4, -14(%rbp)  ; b[0] starts at -14 (10 bytes for b: -14 to -5)
movb $5, -5(%rbp)   ; b[9] is the last byte of array b
nop                 ; Optional padding if needed for 16-byte alignment
popq %rbp
ret

Key Differences Between func1 and func2

  • Larger stack frame: func2's stack frame is 10 bytes bigger than func1's, directly accounting for the extra b array.
  • Shifted variable offsets: Every variable in func2 is shifted 10 bytes away from %rbp (more negative offset) compared to func1. This is because -O0 allocates variables in declaration order: first x, then a, then b—so b gets placed at the lowest (most negative) address in the stack frame, pushing a and x up.
  • Extra initialization instructions: func2 has two additional movb lines to set b[0] and b[9], which are missing in func1.

Why This Behavior?

With -O0, GCC prioritizes debuggability over efficiency. It:

  • Allocates stack space for every local variable in the exact order they're written in your code.
  • Stores function parameters on the stack even though they're already in registers (so debuggers can easily access them).
  • Adds padding to ensure the entire stack frame is aligned to 16 bytes—a mandatory requirement for x86-64 function calls.

内容的提问来源于stack exchange,提问作者toozyfuzzy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:53:11