2015-06-29 2 views
1

Я компиляции ниже программы в C:Связаны ли переменные стека в виртуальной памяти?

void function(int a, int b, int c) { 
char buffer1[11]; 
char buffer2[3]; 
char buffer3[1]; 
char buffer4[1]; 
} 

void main() { 
function(1,2,3); 
} 

с помощью команды:

gcc -m32 -fno-asynchronous-unwind-tables -fno-stack-protector -S -o example1.s example1.c 

Ниже выход я получаю:

.file "example1.c" 
    .text 
    .globl function 
    .type function, @function 
function: 
    pushl %ebp 
    movl %esp, %ebp 
    subl $16, %esp 
    leave 
    ret 
    .size function, .-function 
    .globl main 
    .type main, @function 
main: 
    pushl %ebp 
    movl %esp, %ebp 
    pushl $3 
    pushl $2 
    pushl $1 
    call function 
    addl $12, %esp 
    leave 
    ret 
    .size main, .-main 
    .ident "GCC: (Ubuntu 4.9.2-10ubuntu13) 4.9.2" 
    .section .note.GNU-stack,"",@progbits 

Линия subl $ ,% esp указывает, что в стеке выделено 16 байт.

Однако, как и в разных учебниках, я вижу, что пространство стека обычно выделяется в блоках по 4 байта.

Почему поведение я вижу другим?

Я бегу 64 битной системы Ubuntu: -

vendor_id : GenuineIntel 
cpu family : 6 
model  : 58 
model name : Intel(R) Core(TM) i5-3210M CPU @ 2.50GHz 
stepping : 9 
microcode : 0x1b 
cpu MHz  : 1202.636 
cache size : 3072 KB 
physical id : 0 
siblings : 4 
core id  : 0 
cpu cores : 2 
apicid  : 0 
initial apicid : 0 
fpu  : yes 
fpu_exception : yes 
cpuid level : 13 
wp  : yes 
bugs  : 
bogomips : 4988.46 
clflush size : 64 
cache_alignment : 64 
address sizes : 36 bits physical, 48 bits virtual 
power management: 

Может кто-нибудь, пожалуйста, помогите мне понять это.

Я упомянув ниже вопрос: How is memory allocated for stack variables? , но мне не удалось найти конкретный ответ.

Редактировать: 1) Я хотел бы понять, должен ли общий стек просто выравниваться с границей 4/8/16 байтов или каждой переменной стека. 2) Есть ли какое-либо ограничение для типов локальных переменных, которые могут быть объединены в слово памяти стека?

+0

Не знаете, в чем проблема, вы объявили 16 байтов местных жителей, и вы получили 16 байт, что кратно 4.Да, компилятор может организовать местных жителей по своему усмотрению, а выравнивание для 'char' -' 1', чтобы они могли быть упакованы смежно. – Jester

+0

@Jester Я отредактировал вопрос. Не могли бы вы сейчас проверить – nkvp

+1

соглашение о вызове может потребоваться или потребовать, но я не думаю, что для набора инструкций требуется выравнивание. Эти выравнивания помогают производительности, а ebi для этого требует также, но в конце концов это конкретные параметры компилятора, версии, командной строки, независимо от того, что диктует генерируемый код. И нет причин, по которым любые два компилятора должны были бы сделать то же самое. –

ответ

2

Ответ заключается в том, что переменные стека не должны выделяться смежно. Во многих случаях они вряд ли будут.

Если у вас есть

{ 
    struct 
    { 
     int a ; 
     char b ; 
     double c ; 
     char d ; 
    } x, y, z; 
} 

Держу пари, большинство компиляторов не сделало бы х, у и г смежную.

В любом случае, то, что вы просите, полностью зависит от системы и компилятора. Компилятору вообще не нужно ставить автоматическую переменную в стек.

+0

Любая конкретная причина, почему gcc выделяет аналогичные типизированные переменные вместе? – nkvp

+0

В некоторой системе есть преимущество в производительности, так как для получения несвязанных данных требуется несколько циклов. В других системах неприглаженные обращения запрещены. – user3344003

3

«1) Я хотел бы понять, должен ли общий стек просто выравниваться с границей 4/8/16 бит или каждой переменной стека».

Это вопрос, связанный с машиной и компилятором. Как правило, переменные выравниваются в соответствии с их размером и размером слова процессора. Существует огромное преимущество для выравнивания 32-битных переменных на 32-битных границах на 32-разрядном ЦП, но нет никакой пользы для выравнивания 32-битных переменных на 8-битном ЦП, например 8051. 32-разрядный ЦП может обрабатывать 32-битные значения только как 32-битные значения, если они выровнены по 32-битной границе (0x ?? 0, 0x ?? 4, 0x ?? 8, 0x ?? c).

2) Существуют ли ограничения для типов локальных переменных, которые могут быть объединены в слово памяти стека?

Никаких ограничений, кроме выравнивания.

+0

Вот шаблон, который я вижу, - если я увеличиваю общее количество байтов до 17, тогда 32 байта выделяются в стеке. Это привело меня к выводу, что для gcc в 64-битных системах, когда скомпилировано с флагом -m32, не имеет значения, как локальные переменные выровнены, а общий размер стека будет в 16 раз. Насколько я понимаю? – nkvp

+0

Также существует какая-либо конкретная причина, по которой gcc с флагом -m32 не следует этому подходу выравнивания локальных переменных к границе 4/8/16 бит? – nkvp

+0

@nkvp Как в Windows, так и в Linux ABI требует, чтобы стек выравнивался по 16 ** байтам ** границ. На 32-битной машине такого требования нет, но стек обычно выравнивается (например, моя версия gcc по-прежнему выравнивает стек с 16-байтовой границей). ** обратите внимание, что вы объявили четыре массива, массивы должны быть непрерывными. Массив с 1 элементом char и один с 16 элементами char (на этой машине) возьмут некоторое пространство. Также, когда 16 байт «выделены» в стеке, это создает пространство для четырех 32-битных var или двух 64-битных var и т. Д. –

Смежные вопросы