轉(zhuǎn)載自https://blog.csdn.net/yyttiao/article/details/7350279
今天這一節(jié),主要是講程序頭(Program Headers),程序頭主要是從加載執(zhí)行的角度來看的,很多人想那里面到底是什么東西呢,其實程序頭就是一個結(jié)構(gòu)數(shù)組,每一個頭保存著對應(yīng)的不同的數(shù)據(jù),有的數(shù)據(jù)是告訴系統(tǒng)把我放入內(nèi)存,有的數(shù)據(jù)時告訴系統(tǒng)我是變量.等等...在系統(tǒng)加載程序的時候就要通過該程序頭來加載不同的段.
下面就來看一下程序頭的結(jié)構(gòu)體:
typedef struct
{
Elf32_Word p_type; /* Segment type */
Elf32_Off p_offset; /* Segment file offset */
Elf32_Addr p_vaddr; /* Segment virtual address */
Elf32_Addr p_paddr; /* Segment physical address */
Elf32_Word p_filesz; /* Segment size in file */
Elf32_Word p_memsz; /* Segment size in memory */
Elf32_Word p_flags; /* Segment flags */
Elf32_Word p_align; /* Segment alignment */
} Elf32_Phdr;
p_type: 段的類型
在elf.h頭文件中,有很詳細(xì)的說明段的類型,比如PT_LOAD 表示加載的程序段
p_offset: 文件偏移
該段在文件中的偏移世吨。這個偏移是相對于整個文件的乙埃。
p_vaddr: 加載后的虛擬地址
該段加載后在進程空間中占用的內(nèi)存起始地址觅玻。
p_paddr: 該段的物理地址
這個字段被忽略虏束,因為在多數(shù)現(xiàn)代操作系統(tǒng)下物理地址是進程無法觸及的。
p_filesz: 該段在文件中占用的字節(jié)大小
有些段可能在文件中不存在但卻占用一定的內(nèi)存空間,此時這個字段為0。
p_memsz: 該段在內(nèi)存中占用的字節(jié)大小
有些段可能僅存在于文件中而不被加載到內(nèi)存,此時這個字段為0别智。
p_flags: 段的屬性
表示該段的讀寫執(zhí)行等屬性.elf.h文件中的定義是
#define PF_X (1 << 0) /* Segment is executable */
#define PF_W (1 << 1) /* Segment is writable */
#define PF_R (1 << 2) /* Segment is readable */
#define PF_MASKOS 0x0ff00000 /* OS-specific */
#define PF_MASKPROC 0xf0000000 /* Processor-specific */
p_align: 對齊
現(xiàn)代操作系統(tǒng)都使用虛擬內(nèi)存為進程序提供更大的空間,分頁技術(shù)功不可沒稼稿,頁就成了最小的內(nèi)存分配單位薄榛,不足一頁的按一頁算讳窟。所以加載程序數(shù)據(jù)一般也從一頁的起始地址開始,這就屬于對齊敞恋。
示例代碼:
#include <stdio.h>
#include <math.h>
#include <elf.h>
int main()
{
typedef struct
{
int num;
} student;
student stu1;
stu1.num = 133;
printf("%d\n", stu1.num);
return 0;
}
typedef struct _SegmentType_
{
unsigned int type;
char *typeName;
} SegmentType;
SegmentType segTyoe[] = {
{0, "NULL"},
{1, "LOAD"},
{2, "DYNAMIC"},
{3, "INTERP"},
{4, "NOTE"},
{5, "SHLIB"},
{6, "PHDR"},
{7, "TLS"},
{8, "NUM"},
{0x60000000, "LOOS"},
{0x6474e550, "GNU_EH_FRAME"},
{0x6474e551, "PT_GNU_STACK"},
{0x6474e552, "PT_GNU_RELRO"},
{0x6ffffffa, "PT_SUNWBSS"},
{0x6ffffffb, "PT_SUNWSTACK"},
{0x6fffffff, "PT_HISUNW"},
{0x70000000, "PT_HIOS"},
{0x7fffffff, "PT_HIPROC"},
};
char *findSegTypeName(unsigned int type)
{
int i = 0;
for (i = 0; i < sizeof(segTyoe) / sizeof(SegmentType); i++)
{
if (segTyoe[i].type == type)
{
return segTyoe[i].typeName;
break;
}
}
return segTyoe[0].typeName;
}
void displayPhdr(Elf32_Ehdr *ehdr, Elf32_Phdr *phdr)
{
printf("Program Headers:\n");
printf("%-20s%-10s%-10s%-10s%-10s%-10s%-10s%-10s\n",
"Type", "Offset", "VirtAddr", "PhysAddr", "FileSiz",
"MemSiz", "Flg", "Align");
int i = 0;
for (i = 0; i < ehdr->e_phnum; i++)
{
printf("%-20s%-10x%-10x%-10x%-10x%-10x%-10x%-10x\n",
findSegTypeName(phdr->p_type),
phdr->p_offset,
phdr->p_vaddr,
phdr->p_paddr,
phdr->p_filesz,
phdr->p_memsz,
phdr->p_flags,
phdr->p_align
);
if (phdr->p_type == PT_INTERP)
{
printf("\t[Requesting program interpreter: %s]\n",
(char *)((char *)ehdr + phdr->p_offset));
}
phdr++;
}
}