objdump --disassemble=sym peculiarities

Given this testcase:
 .text
 mov $x1,%eax
f1:
 mov $f1,%eax
 .type f1,@function
 .size f1,.-f1

 mov $x2,%eax
f2:
 mov $f2,%eax
 .type f2,@function
 .size f2,.-f2+0x1000 #bad size

objdump --reloc --disassemble=f1 prints
00000000 <f1-0x5>:
   0:	b8 00 00 00 00       	mov    $0x0,%eax

and objdump --reloc --disassemble=f2 prints
0000000f <f2>:
   f:	b8 0f 00 00 00       	mov    $0xf,%eax
			10: R_386_32	.text

It seems for f1 we get the insn before f1 and no reloc whereas, post
159daa36fa, f2 is disassembled correctly.  Some analysis says that
find_symbol_for_address may return a symbol past the current address,
and reloc skipping is broken.  Fix both of these problems.

	* objdump.c (disassemble_jumps, disassemble_bytes): Replace
        relppp with relpp, ie. don't update caller's rel_pp.  Adjust
        calls.
	(disassemble_section): Skip over relocs inside loop rather
        than before loop.  Revert 7e538762c2.  If given a symbol,
	don't start disassembling until its address is reached.
	Correct end of function calculation.
This commit is contained in:
Alan Modra
2024-04-02 07:18:19 +10:30
parent 0ed1e396e4
commit f37f8c46c2

View File

