URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 1699
[ Назад ]

Исходное сообщение
"Как получить адрес программы в оперативной памяти?"

Отправлено retro , 21-Май-03 14:46 
Подскажите, пжста, как можно получить адрес текущий программы, написанной на си (адрес исполняемого файла)?

Содержание

Сообщения в этом обсуждении
"Как получить адрес программы в оперативной памяти?"
Отправлено Olej , 21-Май-03 15:56 
>Подскажите, пжста, как можно получить адрес текущий программы, написанной на си (адрес исполняемого файла)?

Не очень понятен вопрос... Но, скорее всего - ответ такой: "никак"!
От OS зависит, но если это 32-бит многозадачная OS в виртуализацией и т.д. ... то все программы будут начинаться с одного и того-же стартового адреса. Это если говорить об логических адресах.

А если об физических (адрес в чипе RAM) то тут совсем ... приехали.
Адрес "начала" может быть, напр. 0хсссссс (кстати, адрес "конца" - вполне может быть 0хbbbb00), но, пока мы это определили ... он уже стал 0x00aaaa! И это даже если образ программы "невыгружаемый", т.е. без виртуализации через диск.


"Как получить адрес программы в оперативной памяти?"
Отправлено retro , 21-Май-03 16:54 
>>Подскажите, пжста, как можно получить адрес текущий программы, написанной на си (адрес исполняемого файла)?
>
>Не очень понятен вопрос... Но, скорее всего - ответ такой: "никак"!
>От OS зависит, но если это 32-бит многозадачная OS в виртуализацией и
>т.д. ... то все программы будут начинаться с одного и того-же
>стартового адреса. Это если говорить об логических адресах.
>
>А если об физических (адрес в чипе RAM) то тут совсем ...
>приехали.
>Адрес "начала" может быть, напр. 0хсссссс (кстати, адрес "конца" - вполне может
>быть 0хbbbb00), но, пока мы это определили ... он уже стал
>0x00aaaa! И это даже если образ программы "невыгружаемый", т.е. без виртуализации
>через диск.
Требуется определить физический адрес первого байта программы в ОП;
скажем что-то, типа:

mian()
{
printf("%d",main);
}



"Как получить адрес программы в оперативной памяти?"
Отправлено Olej , 21-Май-03 17:54 
>Требуется определить физический адрес первого байта программы в ОП;
>скажем что-то, типа:
>
>mian()
>{
>printf("%d",main);
>}

Ещё раз:
Что значит физический адрес в ОП, именно физический адрес в RAM? К тому времени, пока вы его определите - он уже может быть другим...

И что значит первого байта программы? Адрес main?:

void main() {
  printf ( "%X", &main );
};

Или адрес 1-й выполняемой инструкции кода - инициализация среды, static переменных... ведь достаточно много выполняется до main()... Или адрес адрес образа задачи, отображённого на RAM из ELF-формата файла?... И какая конкретно OS - каждая имеет свои соглашения о начальных адресах загрузки.

И это всё будут только логические адреса, для преобразования их в физические .... ой-ой-ой:
- будучи root вы должны получить превилегированный режим - кольца защиты 0;
- от регистра страниц процессора - двигаться по цепочке от LDT ... выполнить всю реконструкцию преобразования адресных страниц...

Что это может дать? Может проще сформулировать конечную проблему, которую нужно решить таким загадочным способом?


"Как получить адрес программы в оперативной памяти?"
Отправлено Bob , 31-Май-03 22:19 
>Требуется определить физический адрес первого байта программы в ОП;
>скажем что-то, типа:
>
>mian()
>{
>printf("%d",main);
>}


Чтобы найти адрес функции main, проанализируем заголовок исполняемого файла формата ELF32. Структура заголовка находится в файле <linux/elf.h>. Поле e_entry структуры struct elf32_hdr содержит стартовый адрес программы. Найти его можно следующим способом:


#include <stdio.h>
#include <linux/elf.h>
#include <fcntl.h>

