diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 5d38cb250f..f2c08aa530 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -947,7 +947,8 @@ record_line (struct subfile *subfile, int line, CORE_ADDR pc)
   if (line == 0 && subfile->line_vector->nitems > 0)
     {
       e = subfile->line_vector->item + subfile->line_vector->nitems - 1;
-      while (subfile->line_vector->nitems > 0 && e->pc == pc)
+      while (subfile->line_vector->nitems > 0
+	     && e->raw_address () == pc)
 	{
 	  e--;
 	  subfile->line_vector->nitems--;
@@ -955,8 +956,7 @@ record_line (struct subfile *subfile, int line, CORE_ADDR pc)
     }
 
   e = subfile->line_vector->item + subfile->line_vector->nitems++;
-  e->line = line;
-  e->pc = pc;
+  e->set (line, pc);
 }
 
 /* Needed in order to sort line tables from IBM xcoff files.  Sigh!  */
@@ -969,15 +969,15 @@ compare_line_numbers (const void *ln1p, const void *ln2p)
 
   /* Note: this code does not assume that CORE_ADDRs can fit in ints.
      Please keep it that way.  */
-  if (ln1->pc < ln2->pc)
+  if (ln1->raw_address () < ln2->raw_address ())
     return -1;
 
-  if (ln1->pc > ln2->pc)
+  if (ln1->raw_address () > ln2->raw_address ())
     return 1;
 
   /* If pc equal, sort by line.  I'm not sure whether this is optimum
      behavior (see comment at struct linetable in symtab.h).  */
-  return ln1->line - ln2->line;
+  return ln1->line () - ln2->line ();
 }
 
 /* See buildsym.h.  */
diff --git a/gdb/coffread.c b/gdb/coffread.c
index cad3e7e2f1..8408d07bde 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -1130,8 +1130,7 @@ coff_symtab_read (minimal_symbol_reader &reader,
 	         other statement-line-number.  */
 	      if (fcn_last_line == 1)
 		record_line (current_subfile, fcn_first_line,
-			     gdbarch_addr_bits_remove (gdbarch,
-						       fcn_first_line_addr));
+			     fcn_first_line_addr);
 	      else
 		enter_linenos (fcn_line_ptr, fcn_first_line,
 			       fcn_last_line, objfile);
@@ -1506,11 +1505,9 @@ enter_linenos (long file_offset, int first_line,
       if (L_LNNO32 (&lptr) && L_LNNO32 (&lptr) <= last_line)
 	{
 	  CORE_ADDR addr = lptr.l_addr.l_paddr;
-	  addr += ANOFFSET (objfile->section_offsets,
-			    SECT_OFF_TEXT (objfile));
 	  record_line (current_subfile,
 		       first_line + L_LNNO32 (&lptr),
-		       gdbarch_addr_bits_remove (gdbarch, addr));
+		       addr);
 	}
       else
 	break;
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index bdf4fb9c79..ff6f9ec20f 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -2562,10 +2562,10 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, const char *name,
 	     but no N_SLINE stabs.  */
 	  if (sline_found_in_function)
 	    {
-	      CORE_ADDR addr = last_function_start + valu;
-
-	      record_line (current_subfile, 0,
-			   gdbarch_addr_bits_remove (gdbarch, addr));
+	      CORE_ADDR addr = (last_function_start + valu
+				- ANOFFSET (section_offsets,
+					    SECT_OFF_TEXT (objfile)));
+	      record_line (current_subfile, 0, addr);
 	    }
 
 	  within_function = 0;
@@ -2767,16 +2767,22 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, const char *name,
 
       if (within_function && sline_found_in_function == 0)
 	{
-	  CORE_ADDR addr = processing_gcc_compilation == 2 ?
-			   last_function_start : valu;
+	  CORE_ADDR addr = ((processing_gcc_compilation == 2 ?
+			     last_function_start : valu)
+			    - ANOFFSET (section_offsets,
+					SECT_OFF_TEXT (objfile)));
 
-	  record_line (current_subfile, desc,
-		       gdbarch_addr_bits_remove (gdbarch, addr));
+	  record_line (current_subfile, desc, addr);
 	  sline_found_in_function = 1;
 	}
       else
