前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux编程--指针的++操作

Linux编程--指针的++操作

作者头像
None_Ling
发布2019-04-22 11:50:08
8110
发布2019-04-22 11:50:08
举报
文章被收录于专栏:Android相关Android相关

背景

在学习ELF文件的过程中,看到Matrix中有类似于如下的代码来遍历ELF文件的e->phdr程序头表的内容。

代码语言:javascript
复制
// 根据e_phoff找到Program Header的位置
    elf_file->elf_phdr = (ELF_Phdr *) (elf_file->base_address + elf_file->elf_ehdr->e_phoff);
    // ELF文件Program Header的结束位置
    void *phdr_end_addr = elf_file->elf_phdr + elf_file->elf_ehdr->e_phnum;
    // 从phdr开始到结束寻找,开始找到PT_LOAD的段
    for (ELF_Phdr *phdr_start_addr = elf_file->elf_phdr; phdr_start_addr < phdr_end_addr; phdr_start_addr++) {
        // 开始遍历程序头
        // 在C中,数组指针的++代表指向下个元素
        auto *program_head_table = (ELF_Phdr *) phdr_start_addr;
        if (program_head_table->p_type == PT_LOAD) {
            LOGE(TAG, "TYPE:%u, PT LOAD FIND", program_head_table->p_type);
        }
        LOGE(TAG, "TYPE:%u", program_head_table->p_type);
    }

问题

  • elf_file->elf_phdr:程序头表的起始位置
  • elf_file->elf_ehdr->e_phnum:程序头表中段的总数
  • elf_file->elf_ehdr->e_phentsize:程序头表中每个Entry的大小

问题1:为何elf_file->elf_phdr + elf_file->elf_ehdr->e_phnum就能得到程序头表的结束地址呢?而不是简单的地址加上对应的数字?

问题2:在for循环中,phdr_start_addr++为何能找到程序头表中的下一个段结构呢?

问题3:在elf_file->base_address + elf_file->elf_ehdr->e_phoff计算ELF_Phdr的地址时,是直接加的,和问题1中的有何区别?

日志验证

在代码中加入日志,打印phdr的起始与结束地址,以及entry的总数与每个entry的大小。

代码语言:javascript
复制
e->phdr start addr:534289383488
e->phdr end addr:534289383936
e->phdr entry count:8, entry size:56
Program Header: index:0...addr:534289383488
Program Header: index:1...addr:534289383544
Program Header: index:2...addr:534289383600
Program Header: index:3...addr:534289383656
Program Header: index:4...addr:534289383712
Program Header: index:5...addr:534289383768
Program Header: index:6...addr:534289383824
Program Header: index:7...addr:534289383880

可以看到:

  1. 结束地址减去起始地址正好是所有Entry的大小
    • end addr-start addr = 534289383936 - 534289383488 = 448
    • entry count * entry size = 8 * 56 = 448
  2. 在for循环中,phdr_start_addr++获取到就是对应index的起始地址
    • Entry之间的间隔大小正好为56,534289383544 - 534289383488 = 56是一个Entry的大小

原因

对于问题3而言,由于elf_file->base_addressELF_Addr类型,本身就是无符号的32位或者64位整形,所以直接加减即可。

代码语言:javascript
复制
typedef __u64 Elf64_Addr;
typedef __u32 Elf32_Addr;

elf_file->elf_phdr则是(Elf64_Phdr *),也就是指针类型,而对于指针来说,+1或者-1都是对于整个结构体而言,所以对于指针的操作,每次加1或者-1都会偏移sizeof(struct)的大小。

而这个计算,都是在编译期间编译器已经计算好了的。

(void *)的计算

C和C++中不允许(void *)pointer与整数相加,否则在编译的时候会报错误:

代码语言:javascript
复制
arithmetic on a pointer to void

原因是C和C++禁止在(void *)的指针中进行运算,因为在运行的时候会有很多字节对齐的操作,如果没有指定类型的话,无法知道对应的结构体的大小,所以禁止(void *)指针的计算。

结论

对于地址的加减来说,可以正常按数加减,而且加减完后可以赋值给结构体指针。

而对于指针的加减来说,是对于指针对应的结构体大小而言的,每次加减都是计算的N个结构体大小的偏移。 例如:phdr_start_addr++可以理解成: phdr_start_addr = phdr_start_addr + sizeof(ELF_Phdr); // 计算地址的方式

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.04.15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 问题
  • 日志验证
  • 原因
  • (void *)的计算
  • 结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档