Track undefined sym in the symtab. Remove hack for missing relocs against undef.

Preliminary linking tests, seems to show that the linker
and objcopy are happy to use 'em on spec2k, and the
result runs! (Had to be careful to clobber the old .s
and .o files to make it's testing the right copy).

Haven't tried crosstests yet.

BUG=none
R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/889613004
diff --git a/src/IceELFObjectWriter.cpp b/src/IceELFObjectWriter.cpp
index 7fcb043..c428c12 100644
--- a/src/IceELFObjectWriter.cpp
+++ b/src/IceELFObjectWriter.cpp
@@ -532,12 +532,23 @@
   writeRelocationSections(IsELF64, RelRODataSections);
 }
 
+void ELFObjectWriter::setUndefinedSyms(const ConstantList &UndefSyms) {
+  for (const Constant *S : UndefSyms) {
+    const auto Sym = llvm::cast<ConstantRelocatable>(S);
+    IceString Name = Sym->getName();
+    assert(Sym->getOffset() == 0);
+    assert(Sym->getSuppressMangling());
+    SymTab->noteUndefinedSym(Name, NullSection);
+    StrTab->add(Name);
+  }
+}
+
 void ELFObjectWriter::writeRelocationSections(bool IsELF64,
                                               RelSectionList &RelSections) {
   for (ELFRelocationSection *RelSec : RelSections) {
     Elf64_Off Offset = alignFileOffset(RelSec->getSectionAlign());
     RelSec->setFileOffset(Offset);
-    RelSec->setSize(RelSec->getSectionDataSize(Ctx, SymTab));
+    RelSec->setSize(RelSec->getSectionDataSize());
     if (IsELF64) {
       RelSec->writeData<true>(Ctx, Str, SymTab);
     } else {
diff --git a/src/IceELFObjectWriter.h b/src/IceELFObjectWriter.h
index 74fee5e..6c44ed5 100644
--- a/src/IceELFObjectWriter.h
+++ b/src/IceELFObjectWriter.h
@@ -33,7 +33,8 @@
 // (2) writeDataSection  (invoke once)
 // (3) writeFunctionCode (must invoke once per function)
 // (4) writeConstantPool (must invoke once per pooled primitive type)
-// (5) writeNonUserSections (invoke once)
+// (5) setUndefinedSyms (invoke once)
+// (6) writeNonUserSections (invoke once)
 //
 // The requirement for writeDataSection to be invoked only once can
 // be relaxed if using -fdata-sections. The requirement to invoke only once
@@ -76,6 +77,9 @@
   // fills the symbol table with labels for each constant pool entry.
   template <typename ConstType> void writeConstantPool(Type Ty);
 
+  // Populate the symbol table with a list of external/undefined symbols.
+  void setUndefinedSyms(const ConstantList &UndefSyms);
+
   // Do final layout and write out the rest of the object file.
   // Finally, patch up the initial ELF header with the final info.
   void writeNonUserSections();
diff --git a/src/IceELFSection.cpp b/src/IceELFSection.cpp
index f6fb526..f2e129d 100644
--- a/src/IceELFSection.cpp
+++ b/src/IceELFSection.cpp
@@ -74,18 +74,8 @@
   }
 }
 
-size_t ELFRelocationSection::getSectionDataSize(
-    const GlobalContext &Ctx, const ELFSymbolTableSection *SymTab) const {
-  size_t NumWriteableRelocs = 0;
-  for (const AssemblerFixup &Fixup : Fixups) {
-    const ELFSym *Symbol = SymTab->findSymbol(Fixup.symbol(&Ctx));
-    // TODO(jvoung): When the symbol table finally tracks everything,
-    // just use the Fixups.size() as the count, and remove the
-    // SymTab and Ctx params.
-    if (Symbol)
-      ++NumWriteableRelocs;
-  }
-  return NumWriteableRelocs * Header.sh_entsize;
+size_t ELFRelocationSection::getSectionDataSize() const {
+  return Fixups.size() * Header.sh_entsize;
 }
 
 // Symbol tables.
diff --git a/src/IceELFSection.h b/src/IceELFSection.h
index db000f4..24ec561 100644
--- a/src/IceELFSection.h
+++ b/src/IceELFSection.h
@@ -217,8 +217,7 @@
   // Track a single additional relocation.
   void addRelocation(const AssemblerFixup &Fixup) { Fixups.push_back(Fixup); }
 
-  size_t getSectionDataSize(const GlobalContext &Ctx,
-                            const ELFSymbolTableSection *SymTab) const;
+  size_t getSectionDataSize() const;
 
   template <bool IsELF64>
   void writeData(const GlobalContext &Ctx, ELFStreamer &Str,
@@ -333,25 +332,23 @@
                                      const ELFSymbolTableSection *SymTab) {
   for (const AssemblerFixup &Fixup : Fixups) {
     const ELFSym *Symbol = SymTab->findSymbol(Fixup.symbol(&Ctx));
-    // TODO(jvoung): Make sure this always succeeds.
-    // We currently don't track data symbols, so they aren't even marked
-    // as undefined symbols.
-    if (Symbol) {
-      if (IsELF64) {
-        Elf64_Rela Rela;
-        Rela.r_offset = Fixup.position();
-        Rela.setSymbolAndType(Symbol->getNumber(), Fixup.kind());
-        Rela.r_addend = Fixup.offset();
-        Str.writeAddrOrOffset<IsELF64>(Rela.r_offset);
-        Str.writeELFXword<IsELF64>(Rela.r_info);
-        Str.writeELFXword<IsELF64>(Rela.r_addend);
-      } else {
-        Elf32_Rel Rel;
-        Rel.r_offset = Fixup.position();
-        Rel.setSymbolAndType(Symbol->getNumber(), Fixup.kind());
-        Str.writeAddrOrOffset<IsELF64>(Rel.r_offset);
-        Str.writeELFWord<IsELF64>(Rel.r_info);
-      }
+    if (!Symbol)
+      llvm::report_fatal_error("Missing symbol mentioned in reloc");
+
+    if (IsELF64) {
+      Elf64_Rela Rela;
+      Rela.r_offset = Fixup.position();
+      Rela.setSymbolAndType(Symbol->getNumber(), Fixup.kind());
+      Rela.r_addend = Fixup.offset();
+      Str.writeAddrOrOffset<IsELF64>(Rela.r_offset);
+      Str.writeELFXword<IsELF64>(Rela.r_info);
+      Str.writeELFXword<IsELF64>(Rela.r_addend);
+    } else {
+      Elf32_Rel Rel;
+      Rel.r_offset = Fixup.position();
+      Rel.setSymbolAndType(Symbol->getNumber(), Fixup.kind());
+      Str.writeAddrOrOffset<IsELF64>(Rel.r_offset);
+      Str.writeELFWord<IsELF64>(Rel.r_info);
     }
   }
 }
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index 8805cea..7b782e9 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -105,6 +105,8 @@
   TypePool<IceType_i32, int32_t, ConstantInteger32> Integers32;
   TypePool<IceType_i64, int64_t, ConstantInteger64> Integers64;
   TypePool<IceType_i32, RelocatableTuple, ConstantRelocatable> Relocatables;
+  TypePool<IceType_i32, RelocatableTuple, ConstantRelocatable>
+      ExternRelocatables;
   UndefPool Undefs;
 };
 
@@ -422,6 +424,13 @@
       this, RelocatableTuple(Offset, Name, SuppressMangling));
 }
 
