diff --git a/llvm/include/llvm/Bitcode/EmbedBitcodePass.h b/llvm/include/llvm/Bitcode/EmbedBitcodePass.h
new file mode 100644
--- /dev/null
+++ b/llvm/include/llvm/Bitcode/EmbedBitcodePass.h
@@ -0,0 +1,42 @@
+//===-- EmbedBitcodePass.h - Embeds bitcode into global ---------*- 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
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file provides apass which embeds the bitcode into a global variable.
+///
+//===----------------------------------------------------------------------===//
+//
+#ifndef LLVM_BITCODE_EMBEDBITCODEPASS_H
+#define LLVM_BITCODE_EMBEDBITCODEPASS_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+class Module;
+class ModulePass;
+class Pass;
+
+/// Pass embeds the current module into a global variable.
+class EmbedBitcodePass : public PassInfoMixin<EmbedBitcodePass> {
+  bool IsThinLTO;
+  bool EmitLLVMUSeLists;
+  bool EmitLTOSummary;
+
+public:
+  EmbedBitcodePass(bool IsThinLTO, bool EmitLLVMUSeLists, bool EmitLTOSummary)
+      : IsThinLTO(IsThinLTO), EmitLLVMUSeLists(EmitLLVMUSeLists),
+        EmitLTOSummary(EmitLTOSummary){};
+
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &);
+
+  static bool isRequired() { return true; }
+};
+
+} // end namespace llvm.
+
+#endif
diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h
--- a/llvm/include/llvm/Passes/PassBuilder.h
+++ b/llvm/include/llvm/Passes/PassBuilder.h
@@ -239,6 +239,21 @@
   ModulePassManager buildPerModuleDefaultPipeline(OptimizationLevel Level,
                                                   bool LTOPreLink = false);
 
+  /// Build a fat object default optimization pipeline.
+  ///
+  /// This builds a pipeline that runs the LTO/ThinLTO pipeline, and emits a
+  /// section containing the bitcode along size the object code generated by the
+  /// PerModuleDefaultPipeline.
+  ///
+  /// Note that \p Level cannot be `O0` here. The pipelines produced are
+  /// only intended for use when attempting to optimize code. If frontends
+  /// require some transformations for semantic reasons, they should explicitly
+  /// build them.
+  ModulePassManager buildFatLTODefaultPipeline(OptimizationLevel Level,
+                                               bool ThinLTOPreLink,
+                                               bool EmitUseList,
+                                               bool EmitSummary);
+
   /// Build a pre-link, ThinLTO-targeting default optimization pipeline to
   /// a pass manager.
   ///
@@ -576,6 +591,10 @@
   void addVectorPasses(OptimizationLevel Level, FunctionPassManager &FPM,
                        bool IsFullLTO);
 
+  void addPerModuleDefaultPipelinePasses(ModulePassManager &MPM,
+                                         OptimizationLevel Level,
+                                         bool LTOPreLink = false);
+
   static std::optional<std::vector<PipelineElement>>
   parsePipelineText(StringRef Text);
 
diff --git a/llvm/lib/Bitcode/Writer/CMakeLists.txt b/llvm/lib/Bitcode/Writer/CMakeLists.txt
--- a/llvm/lib/Bitcode/Writer/CMakeLists.txt
+++ b/llvm/lib/Bitcode/Writer/CMakeLists.txt
@@ -2,6 +2,7 @@
   BitWriter.cpp
   BitcodeWriter.cpp
   BitcodeWriterPass.cpp
+  EmbedBitcodePass.cpp
   ValueEnumerator.cpp
 
   DEPENDS
