[手搓 RISC-V 高性能模拟器]笔记三

本文详细介绍了ELF文件的结构,包括programheader(phnum)的作用,如描述磁盘上的代码和数据段;fseek函数的使用,用于在文件中设置位置指针;static函数的可见性和用途,如统计功能;.bss段和.sbss段在存储未初始化全局变量中的角色,以及mmap函数在内存映射中的应用。
摘要由CSDN通过智能技术生成

知识点

1. phnum指的是什么?有什么意义?如何使用?

phnum = program header number

program header

程序头是专门用来描述段信息的,这个段不是内存中的段,内存中的段是记录在全局描述符表中的。程序头描述的段是磁盘上程序中的一个段,常见的如代码段和数据段,下面是其结构

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_offset表示该segment相对ELF文件开头的偏移量
p_filesz表示该segment在ELF文件中的大小
p_memsz表示该segment加载到内存后所占用的大小

p_filesz和p_memsz的大小只有在少数情况下不相同,如包含.bss section的segment,因为.bss section在ELF文件中不占用空间,但在内存中需要占用相应字节大小的空间

通过p_offset和p_filesz两个成员就可以获得相应segment中的所有内容,所以这里就不再需要section header的支持,但需要ELF文件头中的信息来确定program header表(每个program header的大小相同)的开头位置,因此ELF文件头(它包含在第一个LOAD segment中)也要加载到内存中 [1]

ELF header

#define EI_NIDENT (16)
 
typedef struct
{
  unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
  Elf32_Half    e_type;             /* Object file type */
  Elf32_Half    e_machine;      	/* Architecture */
  Elf32_Word    e_version;      	/* Object file version */
  Elf32_Addr    e_entry;        	/* Entry point virtual address */
  Elf32_Off	    e_phoff;        	/* Program header table file offset */
  Elf32_Off	    e_shoff;        	/* Section header table file offset */
  Elf32_Word    e_flags;        	/* Processor-specific flags */
  Elf32_Half    e_ehsize;       	/* ELF header size in bytes */
  Elf32_Half    e_phentsize;    	/* Program header table entry size */
  Elf32_Half    e_phnum;        	/* Program header table entry count */
  Elf32_Half    e_shentsize;   		/* Section header table entry size */
  Elf32_Half    e_shnum;      	    /* Section header table entry count */
  Elf32_Half    e_shstrndx;   	    /* Section header string table index */
} Elf32_Ehdr;

e_phentsize表示Program header table entry size
e_phoff表示Program header的offset
获取对应program header的计算方式 = e_phoff + e_phentsize × i

2. fseek函数 [3]

头文件

#include <stdio.h>

函数原型

int fseek(FILE *stream, long offset, int fromwhere);

参数

  • stream:指向打开的文件指针。
  • offset:以基准点为起始点的偏移量。
  • fromwhere:基准点。

其中基准点包括这三个枚举

  • SEEK_SET:文件头
  • SEEK_CUR:当前位置
  • SEEK_END:文件件尾

返回值

成功返回0,失败返回-1

作用

重定位流(数据流/文件)的内部位置指针。

描述

函数设置文件指针stream的位置。如果执行成功,stream将指向以fromwhere为基准,偏移offset个字节的位置。如果执行失败,则不改变stream指向的位置。

3. static函数 [4]

函数的定义和声明默认情况下是extern的,但静态函数只是在声明他的文件当中可见,不能被其他文件所用。由于static变量的以上特性,可实现一些特定功能,如统计次数功能

4. sbss bss段 内容,ELF里和内存里的存储

.bss 表示未初始化和初始化为 0的全局变量的一块内存区域。在程序载入时由内核清零。数据段属于静态内存分配。从可执行程序的角度来说,如果一个数据未被初始化,就不需要为其分配空间,所以.data 和.bss 的区别就是 .bss 并不占用可执行文件的大小,仅仅记录需要用多少空间来存储这些未初始化的数据,而不分配实际空间[5]。

.sbss是小的BSS段,用于存放“近”数据,即使用短指针(near)寻址的数据。有利于小的对象组合到单个可以直接寻址的区域。《程序员的自我修养--链接、装载与库》一书的3.3.4节说:“以前用过的一些名字如.sdata、.tdesc、sbss、lit4、lit8、reginfo、gptab、liblist、.confict。可以不用理会这些段,它们已经被遗弃了。”话虽然这么说,不过实际使用中还是会碰到[6]。

5. mmap函数

参考资料
[1] 程序的本质之二ELF文件的文件头、section header和program header
[2] Linux内核如何装载和启动一个可执行程序
[3] c语言fseek函数的总结
[4] c语言中static 函数和普通函数的区别?
[5] 再谈应用程序分段: 数据段、代码段、BSS段以及堆和栈
[6] .text、.data、.bss、sbss、scommon段
[7] 全网首发】万字图文 | 你写的代码是如何跑起来的?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值