Merge "Add stub for x86 & x86_64."
diff --git a/cpu_ref/linkloader/include/ELFSectionProgBits.h b/cpu_ref/linkloader/include/ELFSectionProgBits.h
index 3a973f7..a642b16 100644
--- a/cpu_ref/linkloader/include/ELFSectionProgBits.h
+++ b/cpu_ref/linkloader/include/ELFSectionProgBits.h
@@ -44,19 +44,27 @@
   ELFSectionProgBits(int machine) {
     switch(machine) {
     case EM_ARM:
-        stubs = new StubLayoutARM();
+      stubs = new StubLayoutARM();
       break;
 
     case EM_AARCH64:
-        stubs = new StubLayoutAARCH64();
+      stubs = new StubLayoutAARCH64();
       break;
 
     case EM_MIPS:
-        stubs = new StubLayoutMIPS();
+      stubs = new StubLayoutMIPS();
+      break;
+
+    case EM_386:
+      stubs = new StubLayoutX86();
+      break;
+
+    case EM_X86_64:
+      stubs = new StubLayoutX86_64();
       break;
 
     default:
-        stubs = NULL;
+      stubs = NULL;
     }
   }
 
diff --git a/cpu_ref/linkloader/include/StubLayout.h b/cpu_ref/linkloader/include/StubLayout.h
index 436c18e..0c2e950 100644
--- a/cpu_ref/linkloader/include/StubLayout.h
+++ b/cpu_ref/linkloader/include/StubLayout.h
@@ -69,5 +69,22 @@
   virtual void setStubAddress(void *stub, void *addr);
 };
 
+class StubLayoutX86 : public StubLayout {
+public:
+  StubLayoutX86() { }
+  size_t getUnitStubSize() const;
+
+private:
+  virtual void setStubAddress(void *stub, void *addr);
+};
+
+class StubLayoutX86_64 : public StubLayout {
+public:
+  StubLayoutX86_64() { }
+  size_t getUnitStubSize() const;
+
+private:
+  virtual void setStubAddress(void *stub, void *addr);
+};
 
 #endif // STUB_LAYOUT_H
diff --git a/cpu_ref/linkloader/lib/StubLayout.cpp b/cpu_ref/linkloader/lib/StubLayout.cpp
index 609ec76..08842e8 100644
--- a/cpu_ref/linkloader/lib/StubLayout.cpp
+++ b/cpu_ref/linkloader/lib/StubLayout.cpp
@@ -128,3 +128,36 @@
   stub[2] = 0x03200008ul; // jr (jump register)
   stub[3] = 0x00000000ul; // nop
 }
+
+size_t StubLayoutX86::getUnitStubSize() const {
+  return 8;
+}
+
+void StubLayoutX86::setStubAddress(void *stub_, void *addr) {
+  uint8_t *stub = (uint8_t *)stub_;
+  stub[0] = 0xE9; // 32-bit pc-relative jump.
+  void **target = (void **)(stub + 1);
+  *target = addr;
+}
+
+size_t StubLayoutX86_64::getUnitStubSize() const {
+  return 16;
+}
+
+void StubLayoutX86_64::setStubAddress(void *stub_, void *addr) {
+  // x86 doesn't have proper register/mem to store the jump destination
+  // use below instructions to jump to the specified address
+
+  // jmp *0x0(%rip);       jump to the location which is stored in next instruction
+  // addr;                 this is not a real instruction, just an address
+  uint8_t *stub = (uint8_t*)stub_;
+  stub[0] = 0xff;
+  stub[1] = 0x25;
+  stub[2] = 0x0;
+  stub[3] = 0x0;
+  stub[4] = 0x0;
+  stub[5] = 0x0;
+  uint64_t *target = reinterpret_cast<uint64_t*>(stub + 6);
+  *target = reinterpret_cast<uint64_t>(addr);
+}
+