Несколько подробностей о функции main
Однажды заинтересовался, содержимым стека функции main процесса в linux. Провел некоторые изыскания и теперь представляю вам результат.
Варианты описания функции main:
1. int main()
2. int main(int argc, char **argv)
3. int main(int argc, char **argv, char **env)
4. int main(int argc, char **argv, char **env, ElfW(auxv_t) auxv[])
5. int main(int argc, char **argv, char **env, char **apple)
argc — число параметров
argv — нуль-терминальный массив указателей на строки параметров командной строки
env — нуль-терминальный массив указателей на строки переменных окружения. Каждая строка в формате ИМЯ=ЗНАЧЕНИЕ
auxv — массив вспомогательных значение (доступно только для PowerPC [1])
apple — путь к исполняемому файлу (в MacOS и Darwin [2])
Вспомогательный вектор — массив с различной дополнительной информацией, такой как эффективный идентификатор пользователя, признак setuid бита, размер страницы памяти и т.п.
Далее о том как получить массив вспомогательных значений для i386 и x86_64, а также об остальном содержимом «сегмента» стека.
Размер сегмента стека можно глянуть в файле maps:
cat /proc/10918/maps
…
7ffffffa3000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
…
Перед тем, как загрузчик передаст управление в main, он инициализирует содержимое массивов параметров командной строки, переменных окружения, вспомогательный вектор.
После инициализации верхняя часть стека выглядит примерно так, для 64битной версии.
Старший адрес сверху.
| 1. | 0x7ffffffff000 | Верхняя точка сегмента стека. Обращение вызывает segfault | |||
| 0x7ffffffff0f8 | NULL | void* | 8 | 0x00′ | |
| 2. | filename[0] | char | 1+ | «/tmp/a.out» | |
| char | 1 | 0x00 | |||
| . | |||||
| env[1][0] | char | 1 | 0x00 | ||
| . | |||||
| char | 1 | 0x00 | |||
| 3. | 0x7fffffffe5e0 | env[0][0] | char | 1 | .. |
| char | 1 | 0x00 | |||
| . | |||||
| argv[1][0] | char | 1 | 0x00 | ||
| . | |||||
| char | 1 | 0x00 | |||
| 4. | 0x7fffffffe5be | argv[0][0] | char | 1+ | «/tmp/a.out» |
| 5. | Массив случайной длины | ||||
| 6. | данные для auxv | void*[] | 48′ | ||
| AT_NULL | Elf64_auxv_t | 16 | |||
| . | |||||
| auxv[1] | Elf64_auxv_t | 16 | |||
| 7. | auxv[0] | Elf64_auxv_t | 16 | Ex.: | |
| NULL | void* | 8 | 0x00 | ||
| . | |||||
| env[1] | char* | 8 | |||
| 8. | 0x7fffffffe308 | env[0] | char* | 8 | 0x7fffffffe5e0 |
| NULL | void* | 8 | 0x00 | ||
| . | |||||
| argv[1] | char* | 8 | |||
| 9. | 0x7fffffffe2f8 | argv[0] | char* | 8 | 0x7fffffffe5be |
| 10. | 0x7fffffffe2f0 | argc | long int | 8′ | число аргументов + 1 |
| 11. | Локальные переменные и аргументы, функций вызываемых до main | ||||
| 12. | Локальные переменные main | ||||
| 13. | 0x7fffffffe1fc | argc | int | 4 | число аргументов + 1 |
| 0x7fffffffe1f0 | argv | char** | 8 | 0x7fffffffe2f8 | |
| 0x7fffffffe1e8 | env | char** | 8 | 0x7fffffffe308 | |
| 14. | Переменные локальных функций | ||||
‘ — описания полей в документах не нашел, но в дампе явно видны.
Для 32 битов не проверял, но скорее всего достаточно только разделить размеры на два.
1. Обращение к адресам, выше верхней точки, вызывает Segfault.
2. Строка, содержащая путь к исполняемому файлу.
3. Массив строк с переменными окружения
4. Массив строк с параметрами командной строки
5. Массив случайной длинны. Его выделение можно отключить командами
sysctl -w kernel.randomize_va_space=0
echo 0 > /proc/sys/kernel/randomize_va_space
6. Данные для вспомогательного вектора (например строка «x86_64»)
7. Вспомогательный вектор. Подробнее ниже.
8. Нуль-терминальный массив указателей на строки переменных окружения
9. Нуль-терминальный массив указателей на строки параметров командной строки
10.Машинное слово, содержащее число параметров командной строки (один из аргументов «старших» функций см. п. 11)
11.Локальные переменные и аргументы, функций вызываемых до main(_start,__libc_start_main..)
12.Переменные, объявленные в main
13.Аргументы функции main
14.Переменные и аргументы локальных функций.
Вспомогательный вектор
Для i386 и x86_64 нельзя получить адрес первого элемента вспомогательного вектора, однако содержимое этого вектора можно получить другими способами. Один из них — обратиться к области памяти, лежащей сразу за массивом указателей на строки переменных окружения.
Это должно выглядеть примерно так:
Структуры Elf<32,64>_auxv_t описаны в /usr/include/elf.h. Функции заполнения структур в linux-kernel/fs/binfmt_elf.c
Второй способ получить содержимое вектора:
hexdump /proc/self/auxv
Самый удобочитаемое представление получается установкой переменной окружения LD_SHOW_AUXV.
LD_SHOW_AUXV=1 ls
AT_HWCAP: bfebfbff //возможности процессора
AT_PAGESZ: 4096 //размер страницы памяти
AT_CLKTCK: 100 //частота обновления times()
AT_PHDR: 0x400040 //информация о заголовке
AT_PHENT: 56
AT_PHNUM: 9
AT_BASE: 0x7fd00b5bc000 //адрес интерпретатора, то бишь ld.so
AT_FLAGS: 0x0
AT_ENTRY: 0x402490 //точка входа в программу
AT_UID: 1000 //идентификаторы пользователя и группы
AT_EUID: 1000 //номинальные и эффективные
AT_GID: 1000
AT_EGID: 1000
AT_SECURE: 0 //поднят ли setuid флаг
AT_RANDOM: 0x7fff30bdc809 //адрес 16 случайных байт,
генерируемых при запуске
AT_SYSINFO_EHDR: 0x7fff30bff000 //указатель на страницу, используемую для
//системных вызовов
AT_EXECFN: /bin/ls
AT_PLATFORM: x86_64
Слева — название переменной, справа значение. Все возможные названия переменных и их описание можно глянуть в файле elf.h. (константы с префиксом AT_)
Возвращение из main()
После инициализации контекста процесса управление передается не в main(), а в функцию _start().
main() вызывает уже из __libc_start_main. Эта последняя функция имеет интересную особенность — ей передается указатель на функцию, которая должна быть выполнена после main(). И указатель этот передается естественно через стек.
Вообще аргументы __libc_start_main имеют вид, согласно файла glibc-2.11/sysdeps/ia64/elf/start.S
/*
* Arguments for __libc_start_main:
* out0: main
* out1: argc
* out2: argv
* out3: init
* out4: fini //функция вызываемая после main
* out5: rtld_fini
* out6: stack_end
*/
Т.е. чтобы получить адрес указателя fini нужно сместиться на два машинных слова от последней локальной переменной main.
Вот что получилось(работоспособность зависит от версии компилятора):
Main что это
в основном in the
главная часть;
основное
главный;
основной;
the main features основные черты;
main line главная железнодорожная линия, магистраль
поэт. открытое море, океан
хорошо развитой, сильный (физически)
число очков, которое играющий в кости называет перед броском the
главный;
основной;
the main features основные черты;
main line главная железнодорожная линия, магистраль
главный;
основной;
the main features основные черты;
main line главная железнодорожная линия, магистраль the
point главный пункт;
main dressing station воен. главный перевязочный пункт point: main
главный пункт повестки дня main = mainmast mainmast: mainmast мор. грот-мачта
Большой англо-русский и русско-английский словарь . 2001 .
Полезное
Смотреть что такое «main» в других словарях:
main — main … Dictionnaire des rimes
MAIN — La main, organe de préhension et récepteur sensitif important, est l’apanage des Primates et de l’homme. En vérité, la main humaine possède une signification particulière, car elle se trouve à l’extrémité du membre supérieur qui est libéré des… … Encyclopédie Universelle
Main — Karte des Mainverlaufs Daten Gewässerkennzahl … Deutsch Wikipedia
main — Main, f. monosyl. Manus. l Espagnol et l Italien le disent de mesmes, Mano. La main dextre, Dextera, vel Dextra. La main senestre ou gauche, Laeua, Sinistra. Main chargée et pleine de quelque chose, Grauis manus. La main est toute engourdie et… … Thresor de la langue françoyse
Main FM — Allgemeine Informationen Empfang früher: analog terrestrisch, Kabel … Deutsch Wikipedia
Main — (m[=a]n), a. [From
Main — Main, n. [AS. m[ae]gen strength, power, force; akin to OHG. magan, Icel. megin, and to E. may, v. [root]103. See
Main — der; [e]s: rechter Nebenfluss des Rheins. * * * I Main [dt. »Haupt «], die Hauptfunktion in einem C bzw. C++ Programm (C, C++). Jedes C bzw. C++ Programm muss genau eine solche Funktion enthalten, von der ausgehend der weitere Ablauf des Progr … Universal-Lexikon
main — [mān] n. [ME < OE mægen, akin to ON magn: see MIGHT2] 1. physical strength; force; power: now only in with might and main, with all one s strength, with all one s strength 2. [< MAIN the adj.] the principal or most important part or point:… … English World dictionary
main — ► ADJECTIVE ▪ chief in size or importance. ► NOUN 1) a principal water or gas pipe or electricity cable. 2) (the mains) Brit. public water, gas, or electricity supply through pipes or cables. 3) (the main) archaic or literary the open ocean … English terms dictionary
main — (m[=a]n), n. [F. main hand, L. manus. See
Main что это
![]()
Откройте возможности нейронного машинного перевода PROMT
PROMT.One — это облачное приложение – бесплатный онлайн-переводчик для перевода с языка на язык на основе нейронных сетей (Neural Machine Translation), словарь с транскрипцией, разговорники и многое другое. Наслаждайтесь правильным и точным переводом на английский, немецкий и еще 20+ языков.
Смотрите перевод слов и устойчивых выражений, транскрипцию и произношение в онлайн cловаре. Словари PROMT для английского, немецкого, французского, русского, испанского, итальянского и португальского языков включают миллионы слов и словосочетаний, самую современную разговорную лексику, которая постоянно отслеживается и пополняется нашими лингвистами.
Учите употребление слов и выражений в разных Контекстах. Миллионы реальных примеров на английском, немецком, испанском, французском помогут вам в изучении иностранных языков и подготовке домашних заданий.
Переводите в любом месте и в любое время с помощью бесплатного мобильного переводчика PROMT.One для iOS и Android. Попробуйте голосовой и фотоперевод.
Установите языковые пакеты для офлайн-перевода на мобильных устройствах и универсальный плагин PROMT АГЕНТ для Windows с подпиской PREMIUM.