@@ -2946,7 +2946,7 @@ disassemble_jumps (struct disassemble_info * inf,
bfd_vma start_offset, bfd_vma start_offset,
bfd_vma stop_offset, bfd_vma stop_offset,
bfd_vma rel_offset, bfd_vma rel_offset,
arelent *** relppp, arelent ** relpp,
arelent ** relppend) arelent ** relppend)
{ {
struct objdump_disasm_info *aux; struct objdump_disasm_info *aux;
@@ -2988,11 +2988,11 @@ disassemble_jumps (struct disassemble_info * inf,
if (inf->disassembler_needs_relocs if (inf->disassembler_needs_relocs
&& (bfd_get_file_flags (aux->abfd) & EXEC_P) == 0 && (bfd_get_file_flags (aux->abfd) & EXEC_P) == 0
&& (bfd_get_file_flags (aux->abfd) & DYNAMIC) == 0 && (bfd_get_file_flags (aux->abfd) & DYNAMIC) == 0
&& *relppp < relppend) && relpp < relppend)
{ {
bfd_signed_vma distance_to_rel; bfd_signed_vma distance_to_rel;
distance_to_rel = (**relppp)->address - (rel_offset + addr_offset); distance_to_rel = (*relpp)->address - (rel_offset + addr_offset);
/* Check to see if the current reloc is associated with /* Check to see if the current reloc is associated with
the instruction that we are about to disassemble. */ the instruction that we are about to disassemble. */
@@ -3205,7 +3205,7 @@ disassemble_bytes (struct disassemble_info *inf,
bfd_vma start_offset, bfd_vma start_offset,
bfd_vma stop_offset, bfd_vma stop_offset,
bfd_vma rel_offset, bfd_vma rel_offset,
arelent ***relppp, arelent **relpp,
arelent **relppend) arelent **relppend)
{ {
struct objdump_disasm_info *aux; struct objdump_disasm_info *aux;
@@ -3377,13 +3377,13 @@ disassemble_bytes (struct disassemble_info *inf,
if (inf->disassembler_needs_relocs if (inf->disassembler_needs_relocs
&& (bfd_get_file_flags (aux->abfd) & EXEC_P) == 0 && (bfd_get_file_flags (aux->abfd) & EXEC_P) == 0
&& (bfd_get_file_flags (aux->abfd) & DYNAMIC) == 0 && (bfd_get_file_flags (aux->abfd) & DYNAMIC) == 0
&& *relppp < relppend) && relpp < relppend)
{ {
bfd_signed_vma distance_to_rel; bfd_signed_vma distance_to_rel;
int max_reloc_offset int max_reloc_offset
= aux->abfd->arch_info->max_reloc_offset_into_insn; = aux->abfd->arch_info->max_reloc_offset_into_insn;
distance_to_rel = ((**relppp)->address - rel_offset distance_to_rel = ((*relpp)->address - rel_offset
- addr_offset); - addr_offset);
insn_size = 0; insn_size = 0;
@@ -3427,7 +3427,7 @@ disassemble_bytes (struct disassemble_info *inf,
&& distance_to_rel < insn_size / (int) opb)) && distance_to_rel < insn_size / (int) opb))
{ {
inf->flags |= INSN_HAS_RELOC; inf->flags |= INSN_HAS_RELOC;
aux->reloc = **relppp; aux->reloc = *relpp;
} }
} }
@@ -3600,14 +3600,14 @@ disassemble_bytes (struct disassemble_info *inf,
need_nl = true; need_nl = true;
} }
while ((*relppp) < relppend while (relpp < relppend
&& (**relppp)->address < rel_offset + addr_offset + octets / opb) && (*relpp)->address < rel_offset + addr_offset + octets / opb)
{ {
if (dump_reloc_info || dump_dynamic_reloc_info) if (dump_reloc_info || dump_dynamic_reloc_info)
{ {
arelent *q; arelent *q;
q = **relppp; q = *relpp;
if (wide_output) if (wide_output)
putchar ('\t'); putchar ('\t');
@@ -3665,7 +3665,7 @@ disassemble_bytes (struct disassemble_info *inf,
printf ("\n"); printf ("\n");
need_nl = false; need_nl = false;
} }
++(*relppp); ++relpp;
} }
if (need_nl) if (need_nl)
@@ -3809,12 +3809,6 @@ disassemble_section (bfd *abfd, asection *section, void *inf)
if (sorted_symcount > 1) if (sorted_symcount > 1)
qsort (sorted_syms, sorted_symcount, sizeof (asymbol *), compare_symbols); qsort (sorted_syms, sorted_symcount, sizeof (asymbol *), compare_symbols);
/* Skip over the relocs belonging to addresses below the
start address. */
while (rel_pp < rel_ppend
&& (*rel_pp)->address < rel_offset + addr_offset)
++rel_pp;
printf (_("\nDisassembly of section %s:\n"), sanitize_string (section->name)); printf (_("\nDisassembly of section %s:\n"), sanitize_string (section->name));
/* Find the nearest symbol forwards from our current position. */ /* Find the nearest symbol forwards from our current position. */
@@ -3846,6 +3840,12 @@ disassemble_section (bfd *abfd, asection *section, void *inf)
bfd_vma nextstop_offset; bfd_vma nextstop_offset;
bool insns; bool insns;
/* Skip over the relocs belonging to addresses below the
start address. */
while (rel_pp < rel_ppend
&& (*rel_pp)->address < rel_offset + addr_offset)
++rel_pp;
addr = section->vma + addr_offset; addr = section->vma + addr_offset;
addr = ((addr & ((sign_adjust << 1) - 1)) ^ sign_adjust) - sign_adjust; addr = ((addr & ((sign_adjust << 1) - 1)) ^ sign_adjust) - sign_adjust;
@@ -3912,17 +3912,11 @@ disassemble_section (bfd *abfd, asection *section, void *inf)
/* We are not currently printing. Check to see /* We are not currently printing. Check to see
if the current symbol matches the requested symbol. */ if the current symbol matches the requested symbol. */
if (streq (name, paux->symbol)) if (streq (name, paux->symbol)
&& bfd_asymbol_value (sym) <= addr)
{ {
do_print = true; do_print = true;
/* Skip over the relocs belonging to addresses below the
symbol address. */
const bfd_vma sym_offset = bfd_asymbol_value (sym) - section->vma;
while (rel_pp < rel_ppend &&
(*rel_pp)->address - rel_offset < sym_offset)
++rel_pp;
loop_until = next_sym; loop_until = next_sym;
if (sym->flags & BSF_FUNCTION) if (sym->flags & BSF_FUNCTION)
{ {
@@ -3932,13 +3926,14 @@ disassemble_section (bfd *abfd, asection *section, void *inf)
{ {
bfd_size_type fsize = bfd_size_type fsize =
((elf_symbol_type *) sym)->internal_elf_sym.st_size; ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
if (addr_offset + fsize > addr_offset bfd_vma fend =
&& addr_offset + fsize <= stop_offset) bfd_asymbol_value (sym) - section->vma + fsize;
if (fend > addr_offset && fend <= stop_offset)
{ {
/* Sym is a function symbol with a valid /* Sym is a function symbol with a valid
size associated with it. Disassemble size associated with it. Disassemble
to the end of the function. */ to the end of the function. */
stop_offset = addr_offset + fsize; stop_offset = fend;
loop_until = stop_offset_reached; loop_until = stop_offset_reached;
} }
} }
@@ -4046,11 +4041,9 @@ disassemble_section (bfd *abfd, asection *section, void *inf)
objdump_print_symname (abfd, &di, sym); objdump_print_symname (abfd, &di, sym);
/* Fetch jump information. */ /* Fetch jump information. */
detected_jumps = disassemble_jumps detected_jumps = disassemble_jumps (pinfo, paux->disassemble_fn,
(pinfo, paux->disassemble_fn, addr_offset, nextstop_offset,
addr_offset, nextstop_offset, rel_offset, rel_pp, rel_ppend);
rel_offset, &rel_pp, rel_ppend);
/* Free symbol name. */ /* Free symbol name. */
free (sf.buffer); free (sf.buffer);
} }
@@ -4058,7 +4051,7 @@ disassemble_section (bfd *abfd, asection *section, void *inf)
/* Add jumps to output. */ /* Add jumps to output. */
disassemble_bytes (pinfo, paux->disassemble_fn, insns, data, disassemble_bytes (pinfo, paux->disassemble_fn, insns, data,
addr_offset, nextstop_offset, addr_offset, nextstop_offset,
rel_offset, &rel_pp, rel_ppend); rel_offset, rel_pp, rel_ppend);
/* Free jumps. */ /* Free jumps. */
while (detected_jumps) while (detected_jumps)