如何解决elf文件读取符号和符号地址1字节差
几天前,我查看了精灵符号表以比较字符串以找到我的函数。 我可以很好地找到目标字符串,并且成功地获得了起始偏移量和大小。 但是,将这个偏移量与objdump的结果进行比较,可以看出1个字节是不同的。 怎么了? 我英语不好。
操作系统:Windows 10
ide : android studio ndk
目标架构:armeabi-v7a
结果图像:
申请结果:0x00908b5
预期结果:0x00908b4
我检查了什么:
- elf32_sym、elf64_sym 已检查(没问题)
- 检查结构字节填充(没问题)
- 结构体,检查变量初始化
这是从开发人员的 git 克隆而来。
template <typename ElfheaderT,typename SectionHeaderT,typename CallbackT>
void read_sections(const void *image,size_t size,const CallbackT &callback)
{
const ElfheaderT *ehdr = static_cast<const ElfheaderT *>(image);
const SectionHeaderT *shdrs = (const SectionHeaderT *)((const uint8_t *)image + ehdr->e_shoff);
const SectionHeaderT *strhdr = &shdrs[ehdr->e_shstrndx];
const char *strtab = static_cast<const char *>(image) + strhdr->sh_offset;
for (int i = 0; i < ehdr->e_shnum; ++i)
{
section s = {0,};
s.index= i;
s.name = strtab + shdrs[i].sh_name;
s.type = shdrs[i].sh_type;
s.virtual_address = static_cast<ptrdiff_t>(shdrs[i].sh_addr);
s.file_offset = static_cast<ptrdiff_t>(shdrs[i].sh_offset);
s.size = static_cast<size_t>(shdrs[i].sh_size);
s.entry_size = static_cast<size_t>(shdrs[i].sh_entsize);
s.address_align = static_cast<size_t>(shdrs[i].sh_addralign);
callback(s);
}
}
template <typename SymbolEntryT,typename CallbackT>
void read_symbols(const void *image,unsigned int code_section_index,const section &symbols,const char *names,const CallbackT &callback)
{
const size_t total_syms = symbols.size / sizeof(SymbolEntryT);
const SymbolEntryT *syms_data = (const SymbolEntryT *)((const uint8_t *)image + symbols.file_offset);
for (size_t i = 0; i < total_syms; ++i)
{
symbol s = {0,};
const SymbolEntryT &sd = syms_data[i];
const unsigned type = ELF32_ST_TYPE(sd.st_info);
if (type != STT_FUNC)
continue;
if (sd.st_shndx != code_section_index || !sd.st_size)
continue;
s.name = names + sd.st_name;
s.size = static_cast<size_t>(sd.st_size);
s.virtual_address = static_cast<size_t>(sd.st_value);
callback(s);
}
}
解决方法
指令必须与其自然边界对齐,这意味着 16 位指令必须是 2 字节对齐,而 32 位指令必须是字对齐。 (除此之外还有更多内容,但对于此问题而言,这是重要的位。)因此,分支目标的最低有效位必须始终为零,并且实际上 LSB 不包含任何信息。
当 16 位 Thumb 指令集与 armv4T 设备(从 ARM7TDMI 开始)中的 32 位 ARM 指令集并行引入时,这个未使用的位被重新用于指示代码是否应该在 ARM 模式下解释或分支后的拇指模式。无论哪种方式,该函数仍然位于同一位置,在硬件中有效清除 LSB 以创建真正的分支目标,但其值控制了分支后的指令解码模式。
自从引入统一的 Thumb-2 指令集后,就不再使用这种机制了。但是 Thumb-2 被认为是 Thumb 指令集的后代,而不是 ARM 指令集的后代,并且(例如)Cortex-M 目标被认为是永久以 Thumb 模式运行的。因此,当该地址用作分支目标时,需要设置该地址的 LSB。如果它没有设置,你会得到一个错误,因为 CPU 认为它被要求执行它不支持的 32 位 ARM 代码。 xPSR 中的 Thumb 位也是如此,它必须始终保持设置。
所以回答你的问题,没有错。如果您想知道您的函数所在的位置,以便您可以在内存窗口或其他东西中检查它,请使用偶数值地址。如果您想手动执行分支,例如通过在汇编代码中使用硬编码的数字分支目标,请确保使用带有 LSB 集的值。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。