x86-64汇编中为何使用25字节偏移量?
-25(%rbp) Appear in Unoptimized x86 Assembly Great question—this is a common point of confusion when first digging into unoptimized compiler output, so let's break this down clearly.
First, let's anchor on your compile flags: g++ -O0 -S -fno-stack-protector. The -O0 flag is the critical piece here—it disables all optimizations, telling the compiler to prioritize source code fidelity and debuggability over efficiency or clean stack layout. That means it won't rearrange, merge, or align variables for space savings; it just maps each local variable (and even temporary values generated during compilation) directly to a spot on the stack, exactly as they're declared in your C++ code.
1. leaq Doesn't Care About Alignment
First, let's clear up a misconception: the q suffix in leaq refers to the target register size (64-bit, since you're using %rax, a 64-bit register), not a requirement that the address itself is 8-byte aligned. leaq is purely an address-calculation instruction—it computes a memory address and stores it in a register, but it never actually accesses the memory at that address. Alignment rules only apply when you're reading/writing data from/to memory (like movq for 8-byte values, which does require aligned addresses). For a 1-byte char variable, even an odd address is perfectly valid, and leaq has no problem calculating it.
2. Unoptimized Stack Layout Is "Literal"
In -O0 mode, the compiler builds the stack frame exactly to match your code's variable declarations. Let's say your return_by_value.cpp has local variables like this:
char tiny_var; // 1 byte long long big_var; // 8 bytes int medium_var; // 4 bytes
The compiler will allocate stack space in that exact order (since it's not optimizing layout). Since the stack grows downward (toward lower memory addresses), the offsets from %rbp (the stack base pointer) would look something like:
big_varat-24(%rbp)(8-byte aligned, since it's an 8-byte type)tiny_vardirectly below it (toward lower addresses) at-25(%rbp)(1 byte, no alignment needed)medium_varwould be at an offset like-29(%rbp)(4 bytes belowtiny_var)
This is why you see adjacent offsets like -25 and -24—they're just neighboring variables of different sizes, placed exactly where the compiler declared them without any optimization to align or pack them.
3. No Optimization Means No Stack Cleanup
Unlike optimized builds (-O1 and above), -O0 doesn't try to round up stack sizes to 8-byte multiples or rearrange variables to fill gaps. It allocates exactly the space needed for each variable, even if that results in non-8-byte offsets. The only time alignment is enforced here is for individual variable types (e.g., a long long will still be placed at an 8-byte aligned offset), but smaller variables can sit right next to them, creating odd offsets.
内容的提问来源于stack exchange,提问作者Nibor

