Этот сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

Что происходит, когда main — переменная

Хочу провести работу над ошибками.

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

Напомню, речь идёт о программе, которая состоит из одного слова — main; или int main;, если забыть о стандарте Си89. Я думал дело в том, что попытка запустить программу приходит к чтению переменной и передаче управления на адрес ноль, но один читателей попенял, что в оригинальной статье указана другая причина.

Я решил глянуть получившийся ассемблер, чтобы разобраться где же правда. Для этого удобно использовать утилиту objdump:

objdump -D -d -M intel ./small

Оказалось, что я был неправ.

Чтобы это увидеть, надо посмотреть в ассемблерном листинге код, который вызывает функцию __libc_start_main() — она передаёт управление функции main(), указатель на которую указывается в регистре rdi. Как мы видим, адрес, записываемый в этот регистр указывает на секцию .data, код в которой запрещён к запуску, именно поэтому программа и падает.

Почему именно туда? Там хранятся все переменные, в том числе переменная main, то есть используется не адрес, записанный в этой переменной, как я думал раньше, а выполнение передаётся прямо на адрес, где хранится сама переменная.

Кстати, это означает, что на оборудовании, где защиты памяти нет или при запуске в реальном режиме (например, из-под DOS), программа может и не упасть — просто начнёт выполнять какой-то мусор, в котором вполне могут попасться инструкции корректного завершения.