diff --git a/llvm/lib/Bitcode/Writer/EmbedBitcodePass.cpp b/llvm/lib/Bitcode/Writer/EmbedBitcodePass.cpp
new file mode 100644
--- /dev/null
+++ b/llvm/lib/Bitcode/Writer/EmbedBitcodePass.cpp
@@ -0,0 +1,59 @@
+//===- EmbedBitcodePass.cpp - Pass that embeds the bitcode into a global---===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// EmbedBitcodePass implementation.
+//
+//===----------------------------------------------------------------------===//
+//
+#include "llvm/Bitcode/EmbedBitcodePass.h"
+
+#include "llvm/Bitcode/BitcodeWriter.h"
+#include "llvm/Bitcode/BitcodeWriterPass.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/TargetParser/Triple.h"
+#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
+
+using namespace llvm;
+
+PreservedAnalyses EmbedBitcodePass::run(Module &M, ModuleAnalysisManager &AM) {
+  if (M.getGlobalVariable("llvm.embedded.module", true))
+    report_fatal_error("Can only embed the module once.");
+
+  Triple T(M.getTargetTriple());
+  if (T.getObjectFormat() != Triple::ELF)
+    report_fatal_error(
+        "Embed bitcode pass currently only supports ELF object format.");
+
+  std::string Data;
+  raw_string_ostream OS(Data);
+
+  if (IsThinLTO)
+    ThinLTOBitcodeWriterPass(OS, nullptr).run(M, AM);
+  else
+    BitcodeWriterPass(OS, EmitLLVMUSeLists, EmitLTOSummary).run(M, AM);
+
+  ArrayRef<uint8_t> ModuleData((const uint8_t *)OS.str().data(),
+                               OS.str().size());
+  Constant *ModuleConstant = ConstantDataArray::get(M.getContext(), ModuleData);
+
+  llvm::GlobalVariable *EM = new llvm::GlobalVariable(
+      M, ModuleConstant->getType(), true, llvm::GlobalValue::PrivateLinkage,
+      ModuleConstant);
+
+  EM->setSection(".llvm.lto");
+  EM->setAlignment(Align(1));
+  EM->setName("llvm.embedded.module");
+  appendToCompilerUsed(M, {EM});
+
+  return PreservedAnalyses::all();
+}
diff --git a/llvm/lib/Object/ObjectFile.cpp b/llvm/lib/Object/ObjectFile.cpp
--- a/llvm/lib/Object/ObjectFile.cpp
+++ b/llvm/lib/Object/ObjectFile.cpp
@@ -79,7 +79,7 @@
 bool ObjectFile::isSectionBitcode(DataRefImpl Sec) const {
   Expected<StringRef> NameOrErr = getSectionName(Sec);
   if (NameOrErr)
-    return *NameOrErr == ".llvmbc";
+    return *NameOrErr == ".llvmbc" || *NameOrErr == ".llvm.lto";
   consumeError(NameOrErr.takeError());
   return false;
 }
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -73,6 +73,7 @@
 #include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/Analysis/TypeBasedAliasAnalysis.h"
 #include "llvm/Analysis/UniformityAnalysis.h"
+#include "llvm/Bitcode/EmbedBitcodePass.h"
 #include "llvm/CodeGen/HardwareLoops.h"
 #include "llvm/CodeGen/TypePromotion.h"
 #include "llvm/IR/DebugInfo.h"
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -24,6 +24,7 @@
 #include "llvm/Analysis/ProfileSummaryInfo.h"
 #include "llvm/Analysis/ScopedNoAliasAA.h"
 #include "llvm/Analysis/TypeBasedAliasAnalysis.h"
+#include "llvm/Bitcode/EmbedBitcodePass.h"
 #include "llvm/IR/PassManager.h"
 #include "llvm/Passes/OptimizationLevel.h"
 #include "llvm/Passes/PassBuilder.h"