-	record_line (current_subfile, desc,
-		     gdbarch_addr_bits_remove (gdbarch, valu));
+	{
+	  CORE_ADDR addr = (valu
+			    - ANOFFSET (section_offsets,
+					SECT_OFF_TEXT (objfile)));
+
+	  record_line (current_subfile, desc, addr);
+	}
       break;
 
     case N_BCOMM:
diff --git a/gdb/disasm.c b/gdb/disasm.c
index 833341a169..97204326d1 100644
--- a/gdb/disasm.c
+++ b/gdb/disasm.c
@@ -30,6 +30,7 @@
 #include "safe-ctype.h"
 #include <algorithm>
 #include "common/gdb_optional.h"
+#include "objfiles.h"
 
 /* Disassemble functions.
    FIXME: We should get rid of all the duplicate code in gdb that does
@@ -368,35 +369,39 @@ do_mixed_source_and_assembly_deprecated
 
   /* First, skip all the preceding functions.  */
 
-  for (i = 0; i < nlines - 1 && le[i].pc < low; i++);
+  for (i = 0;
+       i < nlines - 1 && le[i].address (symtab) < low;
+       i++)
+    ;
 
   /* Now, copy all entries before the end of this function.  */
 
-  for (; i < nlines - 1 && le[i].pc < high; i++)
+  for (; i < nlines - 1 && le[i].address (symtab) < high; i++)
     {
-      if (le[i].line == le[i + 1].line && le[i].pc == le[i + 1].pc)
+      if (le[i].line () == le[i + 1].line ()
+	  && le[i].raw_address () == le[i + 1].raw_address ())
 	continue;		/* Ignore duplicates.  */
 
       /* Skip any end-of-function markers.  */
-      if (le[i].line == 0)
+      if (le[i].line () == 0)
 	continue;
 
-      mle[newlines].line = le[i].line;
-      if (le[i].line > le[i + 1].line)
+      mle[newlines].line = le[i].line ();
+      if (le[i].line () > le[i + 1].line ())
 	out_of_order = 1;
-      mle[newlines].start_pc = le[i].pc;
-      mle[newlines].end_pc = le[i + 1].pc;
+      mle[newlines].start_pc = le[i].address (symtab);
+      mle[newlines].end_pc = le[i + 1].address (symtab);
       newlines++;
     }
 
   /* If we're on the last line, and it's part of the function,
      then we need to get the end pc in a special way.  */
 
-  if (i == nlines - 1 && le[i].pc < high)
+  if (i == nlines - 1 && le[i].address (symtab) < high)
     {
-      mle[newlines].line = le[i].line;
-      mle[newlines].start_pc = le[i].pc;
-      sal = find_pc_line (le[i].pc, 0);
+      mle[newlines].line = le[i].line ();
+      mle[newlines].start_pc = le[i].address (symtab);
+      sal = find_pc_line (le[i].address (symtab), 0);
       mle[newlines].end_pc = sal.end;
       newlines++;
     }
@@ -517,10 +522,10 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch,
   first_le = NULL;
 
   /* Skip all the preceding functions.  */
-  for (i = 0; i < nlines && le[i].pc < low; i++)
-    continue;
+  for (i = 0; i < nlines && le[i].address (main_symtab) < low; i++)
+    ;
 
-  if (i < nlines && le[i].pc < high)
+  if (i < nlines && le[i].address (main_symtab) < high)
     first_le = &le[i];
 
   /* Add lines for every pc value.  */
@@ -589,9 +594,9 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch,
 	     lines.  */
 	  if (last_line == 0
 	      && first_le != NULL
-	      && first_le->line < sal.line)
+	      && first_le->line () < sal.line)
 	    {
-	      start_preceding_line_to_display = first_le->line;
+	      start_preceding_line_to_display = first_le->line ();
 	      end_preceding_line_to_display = sal.line;
 	    }
 	}
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 4207e4c531..a8cc3c95e6 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -20311,8 +20311,11 @@ public:
   void handle_set_address (CORE_ADDR baseaddr, CORE_ADDR address)
   {
     m_op_index = 0;
+    /* Pass the relocated address to the gdbarch for modification, but
+       then only store the relative address.  */
     address += baseaddr;
-    m_address = gdbarch_adjust_dwarf2_line (m_gdbarch, address, false);
+    m_address = (gdbarch_adjust_dwarf2_line (m_gdbarch, address, false)
+		 - baseaddr);
   }
 
   /* Handle DW_LNS_advance_pc.  */