+Constant *GlobalContext::getConstantExternSym(const IceString &Name) {
+  const RelocOffsetT Offset = 0;
+  const bool SuppressMangling = true;
+  return getConstPool()->ExternRelocatables.getOrAdd(
+      this, RelocatableTuple(Offset, Name, SuppressMangling));
+}
+
 Constant *GlobalContext::getConstantUndef(Type Ty) {
   return getConstPool()->Undefs.getOrAdd(this, Ty);
 }
@@ -494,6 +503,10 @@
   llvm_unreachable("Unknown type");
 }
 
+ConstantList GlobalContext::getConstantExternSyms() {
+  return getConstPool()->ExternRelocatables.getConstantPool();
+}
+
 TimerStackIdT GlobalContext::newTimerStackID(const IceString &Name) {
   if (!ALLOW_DUMP)
     return 0;
diff --git a/src/IceGlobalContext.h b/src/IceGlobalContext.h
index 79c23d6..2bb8f62 100644
--- a/src/IceGlobalContext.h
+++ b/src/IceGlobalContext.h
@@ -188,6 +188,7 @@
   // Returns a symbolic constant.
   Constant *getConstantSym(RelocOffsetT Offset, const IceString &Name,
                            bool SuppressMangling);
+  Constant *getConstantExternSym(const IceString &Name);
   // Returns an undef.
   Constant *getConstantUndef(Type Ty);
   // Returns a zero value.
@@ -195,6 +196,8 @@
   // getConstantPool() returns a copy of the constant pool for
   // constants of a given type.
   ConstantList getConstantPool(Type Ty);
+  // Returns a copy of the list of external symbols.
+  ConstantList getConstantExternSyms();
 
   const ClFlags &getFlags() const { return Flags; }
 
diff --git a/src/IceTargetLoweringX8632.h b/src/IceTargetLoweringX8632.h
index de0e925..25e33a1 100644
--- a/src/IceTargetLoweringX8632.h
+++ b/src/IceTargetLoweringX8632.h
@@ -153,12 +153,11 @@
   OperandX8632Mem *FormMemoryOperand(Operand *Ptr, Type Ty);
 
   Variable *makeReg(Type Ty, int32_t RegNum = Variable::NoRegister);
+  // Make a call to an external helper function.
   InstCall *makeHelperCall(const IceString &Name, Variable *Dest,
                            SizeT MaxSrcs) {
-    const bool SuppressMangling = true;
     const bool HasTailCall = false;
-    const RelocOffsetT Offset = 0;
-    Constant *CallTarget = Ctx->getConstantSym(Offset, Name, SuppressMangling);
+    Constant *CallTarget = Ctx->getConstantExternSym(Name);
     InstCall *Call =
         InstCall::create(Func, MaxSrcs, Dest, CallTarget, HasTailCall);
     return Call;
diff --git a/src/llvm2ice.cpp b/src/llvm2ice.cpp
index 702d0b1..a98c75d 100644
--- a/src/llvm2ice.cpp
+++ b/src/llvm2ice.cpp
@@ -398,6 +398,7 @@
 
   if (UseELFWriter) {
     Ice::TimerMarker T1(Ice::TimerStack::TT_emit, &Ctx);
+    Ctx.getObjectWriter()->setUndefinedSyms(Ctx.getConstantExternSyms());
     Ctx.getObjectWriter()->writeNonUserSections();
   }
   if (SubzeroTimingEnabled)
diff --git a/tests_lit/llvm2ice_tests/elf_container.ll b/tests_lit/llvm2ice_tests/elf_container.ll
index 2f62911..d8b6ad0 100644
--- a/tests_lit/llvm2ice_tests/elf_container.ll
+++ b/tests_lit/llvm2ice_tests/elf_container.ll
@@ -385,12 +385,8 @@
 ; CHECK:     0x24 R_386_32 .L$double$0 0x0
 ; CHECK:     0x2C R_386_32 .L$double$1 0x0
 ; CHECK:     0x34 R_386_32 .L$double$2 0x0
-; The set of relocations between llvm-mc and integrated elf-writer
-; are different. The integrated elf-writer does not yet handle
-; external/undef functions like memcpy.  Also, it does not resolve internal
-; function calls and instead writes out the relocation. However, there's
-; probably some function call so check for a PC32 relocation at least.
-; CHECK:     0x{{.*}} R_386_PC32
+; CHECK:     0x{{.*}} R_386_PC32 memcpy
+; CHECK:     0x{{.*}} R_386_PC32 memset
 ; CHECK:   }
 ; CHECK:   Section ({{[0-9]+}}) .rel.data {
 ; The set of relocations between llvm-mc and the integrated elf-writer
@@ -617,4 +613,22 @@
 ; CHECK-NEXT:     Other: 0
 ; CHECK-NEXT:     Section: .text
 ; CHECK-NEXT:   }
+; CHECK:        Symbol {
+; CHECK:          Name: memcpy
+; CHECK-NEXT:     Value: 0x0
+; CHECK-NEXT:     Size: 0
+; CHECK-NEXT:     Binding: Global
+; CHECK-NEXT:     Type: None
+; CHECK-NEXT:     Other: 0
+; CHECK-NEXT:     Section: Undefined
+; CHECK-NEXT:   }
+; CHECK:        Symbol {
+; CHECK:          Name: memset
+; CHECK-NEXT:     Value: 0x0
+; CHECK-NEXT:     Size: 0
+; CHECK-NEXT:     Binding: Global
+; CHECK-NEXT:     Type: None
+; CHECK-NEXT:     Other: 0
+; CHECK-NEXT:     Section: Undefined
+; CHECK-NEXT:   }
 ; CHECK: ]