为什么编译器在堆栈中分配的不仅仅是需要的?

时间:2016-06-12 04:32:16

标签: c memory compiler-construction stack allocation

我有一个简单的C程序。比方说,我有一个长度为20的int和一个char数组。我需要总共24个字节。

var htmlToText = require('html-to-text');
var jade = require('jade');

const jadeTemplate = `doctype html
html(lang="en")
  head
    title= pageTitle
    script(type='text/javascript').
      if (foo) {
         bar(1 + 5)
      }
  body
    h1 Jade - node template engine
    #container.col
      if youAreUsingJade
        p You are amazing
      else
        p Get on it!
      p.
        Jade is a terse and simple
        templating language with a
        strong focus on performance
        and powerful features.`;





var html = jade.compile(jadeTemplate, {})({});
var text = htmlToText.fromString(html, {
    wordwrap: 130
});



document.getElementById('text').value = text;

堆栈需要与16字节边界对齐,所以我假设编译器将保留32个字节。但是当我使用gcc x86-64编译这样的程序并读取输出程序集时,编译器会保留64个字节。

int main()
{
   char buffer[20];
   int x = 0;
   buffer[0] = 'a';
   buffer[19] = 'a';
}

给我:

..\gcc -S -o main.s main.c

为什么?当我编程程序集时,我总是只保留我需要的最小内存而没有任何问题。这是编译器的限制,它在评估所需的内存时有困难,还是有原因?

这是gcc -v

    .file   "main.c"
    .def    __main; .scl    2;  .type   32; .endef
    .text
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
    pushq   %rbp                        # RBP is pushed, so no need to reserve more for it
    .seh_pushreg    %rbp
    movq    %rsp, %rbp
    .seh_setframe   %rbp, 0
    subq    $64, %rsp                   # Reserving the 64 bytes
    .seh_stackalloc 64
    .seh_endprologue
    call    __main
    movl    $0, -4(%rbp)                # Using the first 4 bytes to store the int
    movb    $97, -32(%rbp)              # Using from RBP-32 
    movb    $97, -13(%rbp)              # to RBP-13 to store the char array
    movl    $0, %eax
    addq    $64, %rsp                   # Restoring the stack with the last 32 bytes unused
    popq    %rbp
    ret
    .seh_endproc
    .ident  "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 5.2.0"

3 个答案:

答案 0 :(得分:6)

编译器确实可以为自己保留额外的内存。

Gcc有一个标志-mpreferred-stack-boundary,用于设置它将保持的对齐方式。根据{{​​3}},默认值为4,它应该产生16字节对齐,这是SSE指令所需的。

作为the documentation,您应该提供您的gcc版本和编译时选项(使用gcc -v来显示这些选项)。

答案 1 :(得分:4)

因为您尚未启用优化。

如果没有优化,编译器不会尝试最小化生成代码中任何内容所需的空间或时间 - 它只是以最直接的方式生成代码。

如果您希望编译器生成合适的代码,请添加-O2(或者甚至只是-O1)或-Os

答案 2 :(得分:-2)

  

我总共需要24个字节。

编译器需要空间用于返回地址和基指针。当你处于64位模式时,那又是16个字节。总计40.将该数据舍入到32字节的边界,然后得到64。