Index: llvm/include/llvm/Object/ELFObjectFile.h
===================================================================
--- llvm/include/llvm/Object/ELFObjectFile.h
+++ llvm/include/llvm/Object/ELFObjectFile.h
@@ -798,8 +798,9 @@
 template <class ELFT>
 bool ELFObjectFile<ELFT>::isBerkeleyData(DataRefImpl Sec) const {
   const Elf_Shdr *EShdr = getSection(Sec);
-  return !isBerkeleyText(Sec) && EShdr->sh_type != ELF::SHT_NOBITS &&
-         EShdr->sh_flags & ELF::SHF_ALLOC;
+  return !ELFObjectFile<ELFT>::isBerkeleyText(Sec) &&
+          EShdr->sh_type != ELF::SHT_NOBITS &&
+           EShdr->sh_flags & ELF::SHF_ALLOC;
 }
 
 template <class ELFT>
Index: llvm/include/llvm/Object/MutableELFObject.h
===================================================================
--- /dev/null
+++ llvm/include/llvm/Object/MutableELFObject.h
@@ -0,0 +1,236 @@
+//===-- MutableELFObject.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_MUTABLEELFOBJECT_H
+#define LLVM_OBJECT_MUTABLEELFOBJECT_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Object/ELFObjectFile.h"
+
+namespace llvm {
+namespace object {
+
+// T is a wrapper type around Iterable::value_type and must have a constructor
+// taking an Iterable::value_type.
+template <typename T> class MutableRange {
+public:
+  struct MappingType {
+    uintptr_t Ptr;
+    bool New;
+
+    MappingType(bool New, uintptr_t Ptr) : Ptr(Ptr), New(New) {}
+  };
+
+  using iterator = typename std::vector<MappingType>::iterator;
+  using value_type = MappingType;
+
+private:
+  std::vector<MappingType> Mappings;
+  std::vector<T> NewValues;
+
+public:
+  template <typename Iterable>
+  MutableRange(
+      Iterable Range,
+      function_ref<uintptr_t(typename Iterable::iterator::value_type)> Extract)
+      : MutableRange(Range.begin(), Range.end(), Extract) {}
+
+  template <typename Iter>
+  MutableRange(Iter Begin, Iter End,
+               function_ref<uintptr_t(typename Iter::value_type)> Extract) {
+    std::transform(Begin, End, std::back_inserter(Mappings),
+                   [&Extract](typename Iter::value_type Value) {
+                     return MappingType(false, Extract(Value));
+                   });
+  }
+
+  MappingType operator[](uint64_t Index) const { return Mappings[Index]; }
+
+  size_t size() const { return Mappings.size(); }
+
+  iterator begin() { return Mappings.begin(); }
+  iterator end() { return Mappings.end(); }
+
+  const T *getNew(uint64_t Index) const { return &NewValues[Index]; }
+  T *getNew(uint64_t Index) { return &NewValues[Index]; }
+
+  template <typename... Args>
+  T *makeMutable(uint64_t Index, Args &&... Arguments) {
+    MappingType Mapping = Mappings[Index];
+    if (Mapping.New)
+      return &NewValues[reinterpret_cast<uintptr_t>(Mapping.Ptr)];
+    NewValues.emplace_back(Mapping.Ptr, Arguments...);
+    Mappings[Index] = MappingType(true, NewValues.size() - 1);
+    return &NewValues.back();
+  }
+};
+
+template <typename ELFT> class MutableELFObject;
+
+static inline DataRefImpl toDataRef(uintptr_t Ptr) {
+  DataRefImpl Ref;
+  Ref.p = Ptr;
+  return Ref;
+}
+
+template <typename ELFT> struct MutableELFSection {
+  Elf_Shdr_Impl<ELFT> Header;
+  std::string Name;
+  OwningArrayRef<uint8_t> Data;
+
+  MutableELFSection(uintptr_t ToCopy, const MutableELFObject<ELFT> *ObjFile)
+      : Header(*ObjFile->getSection(toDataRef(ToCopy))),
+        Data(OwningArrayRef<uint8_t>(Header.sh_size)) {
+    ::memcpy(Data.data(), ObjFile->base() + Header.sh_offset, Header.sh_size);
+  }
+
+  void setData(ArrayRef<uint8_t> Ref) {
+    Data = OwningArrayRef<uint8_t>(Ref);
+    Header.sh_size = Data.size();
+  }
+};
+
+template <typename ELFT> class MutableELFObject : public ELFObjectFile<ELFT> {
+  friend struct MutableELFSection<ELFT>;
+
+  MutableRange<MutableELFSection<ELFT>> Sections;
+
+protected:
+  using MappingType =
+      typename MutableRange<MutableELFSection<ELFT>>::MappingType;
+
+  // Returns DataRef with pointer to the correct section header.
+  DataRefImpl getSectionRef(DataRefImpl Sec) const {
+    MappingType Mapping = Sections[Sec.p];
+    return Mapping.New ? toDataRef(reinterpret_cast<uintptr_t>(
+                             &Sections.getNew(Mapping.Ptr)->Header))
+                       : toDataRef(Mapping.Ptr);
+  }
+
+  void moveSectionNext(DataRefImpl &Sec) const override;
+  Expected<StringRef> getSectionName(DataRefImpl Sec) const override;
+  uint64_t getSectionAddress(DataRefImpl Sec) const override;
+  uint64_t getSectionIndex(DataRefImpl Sec) const override;
+  uint64_t getSectionSize(DataRefImpl Sec) const override;
+  Expected<ArrayRef<uint8_t>>
+  getSectionContents(DataRefImpl Sec) const override;
+  uint64_t getSectionAlignment(DataRefImpl Sec) const override;
+  bool isSectionCompressed(DataRefImpl Sec) const override;
+  bool isSectionText(DataRefImpl Sec) const override;
+  bool isSectionData(DataRefImpl Sec) const override;
+  bool isSectionBSS(DataRefImpl Sec) const override;
+  bool isSectionVirtual(DataRefImpl Sec) const override;
+  bool isBerkeleyText(DataRefImpl Sec) const override;
+  bool isBerkeleyData(DataRefImpl Sec) const override;
+
+public:
+  MutableELFObject(ELFObjectFile<ELFT> &B)
+      : ELFObjectFile<ELFT>(std::move(B)),
+        Sections(B.section_begin(), B.section_end(),
+                 [&](SectionRef Ref) { return Ref.getRawDataRefImpl().p; }) {}
+
+  section_iterator section_begin() const override {
+    return section_iterator(SectionRef(toDataRef(0), this));
+  }
+
+  section_iterator section_end() const override {
+    return section_iterator(SectionRef(toDataRef(Sections.size()), this));
+  }
+
+  MutableELFSection<ELFT> *getMutableSection(section_iterator Sec) {
+    uintptr_t Index = Sec->getRawDataRefImpl().p;
+    return Sections.makeMutable(Index, this);
+  }
+};
+
+template <typename ELFT>
+void MutableELFObject<ELFT>::moveSectionNext(DataRefImpl &Sec) const {
+  ++Sec.p;
+}
+
+template <typename ELFT>
+Expected<StringRef>
+MutableELFObject<ELFT>::getSectionName(DataRefImpl Sec) const {
+  MappingType Mapping = Sections[Sec.p];
+  if (Mapping.New) {
+    const MutableELFSection<ELFT> *NewSec = Sections.getNew(Mapping.Ptr);
+    return NewSec->Name;
+  }
+  return ELFObjectFile<ELFT>::getSectionName(toDataRef(Mapping.Ptr));
+}
+
+template <typename ELFT>
+uint64_t MutableELFObject<ELFT>::getSectionAddress(DataRefImpl Sec) const {
+  return ELFObjectFile<ELFT>::getSectionAddress(getSectionRef(Sec));
+}
+
+template <typename ELFT>
+uint64_t MutableELFObject<ELFT>::getSectionIndex(DataRefImpl Sec) const {
+  return Sec.p;
+}
+
+template <typename ELFT>
+uint64_t MutableELFObject<ELFT>::getSectionSize(DataRefImpl Sec) const {
+  return ELFObjectFile<ELFT>::getSectionSize(getSectionRef(Sec));
+}
+
+template <typename ELFT>
+Expected<ArrayRef<uint8_t>>
+MutableELFObject<ELFT>::getSectionContents(DataRefImpl Sec) const {
+  MappingType Mapping = Sections[Sec.p];
+  if (Mapping.New) {
+    const MutableELFSection<ELFT> *NewSec = Sections.getNew(Mapping.Ptr);
+    return ArrayRef<uint8_t>(NewSec->Data.data(), NewSec->Header.sh_size);
+  }
+  return ELFObjectFile<ELFT>::getSectionContents(toDataRef(Mapping.Ptr));
+}
+
+template <typename ELFT>
+uint64_t MutableELFObject<ELFT>::getSectionAlignment(DataRefImpl Sec) const {
+  return ELFObjectFile<ELFT>::getSectionAlignment(getSectionRef(Sec));
+}
+
+template <typename ELFT>
+bool MutableELFObject<ELFT>::isSectionCompressed(DataRefImpl Sec) const {
+  return ELFObjectFile<ELFT>::isSectionCompressed(getSectionRef(Sec));
+}
+
+template <typename ELFT>
+bool MutableELFObject<ELFT>::isSectionText(DataRefImpl Sec) const {
+  return ELFObjectFile<ELFT>::isSectionText(getSectionRef(Sec));
+}
+
+template <typename ELFT>
+bool MutableELFObject<ELFT>::isSectionData(DataRefImpl Sec) const {
+  return ELFObjectFile<ELFT>::isSectionData(getSectionRef(Sec));
+}
+
+template <typename ELFT>
+bool MutableELFObject<ELFT>::isSectionBSS(DataRefImpl Sec) const {
+  return ELFObjectFile<ELFT>::isSectionBSS(getSectionRef(Sec));
+}
+
+template <typename ELFT>
+bool MutableELFObject<ELFT>::isSectionVirtual(DataRefImpl Sec) const {
+  return ELFObjectFile<ELFT>::isSectionVirtual(getSectionRef(Sec));
+}
+
+template <typename ELFT>
+bool MutableELFObject<ELFT>::isBerkeleyText(DataRefImpl Sec) const {
+  return ELFObjectFile<ELFT>::isBerkeleyText(getSectionRef(Sec));
+}
+
+template <typename ELFT>
+bool MutableELFObject<ELFT>::isBerkeleyData(DataRefImpl Sec) const {
+  return ELFObjectFile<ELFT>::isBerkeleyData(getSectionRef(Sec));
+}
+
+} // namespace object
+} // namespace llvm
+
+#endif // LLVM_OBJECT_MUTABLEELFOBJECT_H
Index: llvm/unittests/Object/CMakeLists.txt
===================================================================
--- llvm/unittests/Object/CMakeLists.txt
+++ llvm/unittests/Object/CMakeLists.txt
@@ -1,10 +1,12 @@
 set(LLVM_LINK_COMPONENTS
   BinaryFormat
   Object
+  ObjectYAML
   )
 
 add_llvm_unittest(ObjectTests
   MinidumpTest.cpp
+  MutableELFObjectTest.cpp
   SymbolSizeTest.cpp
   SymbolicFileTest.cpp
   )
