Скорая Компьютерная Помощь г. Калуга

Полный спектр компьютерных услуг!

Здравствуйте, гость ( Вход | Регистрация )

> Внимание!

  • Вся информация, расположенная в данном и других разделах форума получена из открытых источников (интернет-ресурсы, средства массовой информации, печатные издания и т.п.) и/или добавлена самими пользователями. Администрация форума предоставляет его участникам площадку для общения / размещения файлов / статей и т.п. и не несет ответственности за содержание сообщений, а также за возможное нарушение авторских, смежных и каких-либо иных прав, которое может повлечь за собой информация, содержащаяся в сообщениях.
Ремонт компьютеров в калуге Рекламное место сдается
 
Ответить в эту темуОткрыть новую тему
> Linux для всех / [Из песочницы] Несколько подробностей о функции main
Decker
сообщение 13.9.2011, 12:29
Сообщение #1


Администратор
*****

Группа: Главные администраторы
Сообщений: 14349
Регистрация: 12.10.2007
Из: Twilight Zone
Пользователь №: 1



Однажды заинтересовался, содержимым стека функции 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 и Denwer [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
{0,0}


...




auxv[1]
Elf64_auxv_t
16


7.

auxv[0]
Elf64_auxv_t
16
Ex.: {0x0e,0x3e8}




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.

белое пятно
void*
240'



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.Белое пятно, что там находится науке пока неизвестно.

12.Переменные, объявленные в main

13.Аргументы функции main

14.Переменные и аргументы локальных функций.



Вспомогательный вектор.

Для i386 и x86_64 нельзя получить адрес первого элемента вспомогательного вектора, однако содержимое этого вектора можно получить другими способами. Один из них — обратиться к области памяти, лежащей сразу за массивом указателей на строки переменных окружения.

Это должно выглядеть примерно так:

#include <stdio.h>

#include <elf.h>

int main(int argc, char** argv, char** env){

Elf64_auxv_t *auxv; //x86_64

// Elf32_auxv_t *auxv; //i386



while(*env++ != NULL); //ищем начало вспомогательного вектора



for (auxv = (Elf64_auxv_t *)env; auxv->a_type != AT_NULL; auxv++){

printf("addr: %p type: %lx is: 0x%lxn", auxv, auxv->a_type, auxv->a_un.a_val);

}

printf("n (void*)(*argv) - (void*)auxv= %p - %p = %ldn (void*)(argv)-(void*)(&auxv)=%p-%p = %ldn ",

(void*)(*argv), (void*)auxv, (void*)(*argv) - (void*)auxv,

(void*)(argv), (void*)(&auxv), (void*)(argv) - (void*)(&auxv));

printf("n argc copy: %dn",*((int *)(argv - 1)));

return 0;

}



Структуры 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_)



Надеюсь, было интересно.

Удач.



Вся информация получена из нижеследующих материалов и с помощью gdb.

1. www.gelato.unsw.edu.au/IA64wiki/AuxiliaryVector

2. unixjunkie.blogspot.com/2006/02/char-apple-argument-vector.html

3. articles.manugarg.com/aboutelfauxiliaryvectors.html

4. www.phrack.org/issues.html?issue=58&id=5#article

5. unixforum.org/index.php?showtopic=94993&st=30

6. sources.redhat.com/ml/libc-alpha/2007-06/msg00108.html

7. linux-kernel/fs/binfmt_elf.c

8. /usr/include/elf.h
Original source: habrahabr.ru (comments, light).

Читать дальше


--------------------

Вернуться в начало страницы
 
+Ответить с цитированием данного сообщения

Ответить в эту темуОткрыть новую тему
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 

Рекламное место сдается Рекламное место сдается
Текстовая версия Сейчас: 13.5.2024, 9:58
Рейтинг@Mail.ru
Яндекс.Метрика Яндекс цитирования