Index: llvm/lib/XRay/InstrumentationMap.cpp
===================================================================
--- llvm/lib/XRay/InstrumentationMap.cpp
+++ llvm/lib/XRay/InstrumentationMap.cpp
@@ -12,12 +12,14 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/XRay/InstrumentationMap.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/None.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Object/Binary.h"
+#include "llvm/Object/ELFObjectFile.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/DataExtractor.h"
 #include "llvm/Support/Error.h"
@@ -79,6 +81,27 @@
     return errorCodeToError(
         std::make_error_code(std::errc::executable_format_error));
 
+  using RelocMap = DenseMap<uint64_t, uint64_t>;
+  RelocMap Relocs;
+
+  if (ObjFile.getBinary()->isELF()) {
+    for (const object::SectionRef &Section : Sections) {
+      // Skip sections that will never have any relocations.
+      if (Section.isBSS() || Section.isVirtual())
+        continue;
+
+      for (const object::RelocationRef &Reloc : Section.relocations()) {
+        // We assume the R_*_RELATIVE relocations are being used so we
+        // compute the addend here and later use it as the value. This
+        // logic will need to be extended if other relocation types are
+        // ever being used.
+        auto AddendOrErr = object::ELFRelocationRef(Reloc).getAddend();
+        if (AddendOrErr)
+          Relocs.insert({Reloc.getOffset(), *AddendOrErr});
+      }
+    }
+  }
+
   // Copy the instrumentation map data into the Sleds data structure.
   auto C = Contents.bytes_begin();
   static constexpr size_t ELF64SledEntrySize = 32;
@@ -89,6 +112,17 @@
               "an XRay sled entry in ELF64."),
         std::make_error_code(std::errc::executable_format_error));
 
+  auto RelocIfNeeded = [&](DataExtractor &Extractor, uint32_t *Offset) {
+    uint64_t Address = I->getAddress() + C - Contents.bytes_begin() + *Offset;
+    uint64_t Value = Extractor.getU64(Offset);
+    if (!Value) {
+      RelocMap::const_iterator R = Relocs.find(Address);
+      if (R != Relocs.end())
+        return R->second;
+    }
+    return Value;
+  };
+
   int32_t FuncId = 1;
   uint64_t CurFn = 0;
   for (; C != Contents.bytes_end(); C += ELF64SledEntrySize) {
@@ -98,8 +132,8 @@
     Sleds.push_back({});
     auto &Entry = Sleds.back();
     uint32_t OffsetPtr = 0;
-    Entry.Address = Extractor.getU64(&OffsetPtr);
-    Entry.Function = Extractor.getU64(&OffsetPtr);
+    Entry.Address = RelocIfNeeded(Extractor, &OffsetPtr);
+    Entry.Function = RelocIfNeeded(Extractor, &OffsetPtr);
     auto Kind = Extractor.getU8(&OffsetPtr);
     static constexpr SledEntry::FunctionKinds Kinds[] = {
         SledEntry::FunctionKinds::ENTRY, SledEntry::FunctionKinds::EXIT,
Index: llvm/test/tools/llvm-xray/X86/extract-instrmap-pie.ll
===================================================================
--- /dev/null
+++ llvm/test/tools/llvm-xray/X86/extract-instrmap-pie.ll
@@ -0,0 +1,11 @@
+; This test makes sure we can extract the instrumentation map from an
+; XRay-instrumented PIE file.
+;
+; RUN: llvm-xray extract %S/Inputs/elf64-pie.bin -s | FileCheck %s
+
+; CHECK:      ---
+; CHECK-NEXT: - { id: 1, address: 0x00000000000299C0, function: 0x00000000000299C0, kind: function-enter, always-instrument: true, function-name: {{.*foo.*}} }
+; CHECK-NEXT: - { id: 1, address: 0x00000000000299D0, function: 0x00000000000299C0, kind: function-exit, always-instrument: true, function-name: {{.*foo.*}} }
+; CHECK-NEXT: - { id: 2, address: 0x00000000000299E0, function: 0x00000000000299E0, kind: function-enter, always-instrument: true, function-name: {{.*bar.*}} }
+; CHECK-NEXT: - { id: 2, address: 0x00000000000299F6, function: 0x00000000000299E0, kind: function-exit, always-instrument: true, function-name: {{.*bar.*}} }
+; CHECK-NEXT: ...