Linux минимально работоспособные примеры с анализом дизассемблирования
Поскольку это детали реализации, не указанные стандартами, давайте просто посмотрим, что делает компилятор в конкретной реализации.
В этом ответе я либо сошлюсь на конкретные ответы, которые делают анализ, либо предоставлю анализ прямо здесь, и суммирую все результаты здесь.
Все они представлены в различных версиях Ubuntu / GCC, и результаты, вероятно, довольно стабильны во всех версиях, но если мы найдем какие-либо варианты, давайте уточним более точные версии.
Локальная переменная внутри функции
Будь то main
или любая другая функция:
void f(void) {
int my_local_var;
}
Как показано на: Что означает <value optimized out> в gdb?
-O0
: stack
-O3
: регистрирует, если они не проливаются, укладываются иначе
Чтобы узнать, почему стек существует, смотрите: Какова функция инструкций push / pop, используемых для регистров в сборке x86?
Глобальные переменные и static
функциональные переменные
/* BSS */
int my_global_implicit;
int my_global_implicit_explicit_0 = 0;
/* DATA */
int my_global_implicit_explicit_1 = 1;
void f(void) {
/* BSS */
static int my_static_local_var_implicit;
static int my_static_local_var_explicit_0 = 0;
/* DATA */
static int my_static_local_var_explicit_1 = 1;
}
- если инициализирован
0
или не инициализирован (и, следовательно, неявно инициализирован 0
):.bss
section, см. также: Почему требуется сегмент .bss?
- иначе:
.data
раздел
char *
и char c[]
Как показано на: Где хранятся статические переменные в C и C ++?
void f(void) {
/* RODATA / TEXT */
char *a = "abc";
/* Stack. */
char b[] = "abc";
char c[] = {'a', 'b', 'c', '\0'};
}
TODO будут помещать в стек очень большие строковые литералы? Или.data
? Или компиляция не удалась?
Аргументы функции
void f(int i, int j);
Должны пройти соответствующее соглашение о вызовах, например: https://en.wikipedia.org/wiki/X86_calling_conventions для X86, в котором указываются либо конкретные регистры, либо места в стеке для каждой переменной.
Тогда, как показано в разделе Что означает <value optimized out> в gdb? , -O0
То хлебает все в стек, в то время как-O3
пытается максимально использовать регистры.
Однако, если функция встроена, они обрабатываются как обычные локальные.
const
Я полагаю, что это не имеет значения, потому что вы можете настроить его.
И наоборот, если компилятор может определить, что некоторые данные никогда не записываются, он теоретически может поместить их, .rodata
даже если не const.
Анализ ТОДО.
указатели
Они являются переменными (которые содержат адреса, которые являются числами), так же, как и все остальные :-)
таНос
Вопрос не имеет особого смысла malloc
, так как malloc
является функцией, и в:
int *i = malloc(sizeof(int));
*i
переменная, которая содержит адрес, поэтому она попадает в приведенный выше случай.
Что касается того, как malloc работает внутренне, когда вы называете его ядром Linux, он помечает определенные адреса как доступные для записи в своих внутренних структурах данных, и когда программа касается их изначально, происходит сбой, и ядро активирует таблицы страниц, что дает доступ без segfaul: как работает подкачка x86?
Однако обратите внимание, что это в основном именно то, что exec
делает системный вызов под капотом, когда вы пытаетесь запустить исполняемый файл: он отмечает страницы, на которые он хочет загрузить, и записывает туда программу, см. Также: Как ядро получает исполняемый двоичный файл, работающий под линукс? За исключением того, что exec
имеет некоторые дополнительные ограничения на то, куда загружать (например, если код не перемещается ).
Точный системный вызов используется для malloc
это mmap
в современных реализациях 2020, а в прошлом brk
был использован: Имеет ли таНос () использование битый () или ММАП ()?
Динамические библиотеки
Как правило, получить mmap
доступ к памяти: /unix/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710
переменные окружения и main
sargv
Выше начального стека: /unix/75939/where-is-the-environment-string-actual-stored TODO, почему не в .data?