недавно (ура, больше не школа) я учил себя формату файла ELF. Я в основном следил за документацией здесь: http://www.skyfree.org/linux/references/ELF_Format.pdf.
Все шло отлично, и я написал эту программу, чтобы получить информацию о разделах файла ELF:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <elf.h>
void dumpShdrInfo(Elf32_Shdr elfShdr, const char *sectionName)
{
printf("Section '%s' starts at 0x%08X and ends at 0x%08X\n",
sectionName, elfShdr.sh_offset, elfShdr.sh_offset + elfShdr.sh_size);
}
int search(const char *name)
{
Elf32_Ehdr elfEhdr;
Elf32_Shdr *elfShdr;
FILE *targetFile;
char tempBuf[64];
int i, ret = -1;
targetFile = fopen(name, "r+b");
if(targetFile)
{
/* read the ELF header */
fread(&elfEhdr, sizeof(elfEhdr), 1, targetFile);
/* Elf32_Ehdr.e_shnum specifies how many sections there are */
elfShdr = calloc(elfEhdr.e_shnum, sizeof(*elfShdr));
assert(elfShdr);
/* set the file pointer to the section header offset and read it */
fseek(targetFile, elfEhdr.e_shoff, SEEK_SET);
fread(elfShdr, sizeof(*elfShdr), elfEhdr.e_shnum, targetFile);
/* loop through every section */
for(i = 0; (unsigned int)i < elfEhdr.e_shnum; i++)
{
/* if Elf32_Shdr.sh_addr isn't 0 the section will appear in memory*/
if(elfShdr[i].sh_addr)
{
/* set the file pointer to the location of the section's name and then read the name */
fseek(targetFile, elfShdr[elfEhdr.e_shstrndx].sh_offset + elfShdr[i].sh_name, SEEK_SET);
fgets(tempBuf, sizeof(tempBuf), targetFile);
#if defined(DEBUG)
dumpShdrInfo(elfShdr[i], tempBuf);
#endif
}
}
fclose(targetFile);
free(elfShdr);
}
return ret;
}
int main(int argc, char *argv[])
{
if(argc > 1)
{
search(argv[1]);
}
return 0;
}
Запустив его несколько раз на паре файлов, я заметил кое-что странное. Раздел '.text' всегда начинался с очень низкого виртуального адреса (мы говорим меньше 1000h). Немного покопавшись в gdb, я заметил, что для каждого раздела sh_addr равен sh_offset.
Это то, что меня смущает - Elf32_Shdr.sh_addr задокументирован как «адрес, по которому должен находиться первый байт», а Elf32_Shdr.sh_offset задокументирован как «байтовое смещение от начала файла до первого байта». в функции». Если это оба случая, для меня действительно не имеет смысла, что они оба равны. Почему это?
Теперь я знаю, что есть разделы, которые содержат неинициализированные данные (думаю, .bss), поэтому было бы разумно, чтобы эти данные не отображались в файле, а появлялись в памяти процесса. Это будет означать, что для каждого раздела, следующего за вышеупомянутым, вычисление его виртуального адреса будет намного сложнее, чем простая переменная.
При этом есть ли способ определить виртуальный адрес раздела?