int main (int argc, char **argv)
{
int fd, kmem;
unsigned long addr = 0; - здесь мы сохраним адрес main
struct elf32_hdr ehdr;

memset(&ehdr, 0, sizeof(struct elf32_hdr));

Откроем исполняемый файл и прочитаем заголовок:

fd=open(argv[0], O_RDONLY);
read(fd, (char *)&ehdr, sizeof(struct elf32_hdr));
close(fd);

Отобразим стартовый адрес программы:
printf("start\t-\t0xx\n", ehdr.e_entry);

Итак, стартовый адрес у нас есть.
Адрес main находится по смещению 24 байта относительно стартового адреса (ниже рассмотрено, почему это так). Воспользуемся файлом /dev/kmem, в котором отображено все виртуальное адресное пространство. Любой адрес задается как смещение в этом файле:

kmem=open("/dev/kmem", O_RDONLY);
lseek(kmem, ehdr.e_entry+24, 0);
read(kmem, (char *)&addr, 4);
close(kmem);

Адрес функции main:
printf("main\t-\t0xx\n",addr);

return 0;
}


Дизассемблируем исполняемый файл при помощи objdump и найдем стартовый адрес. По этому адресу будет расположена секция <_start>. Рассмотрев ассемблерный листинг, мы увидим, что сначала в стек загружаются параметры, а затем следует вызов библиотечной функции __libc_start_main (call <адрес><_init+0x48>). Первым параметром этой функции является адрес main. Этот параметр загружается в стек последним. Адрес main находится по смещению 24 байт относительно стартового адреса.


"Как получить адрес программы в оперативной памяти?"
Отправлено Bob , 02-Июн-03 09:59 
>Cтартовый адрес программы:
> printf("start\t-\t0xx\n", ehdr.e_entry);

printf("start\t-\t0xx\n", ehdr.e_entry);

>Адрес функции main:
> printf("main\t-\t0xx\n",addr);

printf("main\t-\t0xx\n",addr);


"Как получить адрес программы в оперативной памяти?"
Отправлено Olej , 02-Июн-03 14:32 
>>Cтартовый адрес программы:
>> printf("start\t-\t0xx\n", ehdr.e_entry);
>
>printf("start\t-\t0xx\n", ehdr.e_entry);
>
>>Адрес функции main:
>> printf("main\t-\t0xx\n",addr);
>
>printf("main\t-\t0xx\n",addr);

Всё это, наверное, правильно, за исключением:

1. мало значимо: что это сделано reverse engeniging-ом, т.е. будет работать в Linux - этой версии (но может измениться в следующих), и может не работать в других UNIX-клонах, даже использующих elf-формат...

2. что гораздо важнее: это всё будут - логические адреса, которые проходят ещё одну ступень перетрансляции в физические адреса (о которых и спрашивали в вопросе).


"Как получить адрес программы в оперативной памяти?"
Отправлено Bob , 02-Июн-03 15:39 
>
>Всё это, наверное, правильно, за исключением:
>
>1. мало значимо: что это сделано reverse engeniging-ом, т.е. будет работать в
>Linux - этой версии (но может измениться в следующих), и может
>не работать в других UNIX-клонах, даже использующих elf-формат...
>

Работает с ядрами 2.2.16, 2.4.17, 2.4.20, компилятор gcc-2.95.3.
Насчет других клонов - возможно, работать не будет, я не проверял. Если не ошибаюсь, в вопросе платформа не указана.

>2. что гораздо важнее: это всё будут - логические адреса, которые проходят
>ещё одну ступень перетрансляции в физические адреса (о которых и спрашивали
>в вопросе).

Все таки интересно, почему не устроит виртуальный адрес. Какая изначально задача ставилась перед автором вопроса? Если б это знать - можно было бы выйти и на физический адрес. Ну ладно, чем мог - помог.

P.S. Кстати, знак процента не отображается, почему то..