Assemble calls to constant addresses.

Finally address this TODO in the assembler. This will help translate
non-IRT using programs (no ABI stability). The default scons testing
mode is non-IRT, so this helps with that. I haven't actually tested
this against scons yet, but I'm filling in the tests based on how
LLVM translates the same bitcode.

The filetype=asm is adjusted to omit the "*" and the "$".

The filetype=obj is adjusted to check for fixups with NullSymbols,
and also fill the assembler buffer at the instruction's immediate
field w/ the right constant.

The filetype=iasm is still TODO (hits an new assert in the Fixup's emit() function).

Reverts 7ad1bed99d058199a3ba246a5383458518596fbc:
"Allow stubbing of called constant addresses using command line argument."
since this is now handled (except for iasm).

BUG= https://code.google.com/p/nativeclient/issues/detail?id=4080
R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/1017373002
diff --git a/src/IceClFlags.h b/src/IceClFlags.h
index 3ddbbf8..6fcbbbb 100644
--- a/src/IceClFlags.h
+++ b/src/IceClFlags.h
@@ -30,8 +30,8 @@
         DecorateAsm(false), DisableInternal(false), DisableIRGeneration(false),
         DisableTranslation(false), DumpStats(false), FunctionSections(false),
         GenerateUnitTestMessages(false), PhiEdgeSplit(false),
-        StubConstantCalls(false), SubzeroTimingEnabled(false),
-        TimeEachFunction(false), UseSandboxing(false),
+        SubzeroTimingEnabled(false), TimeEachFunction(false),
+        UseSandboxing(false),
         // FileType field
         OutFileType(FT_Iasm),
         // IceString fields.
@@ -87,11 +87,6 @@
   bool getPhiEdgeSplit() const { return PhiEdgeSplit; }
   void setPhiEdgeSplit(bool NewValue) { PhiEdgeSplit = NewValue; }
 
-  bool getStubConstantCalls() const {
-    return !ALLOW_MINIMAL_BUILD && StubConstantCalls;
-  }
-  void setStubConstantCalls(bool NewValue) { StubConstantCalls = NewValue; }
-
   bool getSubzeroTimingEnabled() const { return SubzeroTimingEnabled; }
   void setSubzeroTimingEnabled(bool NewValue) {
     SubzeroTimingEnabled = NewValue;
@@ -154,7 +149,6 @@
   bool FunctionSections;
   bool GenerateUnitTestMessages;
   bool PhiEdgeSplit;
-  bool StubConstantCalls;
   bool SubzeroTimingEnabled;
   bool TimeEachFunction;
   bool UseSandboxing;
diff --git a/src/IceELFObjectWriter.cpp b/src/IceELFObjectWriter.cpp
index 230848c..073163a 100644
--- a/src/IceELFObjectWriter.cpp
+++ b/src/IceELFObjectWriter.cpp
@@ -84,10 +84,7 @@
                 "Elf_Sym sizes cannot be derived from sizeof");
   SymTab = createSection<ELFSymbolTableSection>(SymTabName, SHT_SYMTAB, 0,
                                                 SymTabAlign, SymTabEntSize);
-  // The first entry in the symbol table should be a NULL entry.
-  const IceString NullSymName("");
-  SymTab->createDefinedSym(NullSymName, STT_NOTYPE, STB_LOCAL, NullSection, 0,
-                           0);
+  SymTab->createNullSymbol(NullSection);
 
   const IceString StrTabName(".strtab");
   StrTab =
diff --git a/src/IceELFSection.cpp b/src/IceELFSection.cpp
index f2e129d..4ca2de4 100644
--- a/src/IceELFSection.cpp
+++ b/src/IceELFSection.cpp
@@ -80,6 +80,15 @@
 
 // Symbol tables.
 
+void ELFSymbolTableSection::createNullSymbol(ELFSection *NullSection) {
+  // The first entry in the symbol table should be a NULL entry,
+  // so make sure the map is still empty.
+  assert(LocalSymbols.empty());
+  const IceString NullSymName("");
+  createDefinedSym(NullSymName, STT_NOTYPE, STB_LOCAL, NullSection, 0, 0);
+  NullSymbol = findSymbol(NullSymName);
+}
+
 void ELFSymbolTableSection::createDefinedSym(const IceString &Name,
                                              uint8_t Type, uint8_t Binding,
                                              ELFSection *Section,
@@ -105,7 +114,9 @@
   NewSymbol.Sym.setBindingAndType(STB_GLOBAL, STT_NOTYPE);
   NewSymbol.Section = NullSection;
   NewSymbol.Number = ELFSym::UnknownNumber;
-  GlobalSymbols.insert(std::make_pair(Name, NewSymbol));
+  bool Unique = GlobalSymbols.insert(std::make_pair(Name, NewSymbol)).second;
+  assert(Unique);
+  (void)Unique;
 }
 
 const ELFSym *ELFSymbolTableSection::findSymbol(const IceString &Name) const {
diff --git a/src/IceELFSection.h b/src/IceELFSection.h
index 0bfccca..c2ef9bf 100644
--- a/src/IceELFSection.h
+++ b/src/IceELFSection.h
@@ -163,7 +163,11 @@
   ELFSymbolTableSection &operator=(const ELFSymbolTableSection &) = delete;
 
 public:
-  using ELFSection::ELFSection;
+  ELFSymbolTableSection(const IceString &Name, Elf64_Word ShType,
+                        Elf64_Xword ShFlags, Elf64_Xword ShAddralign,
+                        Elf64_Xword ShEntsize)
+      : ELFSection(Name, ShType, ShFlags, ShAddralign, ShEntsize),
+        NullSymbol(nullptr) {}
 
   // Create initial entry for a symbol when it is defined.
   // Each entry should only be defined once.
@@ -179,6 +183,9 @@
 
   const ELFSym *findSymbol(const IceString &Name) const;
 
+  void createNullSymbol(ELFSection *NullSection);
+  const ELFSym *getNullSymbol() const { return NullSymbol; }
+
   size_t getSectionDataSize() const {
     return (LocalSymbols.size() + GlobalSymbols.size()) * Header.sh_entsize;
   }
@@ -198,6 +205,7 @@
   template <bool IsELF64>
   void writeSymbolMap(ELFStreamer &Str, const SymMap &Map);
 
+  const ELFSym *NullSymbol;
   // Keep Local and Global symbols separate, since the sh_info needs to
   // know the index of the last LOCAL.
   SymMap LocalSymbols;
@@ -211,7 +219,11 @@
   ELFRelocationSection &operator=(const ELFRelocationSection &) = delete;
 
 public:
-  using ELFSection::ELFSection;
+  ELFRelocationSection(const IceString &Name, Elf64_Word ShType,
+                       Elf64_Xword ShFlags, Elf64_Xword ShAddralign,
+                       Elf64_Xword ShEntsize)
+      : ELFSection(Name, ShType, ShFlags, ShAddralign, ShEntsize),
+        RelatedSection(nullptr) {}
 
   const ELFSection *getRelatedSection() const { return RelatedSection; }
   void setRelatedSection(const ELFSection *Section) {
@@ -340,7 +352,11 @@
 void ELFRelocationSection::writeData(const GlobalContext &Ctx, ELFStreamer &Str,
                                      const ELFSymbolTableSection *SymTab) {
   for (const AssemblerFixup &Fixup : Fixups) {
-    const ELFSym *Symbol = SymTab->findSymbol(Fixup.symbol(&Ctx));
+    const ELFSym *Symbol;
+    if (Fixup.isNullSymbol())
+      Symbol = SymTab->getNullSymbol();
+    else
+      Symbol = SymTab->findSymbol(Fixup.symbol(&Ctx));
     if (!Symbol)
       llvm::report_fatal_error("Missing symbol mentioned in reloc");
 
diff --git a/src/IceFixups.cpp b/src/IceFixups.cpp
index 52bb0dd..05559c5 100644
--- a/src/IceFixups.cpp
+++ b/src/IceFixups.cpp
@@ -17,7 +17,11 @@
 
 namespace Ice {
 
+const Constant *AssemblerFixup::NullSymbol = nullptr;
+
 RelocOffsetT AssemblerFixup::offset() const {
+  if (isNullSymbol())
+    return 0;
   if (const auto CR = llvm::dyn_cast<ConstantRelocatable>(value_))
     return CR->getOffset();
   return 0;
@@ -27,6 +31,7 @@
   std::string Buffer;
   llvm::raw_string_ostream Str(Buffer);
   const Constant *C = value_;
+  assert(!isNullSymbol());
   if (const auto CR = llvm::dyn_cast<ConstantRelocatable>(C)) {
     if (CR->getSuppressMangling())
       Str << CR->getName();
@@ -43,6 +48,9 @@
 
 void AssemblerFixup::emit(GlobalContext *Ctx) const {
   Ostream &Str = Ctx->getStrEmit();
+  // TODO(jvoung): Not yet clear how to emit a relocation against
+  // the null symbol.
+  assert(!isNullSymbol());
   Str << symbol(Ctx);
   RelocOffsetT Offset = offset();
   if (Offset)
diff --git a/src/IceFixups.h b/src/IceFixups.h
index bbe7d4a..1bc45f3 100644
--- a/src/IceFixups.h
+++ b/src/IceFixups.h
@@ -38,6 +38,10 @@
 
   RelocOffsetT offset() const;
   IceString symbol(const GlobalContext *Ctx) const;
+
+  static const Constant *NullSymbol;
+  bool isNullSymbol() const { return value_ == NullSymbol; }
+
   void set_value(const Constant *Value) { value_ = Value; }
 
   void emit(GlobalContext *Ctx) const;
diff --git a/src/IceInstX8632.cpp b/src/IceInstX8632.cpp
index 776a870..2464567 100644
--- a/src/IceInstX8632.cpp
+++ b/src/IceInstX8632.cpp
@@ -489,11 +489,10 @@
   } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Target)) {
     // NaCl trampoline calls refer to an address within the sandbox directly.
     // This is usually only needed for non-IRT builds and otherwise not
-    // very portable or stable. For this, we would use the 0xE8 opcode
-    // (relative version of call) and there should be a PC32 reloc too.
-    // The PC32 reloc will have symbol index 0, and the absolute address
-    // would be encoded as an offset relative to the next instruction.
-    // TODO(jvoung): Do we need to support this?
+    // very portable or stable. Usually this is only done for "calls"
+    // and not jumps.
+    // TODO(jvoung): Support this when there is a lowering that
+    // actually triggers this case.
     (void)Imm;
     llvm::report_fatal_error("Unexpected jmp to absolute address");
   } else {
@@ -515,10 +514,7 @@
   Ostream &Str = Func->getContext()->getStrEmit();
   assert(getSrcSize() == 1);
   Str << "\tcall\t";
-  if (const auto CallTarget =
-          llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) {
-    // TODO(stichnot): All constant targets should suppress the '$',
-    // not just relocatables.
+  if (const auto CallTarget = llvm::dyn_cast<Constant>(getCallTarget())) {
     CallTarget->emitWithoutDollar(Func->getContext());
   } else {
     Str << "*";
@@ -544,15 +540,7 @@
     assert(CR->getOffset() == 0 && "We only support calling a function");
     Asm->call(CR);
   } else if (const auto Imm = llvm::dyn_cast<ConstantInteger32>(Target)) {
-    // NaCl trampoline calls refer to an address within the sandbox directly.
-    // This is usually only needed for non-IRT builds and otherwise not
-    // very portable or stable. For this, we would use the 0xE8 opcode
-    // (relative version of call) and there should be a PC32 reloc too.
-    // The PC32 reloc will have symbol index 0, and the absolute address
-    // would be encoded as an offset relative to the next instruction.
-    // TODO(jvoung): Do we need to support this?
-    (void)Imm;
-    llvm_unreachable("Unexpected call to absolute address");
+    Asm->call(x86::Immediate(Imm->getValue()));
   } else {
     llvm_unreachable("Unexpected operand type");
   }
diff --git a/src/IceOperand.h b/src/IceOperand.h
index 5630c5c..3bbd02c 100644
--- a/src/IceOperand.h
+++ b/src/IceOperand.h
@@ -108,6 +108,7 @@
   }
   void emit(const Cfg *Func) const override { emit(Func->getContext()); }
   virtual void emit(GlobalContext *Ctx) const = 0;
+  virtual void emitWithoutDollar(GlobalContext *Ctx) const = 0;
 
   static bool classof(const Operand *Operand) {
     OperandKind Kind = Operand->getKind();
@@ -149,6 +150,7 @@
   // The target needs to implement this for each ConstantPrimitive
   // specialization.
   void emit(GlobalContext *Ctx) const override;
+  void emitWithoutDollar(GlobalContext *Ctx) const override;
   using Constant::dump;
   void dump(const Cfg *, Ostream &Str) const override {
     if (ALLOW_DUMP)
@@ -234,7 +236,7 @@
   using Constant::emit;
   using Constant::dump;
   void emit(GlobalContext *Ctx) const override;
-  void emitWithoutDollar(GlobalContext *Ctx) const;
+  void emitWithoutDollar(GlobalContext *Ctx) const override;
   void dump(const Cfg *Func, Ostream &Str) const override;
 
   static bool classof(const Operand *Operand) {
@@ -273,6 +275,7 @@
   using Constant::dump;
   // The target needs to implement this.
   void emit(GlobalContext *Ctx) const override;
+  void emitWithoutDollar(GlobalContext *Ctx) const override;
   void dump(const Cfg *, Ostream &Str) const override {
     if (ALLOW_DUMP)
       Str << "undef";
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index 42f513b..4f619d6 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -4599,17 +4599,34 @@
   }
 }
 
+template <>
+void ConstantInteger32::emitWithoutDollar(GlobalContext *Ctx) const {
+  if (!ALLOW_DUMP)
+    return;
+  Ostream &Str = Ctx->getStrEmit();
+  Str << (int32_t)getValue();
+}
+
 template <> void ConstantInteger32::emit(GlobalContext *Ctx) const {
   if (!ALLOW_DUMP)
     return;
   Ostream &Str = Ctx->getStrEmit();
-  Str << "$" << (int32_t)getValue();
+  Str << "$";
+  emitWithoutDollar(Ctx);
+}
+
+template <> void ConstantInteger64::emitWithoutDollar(GlobalContext *) const {
+  llvm_unreachable("Not expecting to emitWithoutDollar 64-bit integers");
 }
 
 template <> void ConstantInteger64::emit(GlobalContext *) const {
   llvm_unreachable("Not expecting to emit 64-bit integers");
 }
 
+template <> void ConstantFloat::emitWithoutDollar(GlobalContext *) const {
+  llvm_unreachable("Not expecting to emitWithoutDollar floats");
+}
+
 template <> void ConstantFloat::emit(GlobalContext *Ctx) const {
   if (!ALLOW_DUMP)
     return;
@@ -4617,6 +4634,10 @@
   emitPoolLabel(Str);
 }
 
+template <> void ConstantDouble::emitWithoutDollar(GlobalContext *) const {
+  llvm_unreachable("Not expecting to emitWithoutDollar doubles");
+}
+
 template <> void ConstantDouble::emit(GlobalContext *Ctx) const {
   if (!ALLOW_DUMP)
     return;
@@ -4624,6 +4645,10 @@
   emitPoolLabel(Str);
 }
 
+void ConstantUndef::emitWithoutDollar(GlobalContext *) const {
+  llvm_unreachable("Not expecting to emitWithoutDollar undef");
+}
+
 void ConstantUndef::emit(GlobalContext *) const {
   llvm_unreachable("undef value encountered by emitter.");
 }
diff --git a/src/PNaClTranslator.cpp b/src/PNaClTranslator.cpp
index f02d0cb..799ff94 100644
--- a/src/PNaClTranslator.cpp
+++ b/src/PNaClTranslator.cpp
@@ -167,7 +167,7 @@
       : NaClBitcodeParser(Cursor), Translator(Translator),
         ErrorStatus(ErrorStatus), NumErrors(0), NextDefiningFunctionID(0),
         VariableDeclarations(new Ice::VariableDeclarationList()),
-        BlockParser(nullptr), StubbedConstCallValue(nullptr) {}
+        BlockParser(nullptr) {}
 
   ~TopLevelParser() override {}
 
@@ -276,24 +276,6 @@
     createValueIDsForGlobalVars();
   }
 
-  /// Returns a defined function reference to be used in place of
-  /// called constant addresses. Returns the corresponding operand
-  /// to replace the calling address with. Reports an error if
-  /// a stub could not be found, returning the CallValue.
-  Ice::Operand *getStubbedConstCallValue(Ice::Operand *CallValue) {
-    if (StubbedConstCallValue)
-      return StubbedConstCallValue;
-    for (unsigned i = 0; i < getNumFunctionIDs(); ++i) {
-      Ice::FunctionDeclaration *Func = getFunctionByID(i);
-      if (!Func->isProto()) {
-        StubbedConstCallValue = getGlobalConstantByID(i);
-        return StubbedConstCallValue;
-      }
-    }
-    Error("Unable to find function definition to stub constant calls with");
-    return CallValue;
-  }
-
   /// Returns the number of function declarations in the bitcode file.
   unsigned getNumFunctionIDs() const { return FunctionDeclarationList.size(); }
 
@@ -383,8 +365,6 @@
   // The block parser currently being applied. Used for error
   // reporting.
   BlockParserBaseClass *BlockParser;
-  // Value to use to stub constant calls.
-  Ice::Operand *StubbedConstCallValue;
 
   bool ParseBlock(unsigned BlockID) override;
 
@@ -510,8 +490,8 @@
   raw_ostream &OldErrStream = setErrStream(Context->getStrDump());
   NaClBitcodeParser::ErrorAt(Level, Bit, Message);
   setErrStream(OldErrStream);
-  if (Level >= naclbitc::Error
-      && !Translator.getFlags().getAllowErrorRecovery())
+  if (Level >= naclbitc::Error &&
+      !Translator.getFlags().getAllowErrorRecovery())
     Fatal();
   return true;
 }
@@ -677,8 +657,8 @@
 }
 
 // Generates an error Message with the bit address prefixed to it.
-bool BlockParserBaseClass::ErrorAt(
-    naclbitc::ErrorLevel Level, uint64_t Bit, const std::string &Message) {
+bool BlockParserBaseClass::ErrorAt(naclbitc::ErrorLevel Level, uint64_t Bit,
+                                   const std::string &Message) {
   std::string Buffer;
   raw_string_ostream StrBuf(Buffer);
   // Note: If dump routines have been turned off, the error messages
@@ -2507,10 +2487,6 @@
         return;
       }
     } else {
-      if (getFlags().getStubConstantCalls() &&
-          llvm::isa<Ice::ConstantInteger32>(Callee)) {
-        Callee = Context->getStubbedConstCallValue(Callee);
-      }
       ReturnType = Context->getSimpleTypeByID(Values[2]);
     }
 
diff --git a/src/assembler_ia32.cpp b/src/assembler_ia32.cpp
index a57d791..216cea6 100644
--- a/src/assembler_ia32.cpp
+++ b/src/assembler_ia32.cpp
@@ -112,6 +112,17 @@
   (void)call_start;
 }
 
+void AssemblerX86::call(const Immediate &abs_address) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  intptr_t call_start = buffer_.GetPosition();
+  EmitUint8(0xE8);
+  EmitFixup(
+      this->createFixup(llvm::ELF::R_386_PC32, AssemblerFixup::NullSymbol));
+  EmitInt32(abs_address.value() - 4);
+  assert((buffer_.GetPosition() - call_start) == kCallExternalLabelSize);
+  (void)call_start;
+}
+
 void AssemblerX86::pushl(GPRRegister reg) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x50 + reg);
diff --git a/src/assembler_ia32.h b/src/assembler_ia32.h
index a6a0bb4..1781b47 100644
--- a/src/assembler_ia32.h
+++ b/src/assembler_ia32.h
@@ -475,6 +475,7 @@
   void call(GPRRegister reg);
   void call(const Address &address);
   void call(const ConstantRelocatable *label);
+  void call(const Immediate &abs_address);
 
   static const intptr_t kCallExternalLabelSize = 5;
 
diff --git a/src/main.cpp b/src/main.cpp
index 22ab0a1..bd96142 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -176,12 +176,6 @@
     cl::desc("Allow error recovery when reading PNaCl bitcode."),
     cl::init(false));
 
-// TODO(kschimpf) Remove once the emitter handles these cases.
-static cl::opt<bool>
-    StubConstantCalls("stub-const-calls",
-                      cl::desc("Stub indirect calls to constants."),
-                      cl::init(false));
-
 static cl::opt<bool> LLVMVerboseErrors(
     "verbose-llvm-parse-errors",
     cl::desc("Print out more descriptive PNaCl bitcode parse errors when "
@@ -311,7 +305,6 @@
   Flags.setFunctionSections(FunctionSections);
   Flags.setNumTranslationThreads(NumThreads);
   Flags.setPhiEdgeSplit(EnablePhiEdgeSplit);
-  Flags.setStubConstantCalls(StubConstantCalls);
   Flags.setSubzeroTimingEnabled(SubzeroTimingEnabled);
   Flags.setTimeEachFunction(TimeEachFunction);
   Flags.setTimingFocusOn(TimingFocusOn);
diff --git a/tests_lit/llvm2ice_tests/callindirect.pnacl.ll b/tests_lit/llvm2ice_tests/callindirect.pnacl.ll
index dfa605b..b77ae53 100644
--- a/tests_lit/llvm2ice_tests/callindirect.pnacl.ll
+++ b/tests_lit/llvm2ice_tests/callindirect.pnacl.ll
@@ -4,6 +4,9 @@
 
 ; RUN: %p2i --filetype=obj --disassemble -i %s --args -O2 \
 ; RUN:   | FileCheck %s
+; RUN: %if --need=allow_dump --command %p2i --filetype=asm --assemble \
+; RUN:     --disassemble -i %s --args -O2 \
+; RUN:   | %if --need=allow_dump --command FileCheck %s
 ; RUN: %p2i --filetype=obj --disassemble -i %s --args -Om1 \
 ; RUN:   | FileCheck --check-prefix=OPTM1 %s
 
@@ -62,14 +65,23 @@
 ; OPTM1: call [[TARGET]]
 
 ; Calling an absolute address is used for non-IRT PNaCl pexes to directly
-; access syscall trampolines. Do we need to support this?
-; define internal void @CallIndirectConst() {
-; entry:
-;   %__1 = inttoptr i32 66496 to void ()*
-;   call void %__1()
-;   call void %__1()
-;   call void %__1()
-;   call void %__1()
-;   call void %__1()
-;   ret void
-; }
+; access syscall trampolines. This is not really an indirect call, but
+; there is a cast from int to pointer first.
+define internal void @CallConst() {
+entry:
+  %__1 = inttoptr i32 66496 to void ()*
+  call void %__1()
+  call void %__1()
+  call void %__1()
+  ret void
+}
+
+; CHECK-LABEL: CallConst
+; CHECK: e8 bc 03 01 00 call {{[0-9a-f]+}} {{.*}} R_386_PC32 *ABS*
+; CHECK: e8 bc 03 01 00 call {{[0-9a-f]+}} {{.*}} R_386_PC32 *ABS*
+; CHECK: e8 bc 03 01 00 call {{[0-9a-f]+}} {{.*}} R_386_PC32 *ABS*
+;
+; OPTM1-LABEL: CallConst
+; OPTM1: e8 bc 03 01 00 call {{[0-9a-f]+}} {{.*}} R_386_PC32 *ABS*
+; OPTM1: e8 bc 03 01 00 call {{[0-9a-f]+}} {{.*}} R_386_PC32 *ABS*
+; OPTM1: e8 bc 03 01 00 call {{[0-9a-f]+}} {{.*}} R_386_PC32 *ABS*