static bool show_refs = false; /* --ref */
static bool do_high_level = true; /* ! --nohl */
+int
+layout_rel_file (Elf *elf)
+{
+ GElf_Ehdr ehdr;
+ if (gelf_getehdr (elf, &ehdr) == NULL)
+ return 2;
+
+ if (ehdr.e_type != ET_REL)
+ return 0;
+
+ /* Taken from libdwfl. */
+ GElf_Addr base = 0;
+ GElf_Addr start = 0, end = 0, bias = 0;
+
+ bool first = true;
+ Elf_Scn *scn = NULL;
+ while ((scn = elf_nextscn (elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (unlikely (shdr == NULL))
+ return 2;
+
+ if (shdr->sh_flags & SHF_ALLOC)
+ {
+ const GElf_Xword align = shdr->sh_addralign ?: 1;
+ const GElf_Addr next = (end + align - 1) & -align;
+ if (shdr->sh_addr == 0
+ /* Once we've started doing layout we have to do it all,
+ unless we just layed out the first section at 0 when
+ it already was at 0. */
+ || (bias == 0 && end > start && end != next))
+ {
+ shdr->sh_addr = next;
+ if (end == base)
+ /* This is the first section assigned a location.
+ Use its aligned address as the module's base. */
+ start = base = shdr->sh_addr;
+ else if (unlikely (base & (align - 1)))
+ {
+ /* If BASE has less than the maximum alignment of
+ any section, we eat more than the optimal amount
+ of padding and so make the module's apparent
+ size come out larger than it would when placed
+ at zero. So reset the layout with a better base. */
+
+ start = end = base = (base + align - 1) & -align;
+ Elf_Scn *prev_scn = NULL;
+ do
+ {
+ prev_scn = elf_nextscn (elf, prev_scn);
+ GElf_Shdr prev_shdr_mem;
+ GElf_Shdr *prev_shdr = gelf_getshdr (prev_scn,
+ &prev_shdr_mem);
+ if (unlikely (prev_shdr == NULL))
+ return 2;
+ if (prev_shdr->sh_flags & SHF_ALLOC)
+ {
+ const GElf_Xword prev_align
+ = prev_shdr->sh_addralign ?: 1;
+
+ prev_shdr->sh_addr
+ = (end + prev_align - 1) & -prev_align;
+ end = prev_shdr->sh_addr + prev_shdr->sh_size;
+
+ if (unlikely (! gelf_update_shdr (prev_scn,
+ prev_shdr)))
+ return 2;
+ }
+ }
+ while (prev_scn != scn);
+ continue;
+ }
+
+ end = shdr->sh_addr + shdr->sh_size;
+ if (likely (shdr->sh_addr != 0)
+ && unlikely (! gelf_update_shdr (scn, shdr)))
+ return 2;
+ }
+ else
+ {
+ /* The address is already assigned. Just track it. */
+ if (first || end < shdr->sh_addr + shdr->sh_size)
+ end = shdr->sh_addr + shdr->sh_size;
+ if (first || bias > shdr->sh_addr)
+ /* This is the lowest address in the module. */
+ bias = shdr->sh_addr;
+
+ if ((shdr->sh_addr - bias + base) & (align - 1))
+ /* This section winds up misaligned using BASE.
+ Adjust BASE upwards to make it congruent to
+ the lowest section address in the file modulo ALIGN. */
+ base = (((base + align - 1) & -align)
+ + (bias & (align - 1)));
+ }
+
+ first = false;
+ }
+ }
+ return 0;
+}
+
int
main (int argc, char *argv[])
{
}
/* Create an `Elf' descriptor. */
- Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
+ Elf *elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
if (elf == NULL)
+ invalid_elf:
wr_error (NULL,
- gettext ("cannot generate Elf descriptor: %s\n"),
+ gettext ("Error processing ELF file: %s\n"),
elf_errmsg (-1));
else
{
unsigned int prev_error_count = error_count;
+ switch (layout_rel_file (elf))
+ {
+ case 2:
+ goto invalid_elf;
+ case 1:
+ wr_error (NULL, "Couldn't layout ET_REL file, the range analysis may be inaccurate.\n");
+ default:
+ ;
+ }
+
Dwarf *dwarf = dwarf_begin_elf (elf, DWARF_C_READ, NULL);
if (dwarf == NULL)
{
return;
}
- *value = rel->addend + symbol->st_value;
uint64_t section_index = symbol->st_shndx;
/* XXX We should handle SHN_XINDEX here. Or, instead, maybe it
would be possible to use dwfl, which already does XINDEX
translation. */
+ /* For ET_REL files, we do section layout manually. But we
+ don't update symbol table doing that. So instead of looking
+ at symbol value, look at section address. */
+ uint64_t sym_value = symbol->st_value;
+ if (reloc->file->ehdr.e_type == ET_REL
+ && ELF64_ST_TYPE (symbol->st_info) == STT_SECTION)
+ {
+ assert (sym_value == 0);
+ sym_value = reloc->file->sec[section_index].shdr.sh_addr;
+ }
+
+ *value = rel->addend + sym_value;
+
/* It's target value, not section offset. */
if (offset_into == rel_value
|| offset_into == rel_address)