@@ -1403,15 +1404,22 @@
 ModulePassManager
 PassBuilder::buildPerModuleDefaultPipeline(OptimizationLevel Level,
                                            bool LTOPreLink) {
-  if (Level == OptimizationLevel::O0)
-    return buildO0DefaultPipeline(Level, LTOPreLink);
-
   ModulePassManager MPM;
+  addPerModuleDefaultPipelinePasses(MPM, Level, LTOPreLink);
+  return MPM;
+}
+
+void PassBuilder::addPerModuleDefaultPipelinePasses(ModulePassManager &MPM,
+                                                    OptimizationLevel Level,
+                                                    bool LTOPreLink) {
+  assert(Level != OptimizationLevel::O0 &&
+         "Must request optimizations for the default pipeline!");
 
   // Convert @llvm.global.annotations to !annotation metadata.
   MPM.addPass(Annotation2MetadataPass());
 
-  // Force any function attributes we want the rest of the pipeline to observe.
+  // Force any function attributes we want the rest of the pipeline to
+  // observe.
   MPM.addPass(ForceFunctionAttrsPass());
 
   // Apply module pipeline start EP callback.
@@ -1439,7 +1447,19 @@
 
   if (LTOPreLink)
     addRequiredLTOPreLinkPasses(MPM);
+}
 
+ModulePassManager
+PassBuilder::buildFatLTODefaultPipeline(OptimizationLevel Level,
+                                        bool ThinLTOPreLink, bool EmitUseList,
+                                        bool EmitSummary) {
+  assert(Level != OptimizationLevel::O0 &&
+         "Must request optimizations for the default pipeline!");
+  ModulePassManager MPM = ThinLTOPreLink
+                              ? buildThinLTOPreLinkDefaultPipeline(Level)
+                              : buildLTOPreLinkDefaultPipeline(Level);
+  MPM.addPass(EmbedBitcodePass(ThinLTOPreLink, EmitUseList, EmitSummary));
+  addPerModuleDefaultPipelinePasses(MPM, Level, /*LTOPreLink=*/false);
   return MPM;
 }
 
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -58,6 +58,7 @@
 MODULE_PASS("dot-callgraph", CallGraphDOTPrinterPass())
 MODULE_PASS("elim-avail-extern", EliminateAvailableExternallyPass())
 MODULE_PASS("extract-blocks", BlockExtractorPass({}, false))
+MODULE_PASS("embed-bitcode", EmbedBitcodePass(true, true, true))
 MODULE_PASS("forceattrs", ForceFunctionAttrsPass())
 MODULE_PASS("function-import", FunctionImportPass())
 MODULE_PASS("globaldce", GlobalDCEPass())
diff --git a/llvm/test/Bitcode/embed-multiple.ll b/llvm/test/Bitcode/embed-multiple.ll
new file mode 100644
--- /dev/null
+++ b/llvm/test/Bitcode/embed-multiple.ll
@@ -0,0 +1,6 @@
+; RUN: not --crash opt --mtriple x86_64-unknown-linux-gnu < %s -passes=embed-bitcode -S 2>&1 | FileCheck %s
+
+@a = global i32 1
+@llvm.embedded.module = private constant [4 x i8] c"BC\C0\DE"
+
+; CHECK: LLVM ERROR: Can only embed the module once.
diff --git a/llvm/test/Bitcode/embed-unsupported-object-format.ll b/llvm/test/Bitcode/embed-unsupported-object-format.ll
new file mode 100644
--- /dev/null
+++ b/llvm/test/Bitcode/embed-unsupported-object-format.ll
@@ -0,0 +1,5 @@
+; RUN: not --crash opt --mtriple powerpc64-unknown-aix < %s -passes=embed-bitcode -S 2>&1 | FileCheck %s
+
+@a = global i32 1
+
+; CHECK: LLVM ERROR: Embed bitcode pass currently only supports ELF object format
diff --git a/llvm/test/Bitcode/embed.ll b/llvm/test/Bitcode/embed.ll
new file mode 100644
--- /dev/null
+++ b/llvm/test/Bitcode/embed.ll
@@ -0,0 +1,7 @@
+; RUN: opt --mtriple x86_64-unknown-linux-gnu < %s -passes=embed-bitcode -S | FileCheck %s
+
+@a = global i32 1
+
+; CHECK: @a = global i32 1
+; CHECK: @llvm.embedded.module = private constant {{.*}}, section ".llvm.lto", align 1
+; CHECK: @llvm.compiler.used = appending global [1 x ptr] [ptr @llvm.embedded.module], section "llvm.metadata"