@@ -20538,8 +20541,6 @@ dwarf_record_line_1 (struct gdbarch *gdbarch, struct subfile *subfile,
 		     unsigned int line, CORE_ADDR address,
 		     record_line_ftype p_record_line)
 {
-  CORE_ADDR addr = gdbarch_addr_bits_remove (gdbarch, address);
-
   if (dwarf_line_debug)
     {
       fprintf_unfiltered (gdb_stdlog,
@@ -20548,7 +20549,7 @@ dwarf_record_line_1 (struct gdbarch *gdbarch, struct subfile *subfile,
 			  paddress (gdbarch, address));
     }
 
-  (*p_record_line) (subfile, line, addr);
+  (*p_record_line) (subfile, line, address);
 }
 
 /* Subroutine of dwarf_decode_lines_1 to simplify it.
diff --git a/gdb/jit.c b/gdb/jit.c
index 2f23c058a0..eb4579c96b 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -622,8 +622,9 @@ jit_symtab_line_mapping_add_impl (struct gdb_symbol_callbacks *cb,
   stab->linetable->nitems = nlines;
   for (i = 0; i < nlines; i++)
     {
-      stab->linetable->item[i].pc = (CORE_ADDR) map[i].pc;
-      stab->linetable->item[i].line = map[i].line;
+      /* Use the absolute address here, as the offsets will all be
+	 zero.  */
+      stab->linetable->item[i].set (map[i].line, (CORE_ADDR) map[i].pc);
     }
 }
 
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 7ef8012ab5..48e2128cf1 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -2149,7 +2149,7 @@ create_sals_line_offset (struct linespec_state *self,
 	= decode_digits_ordinary (self, ls, val.line, &best_entry);
       if (intermediate_results.empty () && best_entry != NULL)
 	intermediate_results = decode_digits_ordinary (self, ls,
-						       best_entry->line,
+						       best_entry->line (),
 						       &best_entry);
 
       /* For optimized code, the compiler can scatter one source line
diff --git a/gdb/mdebugread.c b/gdb/mdebugread.c
index c0bce55148..a12e459cc6 100644
--- a/gdb/mdebugread.c
+++ b/gdb/mdebugread.c
@@ -2213,7 +2213,7 @@ parse_lines (FDR *fh, PDR *pr, struct linetable *lt, int maxlines,
 	halt = base + fh->cbLine;
       base += pr->cbLineOffset;
 
-      adr = pst->textlow + pr->adr - lowest_pdr_addr;
+      adr = pr->adr - lowest_pdr_addr;
 
       l = adr >> 2;		/* in words */
       for (lineno = pr->lnLow; base < halt;)
@@ -4090,10 +4090,7 @@ psymtab_to_symtab_1 (struct objfile *objfile,
 	      else
 		{
 		  /* Handle encoded stab line number.  */
-		  valu += ANOFFSET (section_offsets,
-				    SECT_OFF_TEXT (objfile));
-		  record_line (current_subfile, sh.index,
-			       gdbarch_addr_bits_remove (gdbarch, valu));
+		  record_line (current_subfile, sh.index, valu);
 		}
 	    }
 	  else if (sh.st == stProc || sh.st == stStaticProc
@@ -4634,8 +4631,8 @@ add_line (struct linetable *lt, int lineno, CORE_ADDR adr, int last)
   if (last == lineno)		/* Skip continuation lines.  */
     return lineno;
 
-  lt->item[lt->nitems].line = lineno;
-  lt->item[lt->nitems++].pc = adr << 2;
+  lt->item[lt->nitems].set (lineno, adr << 2);
+  ++lt->nitems;
   return lineno;
 }
 
diff --git a/gdb/mi/mi-symbol-cmds.c b/gdb/mi/mi-symbol-cmds.c
index 223b8c3ce1..ca0fc379a4 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -34,6 +34,7 @@ mi_cmd_symbol_list_lines (const char *command, char **argv, int argc)
   struct symtab *s;
   int i;
   struct ui_out *uiout = current_uiout;
+  struct linetable *linetable;
 
   if (argc != 1)
     error (_("-symbol-list-lines: Usage: SOURCE_FILENAME"));
@@ -51,11 +52,12 @@ mi_cmd_symbol_list_lines (const char *command, char **argv, int argc)
   gdbarch = get_objfile_arch (SYMTAB_OBJFILE (s));
 
   ui_out_emit_list list_emitter (uiout, "lines");
-  if (SYMTAB_LINETABLE (s) != NULL && SYMTAB_LINETABLE (s)->nitems > 0)
-    for (i = 0; i < SYMTAB_LINETABLE (s)->nitems; i++)
+  linetable = SYMTAB_LINETABLE (s);
+  if (linetable != NULL && linetable->nitems > 0)
+    for (i = 0; i < linetable->nitems; i++)
     {
       ui_out_emit_tuple tuple_emitter (uiout, NULL);
-      uiout->field_core_addr ("pc", gdbarch, SYMTAB_LINETABLE (s)->item[i].pc);
-      uiout->field_int ("line", SYMTAB_LINETABLE (s)->item[i].line);
+      uiout->field_core_addr ("pc", gdbarch, linetable->item[i].address (s));
+      uiout->field_int ("line", linetable->item[i].line ());
     }
 }
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index 98e81c48c4..0c1d3ffb57 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -799,23 +799,6 @@ objfile_relocate1 (struct objfile *objfile,
   /* OK, get all the symtabs.  */
   {
     struct compunit_symtab *cust;
-    struct symtab *s;
-
-    ALL_OBJFILE_FILETABS (objfile, cust, s)
-    {
-      struct linetable *l;
-      int i;
-
-      /* First the line table.  */
-      l = SYMTAB_LINETABLE (s);
-      if (l)
-	{
-	  for (i = 0; i < l->nitems; ++i)
-	    l->item[i].pc += ANOFFSET (delta,
-				       COMPUNIT_BLOCK_LINE_SECTION
-					 (cust));
-	}
-    }
 
     ALL_OBJFILE_COMPUNITS (objfile, cust)
     {
diff --git a/gdb/python/py-linetable.c b/gdb/python/py-linetable.c
index c4e80d02a5..c17aac31e8 100644
--- a/gdb/python/py-linetable.c
+++ b/gdb/python/py-linetable.c
@@ -20,6 +20,7 @@
 #include "defs.h"
 #include "python-internal.h"
 #include "py-ref.h"
+#include "objfiles.h"
 
 typedef struct {
   PyObject_HEAD
@@ -204,7 +205,7 @@ ltpy_has_line (PyObject *self, PyObject *args)
   for (index = 0; index < SYMTAB_LINETABLE (symtab)->nitems; index++)
     {
       struct linetable_entry *item = &(SYMTAB_LINETABLE (symtab)->item[index]);
-      if (item->line == py_line)
+      if (item->line () == py_line)
 	  Py_RETURN_TRUE;
     }
 
@@ -242,9 +243,9 @@ ltpy_get_all_source_lines (PyObject *self, PyObject *args)
 
       /* 0 is used to signify end of line table information.  Do not
 	 include in the source set. */
-      if (item->line > 0)
+      if (item->line () > 0)
 	{
-	  gdbpy_ref<> line (gdb_py_object_from_longest (item->line));
+	  gdbpy_ref<> line (gdb_py_object_from_longest (item->line ()));
 
 	  if (line == NULL)
 	    return NULL;
@@ -410,7 +411,7 @@ ltpy_iternext (PyObject *self)
 
   /* Skip over internal entries such as 0.  0 signifies the end of
      line table data and is not useful to the API user.  */
-  while (item->line < 1)
+  while (item->line () < 1)
     {
       iter_obj->current_index++;
 
@@ -423,7 +424,7 @@ ltpy_iternext (PyObject *self)
       item = &(SYMTAB_LINETABLE (symtab)->item[iter_obj->current_index]);
     }
 
-  obj = build_linetable_entry (item->line, item->pc);
+  obj = build_linetable_entry (item->line (), item->address (symtab));
   iter_obj->current_index++;
 
   return obj;
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 8736894243..725ff36551 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -40,6 +40,7 @@
 #include "inf-loop.h"
 #include "vec.h"
 #include <algorithm>
+#include "objfiles.h"
 
 /* The target_ops of record-btrace.  */
 static struct target_ops record_btrace_ops;
@@ -633,8 +634,8 @@ btrace_find_line_range (CORE_ADDR pc)
   range = btrace_mk_line_range (symtab, 0, 0);
   for (i = 0; i < nlines - 1; i++)
     {
-      if ((lines[i].pc == pc) && (lines[i].line != 0))
-	range = btrace_line_range_add (range, lines[i].line);
+      if (lines[i].address (symtab) == pc && lines[i].line () != 0)
+	range = btrace_line_range_add (range, lines[i].line ());
     }
 
   return range;
diff --git a/gdb/symmisc.c b/gdb/symmisc.c
index 9adde044cd..05348b880f 100644
--- a/gdb/symmisc.c
+++ b/gdb/symmisc.c
@@ -302,8 +302,9 @@ dump_symtab_1 (struct symtab *symtab, struct ui_file *outfile)
       len = l->nitems;
       for (i = 0; i < len; i++)
 	{
-	  fprintf_filtered (outfile, " line %d at ", l->item[i].line);
-	  fputs_filtered (paddress (gdbarch, l->item[i].pc), outfile);
+	  fprintf_filtered (outfile, " line %d at ", l->item[i].line ());
+	  fputs_filtered (paddress (gdbarch, l->item[i].address (symtab)),
+			  outfile);
 	  fprintf_filtered (outfile, "\n");
 	}
     }
@@ -1017,8 +1018,8 @@ maintenance_print_one_line_table (struct symtab *symtab, void *data)
 	  struct linetable_entry *item;
 
 	  item = &linetable->item [i];
-	  printf_filtered (_("%-6d %6d %s\n"), i, item->line,
-			   core_addr_to_string (item->pc));
+	  printf_filtered (_("%-6d %6d %s\n"), i, item->line (),
+			   core_addr_to_string (item->address (symtab)));
 	}
     }
 
diff --git a/gdb/symtab.c b/gdb/symtab.c
index c1ead701ec..ad3c4621d0 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -287,6 +287,15 @@ search_domain_name (enum search_domain e)
     }
 }
 
