[PATCH 16/27] gdb/coffread: Don't relocate absolute symbols

Pedro Alves <[email protected]> Thu, 23 Jul 2026 14:01:07 +0100
Newsgroups gmane.comp.gdb.patches
Message-ID <[email protected]>
A COFF absolute symbol (i.e., one with COFF section number N_ABS) has
a value that is a plain constant, not an offset into any section.
Such a symbol must not be adjusted when the objfile it belongs to is
relocated, e.g. when a DLL is loaded at an address other than its
preferred image base.

gdb/coffread.c records absolute symbols as mst_abs, which is correct,
but it derives the symbol's section from cs_to_section, which in turn
asks cs_to_bfd_section for the BFD section.  cs_to_bfd_section matches
by section number and finds nothing for an N_ABS symbol, returning
NULL, so cs_to_section falls back to the text section.  The symbol
then inherits the text section's relocation offset (the DLL's load
bias) and its value is wrongly shifted by that amount.

For a DLL loaded at its preferred base the bias is zero and the bug is
invisible, but when two DLLs are loaded overlapping so that one is
relocated, its absolute symbols come out shifted.  This can be seen in
gdb.base/shreloc.exp, which loads two libraries at the same base and
checks that absolute symbols keep the same value in both:

 (gdb) maint print msymbols ...
 [4] A 0x5bc10000 __minor_os_version__ section .text
 [4] A 0x5bbe0000 __minor_os_version__ section .text

__minor_os_version__ has value 0 in both DLLs, but GDB reports its
value as each symbols DLL's load base.  Note also the contradictory "A
... section .text" -- an absolute symbol should not be tied to a
section at all.

Fix this in cs_to_bfd_section, by returning BFD's absolute section for
an N_ABS symbol rather than NULL.  Its relocation offset is always
zero, so the symbol's value is left untouched, matching what
elf_symtab_read does for absolute ELF symbols.  cs_to_section then
naturally returns the absolute section's index.

While at it, fold the N_ABS case in symtab_read into the general path.

Without this fix, gdb.base/shreloc.exp fails on all Windows-based
targets, and it now passes cleanly:

 -FAIL: gdb.base/shreloc.exp: absolute symbols not relocated
 +PASS: gdb.base/shreloc.exp: absolute symbols not relocated

Tested on:

 x86_64-pc-linux-gnu
 x86_64-pc-cygwin
 x86_64-w64-mingw32
 x86_64-pc-windows-msvc

Change-Id: I91b9882b6918cbd46dfdf1aa18f72cbbace70535
---
 gdb/coffread.c | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/gdb/coffread.c b/gdb/coffread.c
index 0a5da42e563..9f792edcd26 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -116,6 +116,13 @@ struct coff_reader
 asection *
 coff_reader::cs_to_bfd_section (struct coff_symbol *cs)
 {
+  /* An absolute symbol (N_ABS) is not tied to any of the input file's
+     sections.  Its value is a plain constant, so map it to BFD's
+     absolute section, so that callers treat it as absolute and, in
+     particular, do not relocate it.  */
+  if (cs->c_secnum == N_ABS)
+    return bfd_abs_section_ptr;
+
   for (asection *sect : gdb_bfd_sections (symfile_bfd))
     if (sect->target_index == cs->c_secnum)
       return sect;
@@ -469,14 +476,6 @@ coff_reader::symtab_read (minimal_symbol_reader &reader,
 		   symbol lookup which returned no match.  */
 		break;
 	      }
-	    else if (cs->c_secnum == N_ABS)
-	      {
-		/* Use the correct minimal symbol type (and don't
-		   relocate) for absolute values.  */
-		ms_type = mst_abs;
-		sec = cs_to_section (cs);
-		tmpaddr = cs->c_value;
-	      }
 	    else
 	      {
 		asection *bfd_section = cs_to_bfd_section (cs);
@@ -484,7 +483,13 @@ coff_reader::symtab_read (minimal_symbol_reader &reader,
 		sec = cs_to_section (cs);
 		tmpaddr = cs->c_value;
 
-		if (bfd_section->flags & SEC_CODE)
+		if (bfd_is_abs_section (bfd_section))
+		  {
+		    /* Use the correct minimal symbol type (and don't
+		       relocate) for absolute values.  */
+		    ms_type = mst_abs;
+		  }
+		else if (bfd_section->flags & SEC_CODE)
 		  {
 		    ms_type =
 		      cs->c_sclass == C_EXT || cs->c_sclass == C_THUMBEXTFUNC
-- 
2.54.0