Index: llvm/unittests/Object/MutableELFObjectTest.cpp
===================================================================
--- /dev/null
+++ llvm/unittests/Object/MutableELFObjectTest.cpp
@@ -0,0 +1,187 @@
+//===- MutableELFObjectTest.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/MutableELFObject.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/ObjectYAML/yaml2obj.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace object;
+using namespace yaml;
+
+// Change a sections name and test that SectionRef::getName() returns the new
+// name.
+TEST(MutableELFObject, ChangeSectionName) {
+  SmallString<0> Storage;
+  Expected<std::unique_ptr<ObjectFile>> ErrOrObj = yaml2ObjectFile(Storage, R"(
+--- !ELF
+FileHeader:
+  Class:     ELFCLASS64
+  Data:      ELFDATA2LSB
+  Type:      ET_REL
+  Machine:   EM_X86_64
+Sections:
+  - Name:    .sec0
+    Type:    SHT_PROGBITS
+  - Name:    .sec1
+    Type:    SHT_PROGBITS
+  - Name:    .sec2
+    Type:    SHT_PROGBITS)");
+
+  ASSERT_THAT_EXPECTED(ErrOrObj, Succeeded());
+  auto *ELFObjFile = dyn_cast<ELFObjectFile<ELF64LE>>(ErrOrObj->get());
+  ASSERT_TRUE(ELFObjFile);
+  MutableELFObject<ELF64LE> MutableObject(*ELFObjFile);
+
+  auto getSectionName = [](section_iterator Iter) {
+    StringRef Name;
+    Iter->getName(Name);
+    return Name.data();
+  };
+
+  ptrdiff_t NumSections =
+      std::distance(MutableObject.section_begin(), MutableObject.section_end());
+
+  auto Iter = MutableObject.section_begin();
+  EXPECT_STREQ(getSectionName(Iter), nullptr);
+  EXPECT_STREQ(getSectionName(++Iter), ".sec0");
+  EXPECT_STREQ(getSectionName(++Iter), ".sec1");
+  EXPECT_STREQ(getSectionName(++Iter), ".sec2");
+
+  Iter = MutableObject.section_begin();
+  std::advance(Iter, 2);
+  auto *MutSection = MutableObject.getMutableSection(Iter);
+  MutSection->Name = ".new_name";
+
+  Iter = MutableObject.section_begin();
+  EXPECT_STREQ(getSectionName(Iter), nullptr);
+  EXPECT_STREQ(getSectionName(++Iter), ".sec0");
+  EXPECT_STREQ(getSectionName(++Iter), ".new_name");
+  EXPECT_STREQ(getSectionName(++Iter), ".sec2");
+
+  // Make sure a section wasn't added.
+  ptrdiff_t NewNumSections =
+      std::distance(MutableObject.section_begin(), MutableObject.section_end());
+  EXPECT_EQ(NewNumSections, NumSections);
+}
+
+// Test MutableELFSection::setData().
+TEST(MutableELFObject, ChangeSectionContents) {
+  SmallString<0> Storage;
+  Expected<std::unique_ptr<ObjectFile>> ErrOrObj = yaml2ObjectFile(Storage, R"(
+--- !ELF
+FileHeader:
+  Class:     ELFCLASS64
+  Data:      ELFDATA2LSB
+  Type:      ET_REL
+  Machine:   EM_X86_64
+Sections:
+  - Name:    .text
+    Type:    SHT_PROGBITS
+    Flags:   [ SHF_ALLOC, SHF_EXECINSTR ]
+    Content: "DEADBEEF")");
+
+  ASSERT_THAT_EXPECTED(ErrOrObj, Succeeded());
+  auto *ELFObjFile = dyn_cast<ELFObjectFile<ELF64LE>>(ErrOrObj->get());
+  ASSERT_TRUE(ELFObjFile);
+  MutableELFObject<ELF64LE> MutableObject(*ELFObjFile);
+
+  ptrdiff_t NumSections =
+    std::distance(MutableObject.section_begin(), MutableObject.section_end());
+
+  auto FirstSec = ++MutableObject.section_begin();
+  Expected<StringRef> Contents = FirstSec->getContents();
+  ASSERT_THAT_EXPECTED(Contents, Succeeded());
+
+  EXPECT_EQ(*Contents, "\xDE\xAD\xBE\xEF");
+  EXPECT_EQ(FirstSec->getSize(), Contents->size());
+
+  ArrayRef<uint8_t> ZeroData{'0', '0', '0', '0'};
+
+  auto *MutSec = MutableObject.getMutableSection(FirstSec);
+  MutSec->setData(ZeroData);
+
+  FirstSec = ++MutableObject.section_begin();
+  Contents = FirstSec->getContents();
+  ASSERT_THAT_EXPECTED(Contents, Succeeded());
+  EXPECT_EQ(*Contents,
+            StringRef(reinterpret_cast<const char *>(ZeroData.data()),
+                      ZeroData.size()));
+
+  MutSec->Header.sh_size = 2;
+  Contents = FirstSec->getContents();
+  ASSERT_THAT_EXPECTED(Contents, Succeeded());
+  EXPECT_EQ(*Contents,
+            StringRef(reinterpret_cast<const char *>(ZeroData.data()), 2));
+
+  // Check that getSize properly uses the header's sh_size value.
+  EXPECT_EQ(FirstSec->getSize(), 2UL);
+
+  // Check that Contents has size 2 because header's sh_size was changed.
+  EXPECT_EQ(Contents->size(), 2UL);
+
+  // Make sure a section wasn't added.
+  ptrdiff_t NewNumSections =
+      std::distance(MutableObject.section_begin(), MutableObject.section_end());
+  EXPECT_EQ(NewNumSections, NumSections);
+}
+
+// Test that when no modifications have been made SectionRef's methods are
+// the same between ELFObjectFile and MutableELFObject.
+TEST(MutableELFObject, NoChange) {
+  SmallString<0> Storage;
+  Expected<std::unique_ptr<ObjectFile>> ErrOrObj = yaml2ObjectFile(Storage, R"(
+--- !ELF
+FileHeader:
+  Class:     ELFCLASS64
+  Data:      ELFDATA2LSB
+  Type:      ET_REL
+  Machine:   EM_X86_64
+Sections:
+  - Name:    .text
+    Type:    SHT_PROGBITS
+    Flags:   [ SHF_ALLOC, SHF_EXECINSTR ]
+    Content: "DEADBEEF")");
+
+  ASSERT_THAT_EXPECTED(ErrOrObj, Succeeded());
+  auto *ELFObjFile = dyn_cast<ELFObjectFile<ELF64LE>>(ErrOrObj->get());
+  ASSERT_TRUE(ELFObjFile);
+  MutableELFObject<ELF64LE> MutableObject(*ELFObjFile);
+  const ObjectFile &ObjFile = *ErrOrObj->get();
+
+  ptrdiff_t ObjFileSecs =
+    std::distance(ELFObjFile->section_begin(), ELFObjFile->section_end());
+  ptrdiff_t MutObjSecs =
+    std::distance(MutableObject.section_begin(), MutableObject.section_end());
+  EXPECT_EQ(ObjFileSecs, MutObjSecs);
+
+  auto TestSections = [](SectionRef ObjFile, SectionRef MutObj) {
+#define EXPECT_EQ_ITER(getMethod)                                              \
+  EXPECT_EQ(ObjFile.getMethod(), MutObj.getMethod())
+    EXPECT_EQ_ITER(getAddress);
+    EXPECT_EQ_ITER(getAlignment);
+    EXPECT_EQ_ITER(getIndex);
+    EXPECT_EQ_ITER(getSize);
+    EXPECT_EQ_ITER(isBerkeleyData);
+    EXPECT_EQ_ITER(isBerkeleyText);
+    EXPECT_EQ_ITER(isBitcode);
+    EXPECT_EQ_ITER(isBSS);
+    EXPECT_EQ_ITER(isCompressed);
+    EXPECT_EQ_ITER(isData);
+    EXPECT_EQ_ITER(isStripped);
+    EXPECT_EQ_ITER(isText);
+    EXPECT_EQ_ITER(isVirtual);
+  };
+
+  for (const auto &Tuple : zip(MutableObject.sections(), ObjFile.sections()))
+    TestSections(std::get<0>(Tuple), std::get<1>(Tuple));
+}