+CORE_ADDR
+linetable_entry::address (struct symtab *symtab) const
+{
+  return gdbarch_addr_bits_remove
+    (get_objfile_arch (SYMTAB_OBJFILE (symtab)),
+     m_pc + ANOFFSET (SYMTAB_OBJFILE (symtab)->section_offsets,
+		      SYMTAB_COMPUNIT (symtab)->block_line_section));
+}
+
 /* See symtab.h.  */
 
 struct symtab *
@@ -3070,6 +3079,7 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
      we will use a line one less than this,
      with a range from the start of that file to the first line's pc.  */
   struct linetable_entry *alt = NULL;
+  struct symtab *alt_symtab = NULL;
 
   /* Info on best line seen in this file.  */
 
@@ -3209,18 +3219,31 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
 
       /* Is this file's first line closer than the first lines of other files?
          If so, record this file, and its first line, as best alternate.  */
-      if (item->pc > pc && (!alt || item->pc < alt->pc))
-	alt = item;
+      if (item->address (iter_s) > pc
+	  && (!alt || (item->address (iter_s) < alt->address (alt_symtab))))
+	{
+	  alt = item;
+	  alt_symtab = iter_s;
+	}
 
-      auto pc_compare = [](const CORE_ADDR & pc,
-			   const struct linetable_entry & lhs)->bool
+      auto pc_compare = [=](const CORE_ADDR & pc,
+			    const struct linetable_entry & lhs)->bool
       {
-	return pc < lhs.pc;
+	return pc < lhs.raw_address ();
       };
 
+      /* We "unrelocate" the incoming PC to make the search
+	 faster.  */
+      CORE_ADDR unrelocated;
+      if (section != nullptr)
+	unrelocated = pc - obj_section_offset (section);
+      else
+	unrelocated = pc - ANOFFSET (SYMTAB_OBJFILE (iter_s)->section_offsets,
+				     SYMTAB_COMPUNIT (iter_s)->block_line_section);
+
       struct linetable_entry *first = item;
       struct linetable_entry *last = item + len;
-      item = std::upper_bound (first, last, pc, pc_compare);
+      item = std::upper_bound (first, last, unrelocated, pc_compare);
       if (item != first)
 	prev = item - 1;		/* Found a matching item.  */
 
@@ -3234,22 +3257,25 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
          save prev if it represents the end of a function (i.e. line number
          0) instead of a real line.  */
 
-      if (prev && prev->line && (!best || prev->pc > best->pc))
+      if (prev
+	  && prev->line ()
+	  && (!best || (prev->address (iter_s) > best->address (best_symtab))))
 	{
 	  best = prev;
 	  best_symtab = iter_s;
 
 	  /* Discard BEST_END if it's before the PC of the current BEST.  */
-	  if (best_end <= best->pc)
+	  if (best_end <= best->address (best_symtab))
 	    best_end = 0;
 	}
 
       /* If another line (denoted by ITEM) is in the linetable and its
 	 PC is after BEST's PC, but before the current BEST_END, then
 	 use ITEM's PC as the new best_end.  */
-      if (best && item < last && item->pc > best->pc
-	  && (best_end == 0 || best_end > item->pc))
-	best_end = item->pc;
+      if (best && item < last
+	  && (item->address (iter_s) > best->address (best_symtab))
+          && (best_end == 0 || best_end > item->address (iter_s)))
+	best_end = item->address (iter_s);
     }
 
   if (!best_symtab)
@@ -3260,7 +3286,7 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
 	 don't make some up.  */
       val.pc = pc;
     }
-  else if (best->line == 0)
+  else if (best->line () == 0)
     {
       /* If our best fit is in a range of PC's for which no line
 	 number info is available (line number is zero) then we didn't
@@ -3270,12 +3296,12 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
   else
     {
       val.symtab = best_symtab;
-      val.line = best->line;
-      val.pc = best->pc;
-      if (best_end && (!alt || best_end < alt->pc))
+      val.line = best->line ();
+      val.pc = best->address (best_symtab);
+      if (best_end && (!alt || best_end < alt->address (alt_symtab)))
 	val.end = best_end;
       else if (alt)
-	val.end = alt->pc;
+	val.end = alt->address (alt_symtab);
       else
 	val.end = BLOCK_END (BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK));
     }
@@ -3355,7 +3381,7 @@ find_line_symtab (struct symtab *symtab, int line,
       struct symtab *s;
 
       if (best_index >= 0)
-	best = best_linetable->item[best_index].line;
+	best = best_linetable->item[best_index].line ();
       else
 	best = 0;
 
@@ -3387,9 +3413,9 @@ find_line_symtab (struct symtab *symtab, int line,
 		best_symtab = s;
 		goto done;
 	      }
-	    if (best == 0 || l->item[ind].line < best)
+	    if (best == 0 || l->item[ind].line () < best)
 	      {
-		best = l->item[ind].line;
+		best = l->item[ind].line ();
 		best_index = ind;
 		best_linetable = l;
 		best_symtab = s;
@@ -3419,6 +3445,7 @@ find_pcs_for_symtab_line (struct symtab *symtab, int line,
 {
   int start = 0;
   std::vector<CORE_ADDR> result;
+  struct linetable *linetable = SYMTAB_LINETABLE (symtab);
 
   /* First, collect all the PCs that are at this line.  */
   while (1)
@@ -3426,22 +3453,21 @@ find_pcs_for_symtab_line (struct symtab *symtab, int line,
       int was_exact;
       int idx;
 
-      idx = find_line_common (SYMTAB_LINETABLE (symtab), line, &was_exact,
-			      start);
+      idx = find_line_common (linetable, line, &was_exact, start);
       if (idx < 0)
 	break;
 
       if (!was_exact)
 	{
-	  struct linetable_entry *item = &SYMTAB_LINETABLE (symtab)->item[idx];
+	  struct linetable_entry *item = &linetable->item[idx];
 
-	  if (*best_item == NULL || item->line < (*best_item)->line)
+	  if (*best_item == NULL || item->line () < (*best_item)->line ())
 	    *best_item = item;
 
 	  break;
 	}
 
-      result.push_back (SYMTAB_LINETABLE (symtab)->item[idx].pc);
+      result.push_back (linetable->item[idx].address (symtab));
       start = idx + 1;
     }
 
@@ -3467,7 +3493,7 @@ find_line_pc (struct symtab *symtab, int line, CORE_ADDR *pc)
   if (symtab != NULL)
     {
       l = SYMTAB_LINETABLE (symtab);
-      *pc = l->item[ind].pc;
+      *pc = l->item[ind].address (symtab);
       return 1;
     }
   else
@@ -3546,16 +3572,16 @@ find_line_common (struct linetable *l, int lineno,
     {
       struct linetable_entry *item = &(l->item[i]);
 
-      if (item->line == lineno)
+      if (item->line () == lineno)
 	{
 	  /* Return the first (lowest address) entry which matches.  */
 	  *exact_match = 1;
 	  return i;
 	}
 
-      if (item->line > lineno && (best == 0 || item->line < best))
+      if (item->line () > lineno && (best == 0 || item->line () < best))
 	{
-	  best = item->line;
+	  best = item->line ();
 	  best_index = i;
 	}
     }
@@ -3656,8 +3682,10 @@ skip_prologue_using_lineinfo (CORE_ADDR func_addr, struct symtab *symtab)
       /* Don't use line numbers of zero, they mark special entries in
 	 the table.  See the commentary on symtab.h before the
 	 definition of struct linetable.  */
-      if (item->line > 0 && func_start <= item->pc && item->pc < func_end)
-	return item->pc;
+      if (item->line () > 0
+	  && func_start <= item->address (symtab)
+	  && item->address (symtab) < func_end)
+	return item->address (symtab);
     }
 
   return func_addr;
@@ -3878,13 +3906,15 @@ skip_prologue_using_sal (struct gdbarch *gdbarch, CORE_ADDR func_addr)
 
 	  /* Skip any earlier lines, and any end-of-sequence marker
 	     from a previous function.  */
-	  while (linetable->item[idx].pc != prologue_sal.pc
-		 || linetable->item[idx].line == 0)
+	  while ((linetable->item[idx].address (prologue_sal.symtab)
+		  != prologue_sal.pc)
+		 || linetable->item[idx].line () == 0)
 	    idx++;
 
 	  if (idx+1 < linetable->nitems
-	      && linetable->item[idx+1].line != 0
-	      && linetable->item[idx+1].pc == start_pc)
+	      && linetable->item[idx+1].line () != 0
+	      && (linetable->item[idx+1].address (prologue_sal.symtab)
+		  == start_pc))
 	    return start_pc;
 	}
 
diff --git a/gdb/symtab.h b/gdb/symtab.h
index f9d52e7697..e85392242c 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -29,6 +29,7 @@
 #include "common/function-view.h"
 #include "common/gdb_optional.h"
 #include "completer.h"
+#include "gdbarch.h"
 
 /* Opaque declarations.  */
 struct ui_file;
@@ -1227,8 +1228,37 @@ struct rust_vtable_symbol : public symbol
 
 struct linetable_entry
 {
-  int line;
-  CORE_ADDR pc;
+  /* Set the members of this object.  */
+  void set (int line_, CORE_ADDR pc)
+  {
+    m_line = line_;
+    m_pc = pc;
+  }
+
+  /* Return the raw address.  */
+  CORE_ADDR raw_address () const
+  {
+    return m_pc;
+  }
+
+  /* Return the relocated address, using the offsets provided by
+     SYMTAB.  */
+  CORE_ADDR address (struct symtab *symtab) const;
+
+  /* Return the line number.  */
+  int line () const
+  {
+    return m_line;
+  }
+
+private:
+
+  int m_line;
+
+  /* Note that the PC as stored is unrelocated.  The appropriate
+     offset must be applied before it can be used; see the "address"
+     method.  */
+  CORE_ADDR m_pc;
 };
 
 /* The order of entries in the linetable is significant.  They should
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 8c707aa8fe..981f7f0716 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -420,7 +420,11 @@ compare_lte (const void *lte1p, const void *lte2p)
   struct linetable_entry *lte1 = (struct linetable_entry *) lte1p;
   struct linetable_entry *lte2 = (struct linetable_entry *) lte2p;
 
-  return lte1->pc - lte2->pc;
+  if (lte1->raw_address () < lte2->raw_address ())
+    return -1;
+  if (lte1->raw_address () > lte2->raw_address ())
+    return 1;
+  return 0;
 }
 
 /* Given a line table with function entries are marked, arrange its
@@ -448,7 +452,7 @@ arrange_linetable (struct linetable *oldLineTb)
 
   for (function_count = 0, ii = 0; ii < oldLineTb->nitems; ++ii)
     {
-      if (oldLineTb->item[ii].line == 0)
+      if (oldLineTb->item[ii].line () == 0)
 	{			/* Function entry found.  */
 	  if (function_count >= fentry_size)
 	    {			/* Make sure you have room.  */
@@ -457,14 +461,15 @@ arrange_linetable (struct linetable *oldLineTb)
 		xrealloc (fentry,
 			  fentry_size * sizeof (struct linetable_entry));
 	    }
-	  fentry[function_count].line = ii;
-	  fentry[function_count].pc = oldLineTb->item[ii].pc;
+	  fentry[function_count].set (ii,
+				      oldLineTb->item[ii].raw_address ());
 	  ++function_count;
 
 	  /* If the function was compiled with XLC, we may have to add an
              extra line entry later.  Reserve space for that.  */
 	  if (ii + 1 < oldLineTb->nitems
-	      && oldLineTb->item[ii].pc != oldLineTb->item[ii + 1].pc)
+	      && (oldLineTb->item[ii].raw_address ()
+		  != oldLineTb->item[ii + 1].raw_address ()))
 	    extra_lines++;
 	}
     }
@@ -488,9 +493,10 @@ arrange_linetable (struct linetable *oldLineTb)
      a function begin.  */
 
   newline = 0;
-  if (oldLineTb->item[0].line != 0)
+  if (oldLineTb->item[0].line () != 0)
     for (newline = 0;
-    newline < oldLineTb->nitems && oldLineTb->item[newline].line; ++newline)
+	 newline < oldLineTb->nitems && oldLineTb->item[newline].line ();
+	 ++newline)
       newLineTb->item[newline] = oldLineTb->item[newline];
 
   /* Now copy function lines one by one.  */
@@ -499,17 +505,18 @@ arrange_linetable (struct linetable *oldLineTb)
     {
       /* If the function was compiled with XLC, we may have to add an
          extra line to cover the function prologue.  */
-      jj = fentry[ii].line;
+      jj = fentry[ii].line ();
       if (jj + 1 < oldLineTb->nitems
-	  && oldLineTb->item[jj].pc != oldLineTb->item[jj + 1].pc)
+	  && (oldLineTb->item[jj].raw_address ()
+	      != oldLineTb->item[jj + 1].raw_address ()))
 	{
-	  newLineTb->item[newline] = oldLineTb->item[jj];
-	  newLineTb->item[newline].line = oldLineTb->item[jj + 1].line;
+	  newLineTb->item[newline].set (oldLineTb->item[jj + 1].line (),
+					oldLineTb->item[jj].raw_address ());
 	  newline++;
 	}
 
-      for (jj = fentry[ii].line + 1;
-	   jj < oldLineTb->nitems && oldLineTb->item[jj].line != 0;
+      for (jj = fentry[ii].line () + 1;
+	   jj < oldLineTb->nitems && oldLineTb->item[jj].line () != 0;
 	   ++jj, ++newline)
 	newLineTb->item[newline] = oldLineTb->item[jj];
     }
@@ -871,6 +878,8 @@ enter_line_range (struct subfile *subfile, unsigned beginoffset,
 
   while (curoffset <= limit_offset)
     {
+      CORE_ADDR relocated;
+
       bfd_seek (abfd, curoffset, SEEK_SET);
       bfd_bread (ext_lnno, linesz, abfd);
       bfd_coff_swap_lineno_in (abfd, ext_lnno, &int_lnno);
@@ -879,20 +888,20 @@ enter_line_range (struct subfile *subfile, unsigned beginoffset,
       addr = (int_lnno.l_lnno
 	      ? int_lnno.l_addr.l_paddr
 	      : read_symbol_nvalue (int_lnno.l_addr.l_symndx));
-      addr += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 
-      if (addr < startaddr || (endaddr && addr >= endaddr))
+      relocated = (addr + ANOFFSET (objfile->section_offsets,
+				    SECT_OFF_TEXT (objfile)));
+      if (relocated < startaddr || (endaddr && relocated >= endaddr))
 	return;
 
       if (int_lnno.l_lnno == 0)
 	{
 	  *firstLine = read_symbol_lineno (int_lnno.l_addr.l_symndx);
-	  record_line (subfile, 0, gdbarch_addr_bits_remove (gdbarch, addr));
+	  record_line (subfile, 0, addr);
 	  --(*firstLine);
 	}
       else
-	record_line (subfile, *firstLine + int_lnno.l_lnno,
-		     gdbarch_addr_bits_remove (gdbarch, addr));
+	record_line (subfile, *firstLine + int_lnno.l_lnno, addr);
       curoffset += linesz;
     }
 }
