Где хранятся статические значения в сборке - PullRequest
0 голосов
/ 12 февраля 2019

Вот простой код C

#include <stdio.h>

int a = 5;

static int b = 20;

int main(){

 int c = 30;

 return 0;
}

, скомпилированный для сборки без оптимизации:

    .section    __TEXT,__text,regular,pure_instructions
    .macosx_version_min 10, 13
    .globl  _main                   ## -- Begin function main
    .p2align    4, 0x90
_main:                                  ## @main
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    xorl    %eax, %eax
    movl    $0, -4(%rbp)
    movl    $30, -8(%rbp)
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function
    .section    __DATA,__data
    .globl  _a                      ## @a
    .p2align    2
_a:
    .long   5                       ## 0x5



Мой вопрос, где находится static int b = 20; в приведенной выше сборке?Я знаю, что они должны быть в глобальном разделе памяти, но я не могу найти его в скомпилированной версии.

Ответы [ 4 ]

0 голосов
/ 13 февраля 2019

Весь вопрос немного неточен ... (перечитывая его, вы на самом деле очень конкретны в отношении "в сборке выше" ... о, хорошо, тогда ответ "никуда" ... и остальная часть моего ответадля вопроса, который не был опубликован, но, надеюсь, объясняющего, почему «нигде» не является ответом на ваш вопрос).

У вас есть источник C, и затем вы показываете некоторую сборку в качестве вывода компилятора (но вы не указываете компилятор) и затем вы спрашиваете о сборке ...

C определяется на "абстрактной машине C", а вы смотрите на конкретную реализацию x86-64 такой абстрактной машины.

Хотя в этой реализации есть некоторые правила, в которых статические переменные обычно заканчиваются, это полностью зависит от компилятора - как он хочет их реализовать.

В чистой сборке (например,от руки, или с точки зрения процессора) нет такой вещи, как «статическое значение».У вас есть только регистры, память и периферийные устройства.

Таким образом, в Assembly (машинный код) вы можете использовать определенный регистр или определенную часть памяти в качестве статической переменной.В зависимости от того, что больше соответствует вашим потребностям (не существует жесткого правила, которое заставляло бы вас делать это каким-либо особым образом, за исключением того, что вы должны выразить свою идею в допустимом машинном коде для целевого ЦП, но это обычно означает, что существуют миллиарды возможностей и даже когдаограничивая себя только «разумными», это все же больше в сторону десятков возможных способов, чем только одного).

Вы можете (в x86-64) даже создать немного запутанную схему, как сохранить значение в виде кодасостояние («часть памяти» - это тогда память, занятая машинным кодом), то есть оно не будет напрямую записано в память как значение, но код будет следовать определенным путям кода (из многих возможных), чтобы получить правильный конечный результат,т.е. кодирование значения в самом коде.Есть, например, полный по Тьюрингу способ компилирования исходного кода C в машинный код x86-64 с использованием только инструкции mov, который, возможно, не использует память для статических переменных (не уверен, добавляет ли он раздел .data или избегает его путемкомпилировать его в код mov тоже, но из его явного существования должно быть совершенно очевидно, как теоретически можно избежать .data).

Таким образом, вы либо спрашиваете, как конкретный компилятор C с конкретными параметрами времени компиляцииреализует статические значения (и это может иметь несколько вариантов в зависимости от источника и используемых опций) ...

... или если вы действительно спрашиваете "где статические значения хранятся в сборке", тогда ответ «где угодно, если ваш машинный код действителен и корректен» , поскольку вся концепция «статического значения» имеет более высокий уровень, чем процессор, на котором она работает, так что это похоже на интерпретацию конкретной цели машинного кода«это статическое значение», но в CPU нет специальной инструкции / поддержки.

0 голосов
/ 12 февраля 2019

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

Чтобы ответить на вопрос заголовка:
Переменная не const статическая / глобальная переменная (т. Е. Статический класс хранения) с ненулевым инициализаторомбудет идти в .section .data, в отличие от .bss (изменяемый с нулевой инициализацией) или .rdata (Windows) / .rodata (Linux) для ненулевых данных только для чтения.


gcc не имеет полностью мозговой мертвецы, который транслитерирует в естественном виде. См. Отключите все параметры оптимизации в GCC - GCC всегда должен преобразовываться через свои внутренние представления.

GCC всегда делает проход, который пропускает неиспользованные вещи, даже на -O0. может быть способом отключить это, в отличие от некоторых других преобразований, которые gcc делает даже при -O0.

gcc и clang -O0 компилировать каждый оператор в отдельный блок asmкоторый хранит / перезагружает все ( для согласованной отладки ), но в этом блоке gcc по-прежнему применяет свои стандартные преобразования, например (x+y) < x становится y<0 для подписанных x и y с gcc8 и новее или x / 10 в кратный + сдвиг старшей половины.( Почему GCC использует умножение на странное число при реализации целочисленного деления? ).

И код внутри if(false) удаляется gcc даже при -O0, поэтому вы не можетеjump к нему в GDB.

Некоторым людям небезразлична производительность во время выполнения отладочных сборок, особенно разработчикам программного обеспечения реального времени, такого как игры или операционные системы, которое не может быть протестировано надлежащим образом, если оно работает слишком медленно.(Взаимодействие с людьми в играх или, возможно, драйверы устройств в ОС.)


Некоторые другие компиляторы более умны в -O0, поэтому вы часто видите asm, который выглядит даже болеекак исходные выражения.Я думаю, что видел MSVC без оптимизации, выдает инструкции, которые mov -посредственно попадают в регистр, затем cmp reg,imm, то есть выполняют ветвь во время выполнения, которая зависит только от немедленной, и, таким образом, может быть тривиально вычислена во время компиляции внутриэто выражение.

И, конечно, есть действительно неоптимизирующие компиляторы, цель которых - просто транслитерировать с фиксированными шаблонами.Например, Tiny C Compiler Я думаю, что это в значительной степени однопроходный и испускает asm (или машинный код), как это происходит.См. Сгенерированный код Tiny C Compiler испускает дополнительные (ненужные?) NOP и JMP показывает, насколько это просто: он всегда испускает sub esp, imm32 в прологах функций и возвращается только для немедленного заполнения вконец функции, когда он знает, какой объем стека нужен функции.Даже если ответ ноль, он не может удалить его и сжать код.


Обычно все равно интереснее смотреть на оптимизированный asm.Напишите функции, которые принимают аргументы и возвращают значение, чтобы вы могли видеть интересную часть ассемблера без большого количества шаблонной информации и шума хранения / перезагрузки. Как убрать "шум" из вывода сборки GCC / clang?

0 голосов
/ 12 февраля 2019

Статические переменные не сохраняются в памяти.Они появятся только при использовании. Например:

static int b = 20;c = c + b;

скомпилирует

add c, '20'

0 голосов
/ 12 февраля 2019

Если переменная static не оптимизирована компилятором, она перейдет в раздел данных процесса по умолчанию.

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

Стандарт C гласит в § 6.2.4 параграф 3:

Объект, идентификатор которого объявлен ... с хранилищемСпецификатор класса статический, имеет статическую длительность хранения.Его время жизни - это полное выполнение программы, и его сохраненное значение инициализируется только один раз, до запуска программы.

С помощью следующего кода:

static int a = 100;

int foo()
{
    return (a / 2);
}

Посмотрите, каксимвол _a появляется в сегменте _DATA для MSVC , строки 27-30 для GCC и строки 28-30 для Clang .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...