为堆栈上的静态变量分配空间

时间:2014-07-10 11:51:33

标签: c stack buffer disassembly

以下代码包含8字节缓冲区。

void vuln() {
    char buffer[8];
    gets(buffer);
    printf("%s",buffer);
}

int main() {
    vuln();
    return 0;
}

因此,预计只为该缓冲区保留8个字节的堆栈。但反汇编显示保留了16个字节。

(gdb) 
Dump of assembler code for function vuln:
   0x000000000040057d <+0>:     push   %rbp
   0x000000000040057e <+1>:     mov    %rsp,%rbp
   0x0000000000400581 <+4>:     sub    $0x10,%rsp
   0x0000000000400585 <+8>:     lea    -0x10(%rbp),%rax
   0x0000000000400589 <+12>:    mov    %rax,%rdi
   0x000000000040058c <+15>:    callq  0x400480 <gets@plt>
   0x0000000000400591 <+20>:    lea    -0x10(%rbp),%rax
   0x0000000000400595 <+24>:    mov    %rax,%rsi
   0x0000000000400598 <+27>:    mov    $0x400644,%edi
   0x000000000040059d <+32>:    mov    $0x0,%eax
   0x00000000004005a2 <+37>:    callq  0x400450 <printf@plt>
   0x00000000004005a7 <+42>:    leaveq 
   0x00000000004005a8 <+43>:    retq   
End of assembler dump.

某些操作将根据自动脚本中堆栈上缓冲区的预期大小执行。但这使剧本瘫痪了。我可以知道为缓冲区分配16个字节的原因,以便我可以将其合并到脚本中吗?

3 个答案:

答案 0 :(得分:2)

x86-64 ELF psABI要求堆栈指针对齐:第3.2.2节(“堆栈帧”)说

  

...输入参数区域的末尾应在16字节边界上对齐。   换句话说,当控制时,值(%rsp - 8)总是16的倍数   转移到功能入口点。堆栈指针%rsp始终指向   最新分配的堆栈帧的结束。

您的函数在堆栈上分配8个字节,然后调用单参数函数gets;该函数的一个参数在寄存器中传递,因此为了保持ABI要求,编译器必须在进行函数调用之前将堆栈指针向下移动8个字节。

答案 1 :(得分:1)

@Zack所述,x86-64 ABI需要16字节堆栈对齐。如果您在x86或x86_64上使用gcc,则默认堆栈是16字节对齐。

来自gcc文档:

  

-mpreferred堆栈边界= NUM   尝试将堆栈边界保持对齐2到num字节边界。如果未指定-mpreferred-stack-boundary,则默认值为4(16字节或128位)。

https://gcc.gnu.org/onlinedocs/gcc/i386-and-x86-64-Options.html

如果SSE被禁用,请进一步查看文档gcc可能会将堆栈对齐到8个字节(因此违反了ABI要求)。

答案 2 :(得分:0)

您无法控制编译器在堆栈上执行的操作。您也无法控制堆栈上变量的顺序。编译器也允许引入填充,以便更好地对齐内存中的内容(尽管不在数组内部:这是严格禁止的)。在某些情况下,它甚至不会在堆栈上分配变量,而是在寄存器中分配变量。

如果您在装配级别有特定需求,请在装配中进行。