以32位为例;程序头表由几个项组成,其处理方式类似于数组项。
/* Program segment header. */
typedef struct
{
Elf32_Word p_type; /* Segment type */
描述段的种类,其中段的种类如下:
PT_NULL表示的段。
PT_LOAD表示可装载段,在程序执行前从二进制文件映射到内存。
PT_DYNAMIC表示段包含了用于动态链接器的信息
PT_INTERP表示当前段指定了可用于动态链接的程序解释器。通常是ld-linux.so
PT_NOTE指定一个段,其中可能包含专用的编译器信息。
还有两个是处理器相关,内核不关注。
Elf32_Off p_offset; /* Segment file offset *
/所述段在文件中的偏移量(从起始位置计算,单位为字节)
Elf32_Addr p_vaddr; /* Segment virtual address */
给出了段的数据映射到虚拟地址空间中的位置(对于PT_LOAD类型的段)。只支持物理寻址,不支持虚拟寻址的系统,将使用p_paddr保持信息。
Elf32_Addr p_paddr; /* Segment physical address */物理寻址支持
Elf32_Word p_filesz; /* Segment size in file */段在二进制文件中的长度
Elf32_Word p_memsz; /* Segment size in memory */段在虚拟地址空间中的长度,与文件中的物理的长度差值可通过截断数据或填充0字节来补偿。
Elf32_Word p_flags; /* Segment flags */
保持了标志信息,定义了该段的访问权限:
PF_R表示只读
PF_X表示文件可执行
Elf32_Word p_align; /*Segment alignment */指明了段在内存和二进制文件中的对齐方式,(p_vaddr和p_offet地址必须是模p_align的,既是p_align的倍数)例如p_align的值为0x1000=4096,这意味着段必须对齐到4k页。
} Elf32_Phdr;
由上图可以看出该程序头表列出了8个段,这些组成了最终在内存中执行的程序。
其还提供了各段在虚拟地址空间和物理地址空间的位置、大小、标志、访问授权和对齐方面的信息。还指定了一个类型来更精确的描述段。
PHDR保存程序头表。
INTERP指定在程序已经从可执行映射到内存之后,必须调用解释器。在这里解释器并不意味着二进制文件的内存必须由另一个程序解释。它指的是这样的一个程序:通过链接其他库,来满足未解决的引用。
通常/lib/ld-linux-so.2、/lib/ld-linux-ia-64.so.2等库,用于在虚拟地址空间中插入程序运行所需的动态库。对几乎所有的程序来说,可能c标准库都是必须映射的,还需要添加各种哭包括,GTK、数学库、libjpeg等。
LOAD表示一个从二进制文件映射到虚拟地址空间的段。其中保存了常量数据(如字符串),程序的目标代码等等。
DYNAMIC段保存了其他动态链接器(即,INTERP中指定的解释器)使用的信息。
NOTE保存了专有信息。
虚拟地址空间的各个段,填充了来自ELF文件中特定段的数据。
readelf输出的第二部分指定了哪些节载入到哪些段。
#include
#include
#include
#include
#include
#include
#define elf_file_path "/home/code/test/main"
#define MA 1
#define PHDR_SIZE 8
int main(int argc,char** argv) {
#ifdef __x86_64__
#if MA
Elf64_Phdr *phdrs = malloc(sizeof (Elf64_Phdr)*PHDR_SIZE);
if(phdrs == NULL) {
perror("malloc error");
}
#else
Elf64_Phdr phdrs[PHDR_SIZE];
#endif
#else
#if MA
Elf32_Phdr*phdrs = malloc(sizeof(Elf32_Phdr)*PHDR_SIZE);
if(phdrs == NULL) {
perror("malloc error");
}
#else
Elf32_Phdr phdrs[PHDR_SIZE];
#endif
#endif
#ifdef __x86_64__
memset(phdrs, 0, sizeof (Elf64_Phdr)*PHDR_SIZE);
#else
memset(phdrs,0, sizeof (Elf32_Phdr)*PHDR_SIZE);
#endif
int fd = open(elf_file_path, O_RDONLY);
if(fd < 0) {
perror("open elf file failed");
}
#ifdef __x86_64__
lseek(fd, 64, SEEK_SET);
intret;
if((ret = read(fd, phdrs, sizeof (Elf64_Phdr)*PHDR_SIZE)) < 1) {
perror("read elf file failed");
}
#else
lseek(fd, 52, SEEK_SET);
int ret;
if((ret = read(fd, phdrs, sizeof (Elf32_Phdr)*PHDR_SIZE)) < 1) {
perror("read elf file failed");
}
#endif
int i= 0;
printf("Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n");
#if 1
for(; i < PHDR_SIZE; i++) {
#ifdef __x86_64__
#if MA
Elf64_Phdr *phdr = phdrs++;
#else
Elf64_Phdr *phdr = &phdrs[i];
#endif
#else
#if MA
Elf32_Phdr *phdr = phdrs++;
#else
Elf32_Phdr *phdr = &phdrs[i];
#endif
#endif
switch (phdr->p_type) {
case PT_NULL:
printf("%s ", "NULL");
break;
case PT_LOAD:
printf("%s ", "LOAD");
break;
case PT_DYNAMIC:
printf("%s ", "DYNA");
break;
case PT_INTERP:
printf("%s ", "INTERP");
break;
case PT_NOTE:
printf("%s ", "NOTE");
break;
case PT_SHLIB:
printf("%s ", "SHLIB");
break;
case PT_PHDR:
printf("%s ", "PHDR");
break;
case PT_TLS:
printf("%s ", "TLS");
break;
case PT_NUM:
printf("%s ", "NUM");
break;
case PT_LOOS:
printf("%s ", "LOOS");
break;
case PT_GNU_EH_FRAME:
printf("%s ", "GNU_EH_FRAME");
break;
case PT_GNU_STACK:
printf("%s ","GNU_STACK");
break;
default:
printf("%s ", "OTHER");
break;
}
printf(" 0x%-6X 0x%-8X 0x%-8X 0x%-6X 0x%-6X",
(phdr)->p_offset,
(phdr)->p_vaddr,
(phdr)->p_paddr,
(phdr)->p_filesz,
(phdr)->p_memsz);
switch ((phdr)->p_flags) {
case PF_W:
printf(" %s", " W ");
break;
case PF_R:
printf(" %s", "R ");
break;
case (PF_W + PF_R):
printf(" %s", "RW ");
break;
case PF_X:
printf(" %s", " E");
break;
case (PF_X + PF_R):
printf(" %s", "R E");
break;
case (PF_X + PF_W):
printf(" %s", " WE");
break;
case (PF_X + PF_W + PF_R):
printf(" %s", "RWE");
break;
case (PF_MASKOS):
printf(" %s", "MASKOS");
break;
case (PF_MASKPROC):
printf(" %s", "MASKPROC");
break;
default:
printf(" %s", " ");
break;
}
printf(" 0x%-4X\n", (phdr)->p_align);
}
#if MA
if(phdrs != NULL){
phdrs = phdrs - PHDR_SIZE;
free(phdrs);
}
#endif
#endif
close(fd);
return (EXIT_SUCCESS);
}
运行程序截图: