diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 7acb89ad0718..ee5293cfee37 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -352,19 +352,19 @@ public:
 // DefinedRegular symbols.
 template <class ELFT> struct ElfSym {
   // The content for __ehdr_start symbol.
-  static DefinedRegular<ELFT> *EhdrStart;
+  static DefinedSynthetic *EhdrStart;
 
   // The content for _etext and etext symbols.
-  static DefinedRegular<ELFT> *Etext;
-  static DefinedRegular<ELFT> *Etext2;
+  static DefinedSynthetic *Etext;
+  static DefinedSynthetic *Etext2;
 
   // The content for _edata and edata symbols.
-  static DefinedRegular<ELFT> *Edata;
-  static DefinedRegular<ELFT> *Edata2;
+  static DefinedSynthetic *Edata;
+  static DefinedSynthetic *Edata2;
 
   // The content for _end and end symbols.
-  static DefinedRegular<ELFT> *End;
-  static DefinedRegular<ELFT> *End2;
+  static DefinedSynthetic *End;
+  static DefinedSynthetic *End2;
 
   // The content for _gp_disp/__gnu_local_gp symbols for MIPS target.
   static DefinedRegular<ELFT> *MipsGpDisp;
@@ -372,13 +372,13 @@ template <class ELFT> struct ElfSym {
   static DefinedRegular<ELFT> *MipsGp;
 };
 
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::EhdrStart;
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext;
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext2;
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata;
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata2;
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End;
-template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End2;
+template <class ELFT> DefinedSynthetic *ElfSym<ELFT>::EhdrStart;
+template <class ELFT> DefinedSynthetic *ElfSym<ELFT>::Etext;
+template <class ELFT> DefinedSynthetic *ElfSym<ELFT>::Etext2;
+template <class ELFT> DefinedSynthetic *ElfSym<ELFT>::Edata;
+template <class ELFT> DefinedSynthetic *ElfSym<ELFT>::Edata2;
+template <class ELFT> DefinedSynthetic *ElfSym<ELFT>::End;
+template <class ELFT> DefinedSynthetic *ElfSym<ELFT>::End2;
 template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsGpDisp;
 template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsLocalGp;
 template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsGp;
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 0715bf04d6de..cee6eb729fdb 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -68,7 +68,7 @@ private:
   void setPhdrs();
   void fixHeaders();
   void fixSectionAlignments();
-  void fixAbsoluteSymbols();
+  void fixPredefinedSymbols();
   void openFile();
   void writeHeader();
   void writeSections();
@@ -208,7 +208,7 @@ template <class ELFT> void Writer<ELFT>::run() {
       assignFileOffsetsBinary();
 
     setPhdrs();
-    fixAbsoluteSymbols();
+    fixPredefinedSymbols();
   }
 
   // It does not make sense try to open the file if we have error already.
@@ -648,12 +648,14 @@ void PhdrEntry::add(OutputSectionBase *Sec) {
 }
 
 template <class ELFT>
-static void addOptionalSynthetic(StringRef Name, OutputSectionBase *Sec,
-                                 typename ELFT::uint Val,
-                                 uint8_t StOther = STV_HIDDEN) {
+static DefinedSynthetic *
+addOptionalSynthetic(StringRef Name, OutputSectionBase *Sec,
+                     typename ELFT::uint Val, uint8_t StOther = STV_HIDDEN) {
   if (SymbolBody *S = Symtab<ELFT>::X->find(Name))
     if (!S->isInCurrentDSO())
-      Symtab<ELFT>::X->addSynthetic(Name, Sec, Val, StOther);
+      return cast<DefinedSynthetic>(
+          Symtab<ELFT>::X->addSynthetic(Name, Sec, Val, StOther)->body());
+  return nullptr;
 }
 
 template <class ELFT>
@@ -750,14 +752,16 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
   if (ScriptConfig->HasSections)
     return;
 
-  ElfSym<ELFT>::EhdrStart = Symtab<ELFT>::X->addIgnored("__ehdr_start");
+  // __ehdr_start is the location of program headers.
+  ElfSym<ELFT>::EhdrStart =
+      addOptionalSynthetic<ELFT>("__ehdr_start", Out<ELFT>::ProgramHeaders, 0);
 
-  auto Define = [this](StringRef S, DefinedRegular<ELFT> *&Sym1,
-                       DefinedRegular<ELFT> *&Sym2) {
-    Sym1 = Symtab<ELFT>::X->addIgnored(S, STV_DEFAULT);
+  auto Define = [this](StringRef S, DefinedSynthetic *&Sym1,
+                       DefinedSynthetic *&Sym2) {
+    Sym1 = addOptionalSynthetic<ELFT>(S, nullptr, 0, STV_DEFAULT);
     assert(S.startswith("_"));
     S = S.substr(1);
-    Sym2 = Symtab<ELFT>::X->addIgnored(S, STV_DEFAULT);
+    Sym2 = addOptionalSynthetic<ELFT>(S, nullptr, 0, STV_DEFAULT);
   };
 
   Define("_end", ElfSym<ELFT>::End, ElfSym<ELFT>::End2);
@@ -1056,6 +1060,11 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
 
   sortSections();
 
+  // This is a bit of a hack. A value of 0 means undef, so we set it
+  // to 1 t make __ehdr_start defined. The section number is not
+  // particularly relevant.
+  Out<ELFT>::ProgramHeaders->SectionIndex = 1;
+
   unsigned I = 1;
   for (OutputSectionBase *Sec : OutputSections) {
     Sec->SectionIndex = I++;
@@ -1548,34 +1557,44 @@ static uint16_t getELFType() {
 }
 
 // This function is called after we have assigned address and size
-// to each section. This function fixes some predefined absolute
+// to each section. This function fixes some predefined
 // symbol values that depend on section address and size.
-template <class ELFT> void Writer<ELFT>::fixAbsoluteSymbols() {
-  // __ehdr_start is the location of program headers.
-  if (ElfSym<ELFT>::EhdrStart)
-    ElfSym<ELFT>::EhdrStart->Value = Out<ELFT>::ProgramHeaders->Addr;
-
-  auto Set = [](DefinedRegular<ELFT> *S1, DefinedRegular<ELFT> *S2, uintX_t V) {
-    if (S1)
-      S1->Value = V;
-    if (S2)
-      S2->Value = V;
+template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() {
+  auto Set = [](DefinedSynthetic *S1, DefinedSynthetic *S2,
+                OutputSectionBase *Sec, uint64_t Value) {
+    if (S1) {
+      S1->Section = Sec;
+      S1->Value = Value;
+    }
+    if (S2) {
+      S2->Section = Sec;
+      S2->Value = Value;
+    }
   };
 
   // _etext is the first location after the last read-only loadable segment.
   // _edata is the first location after the last read-write loadable segment.
   // _end is the first location after the uninitialized data region.
+  PhdrEntry *Last = nullptr;
+  PhdrEntry *LastRO = nullptr;
+  PhdrEntry *LastRW = nullptr;
   for (PhdrEntry &P : Phdrs) {
     if (P.p_type != PT_LOAD)
       continue;
-    Set(ElfSym<ELFT>::End, ElfSym<ELFT>::End2, P.p_vaddr + P.p_memsz);
-
-    uintX_t Val = P.p_vaddr + P.p_filesz;
+    Last = &P;
     if (P.p_flags & PF_W)
-      Set(ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2, Val);
+      LastRW = &P;
     else
-      Set(ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2, Val);
+      LastRO = &P;
   }
+  if (Last)
+    Set(ElfSym<ELFT>::End, ElfSym<ELFT>::End2, Last->First, Last->p_memsz);
+  if (LastRO)
+    Set(ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2, LastRO->First,
+        LastRO->p_filesz);
+  if (LastRW)
+    Set(ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2, LastRW->First,
+        LastRW->p_filesz);
 
   // Setup MIPS _gp_disp/__gnu_local_gp symbols which should
   // be equal to the _gp symbol's value.
diff --git a/lld/test/ELF/edata-etext.s b/lld/test/ELF/edata-etext.s
index 7723adf94e23..3b0ba49ad1af 100644
--- a/lld/test/ELF/edata-etext.s
+++ b/lld/test/ELF/edata-etext.s
@@ -18,9 +18,9 @@
 # CHECK-NEXT:    3 .bss          00000006 0000000000202004 BSS
 # CHECK:      SYMBOL TABLE:
 # CHECK-NEXT:  0000000000000000         *UND* 00000000
-# CHECK-NEXT:  0000000000202002         *ABS* 00000000 _edata
-# CHECK-NEXT:  000000000020200a         *ABS* 00000000 _end
-# CHECK-NEXT:  0000000000201001         *ABS* 00000000 _etext
+# CHECK-NEXT:  0000000000202002         .data 00000000 _edata
+# CHECK-NEXT:  000000000020200a         .data 00000000 _end
+# CHECK-NEXT:  0000000000201001         .text 00000000 _etext
 # CHECK-NEXT:  0000000000201000         .text 00000000 _start
 
 # RUN: ld.lld -r %t.o -o %t2
diff --git a/lld/test/ELF/ehdr_start.s b/lld/test/ELF/ehdr_start.s
index 9172feca5e9c..67d23cf7164e 100644
--- a/lld/test/ELF/ehdr_start.s
+++ b/lld/test/ELF/ehdr_start.s
@@ -3,7 +3,7 @@
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
 # RUN: ld.lld %t.o -o %t
 # RUN: llvm-objdump -t %t | FileCheck %s
-# CHECK: 0000000000200040 *ABS* 00000000 .hidden __ehdr_start
+# CHECK: 0000000000200040 .text 00000000 .hidden __ehdr_start
 
 .text
 .global _start, __ehdr_start
diff --git a/lld/test/ELF/end-abs.s b/lld/test/ELF/end-abs.s
new file mode 100644
index 000000000000..2199ce23ad04
--- /dev/null
+++ b/lld/test/ELF/end-abs.s
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t -pie
+# RUN: llvm-readobj -r %t | FileCheck %s
+
+# CHECK:      Relocations [
+# CHECK-NEXT: ]
+
+.global _start
+_start:
+.long _end - .