diff --git a/lld/MachO/Driver.h b/lld/MachO/Driver.h
--- a/lld/MachO/Driver.h
+++ b/lld/MachO/Driver.h
@@ -15,6 +15,10 @@
 #include "llvm/Option/OptTable.h"
 #include "llvm/Support/MemoryBuffer.h"
 
+namespace llvm::MachO {
+class InterfaceFile;
+}
+
 namespace lld {
 namespace macho {
 
@@ -43,9 +47,10 @@
 // Check for both libfoo.dylib and libfoo.tbd (in that order).
 llvm::Optional<std::string> resolveDylibPath(llvm::StringRef path);
 
-llvm::Optional<DylibFile *> loadDylib(llvm::MemoryBufferRef mbref,
-                                      DylibFile *umbrella = nullptr,
-                                      bool isBundleLoader = false);
+llvm::Optional<DylibFile *>
+loadDylib(llvm::MemoryBufferRef mbref,
+          const llvm::MachO::InterfaceFile *currentTopLevelTapi,
+          DylibFile *umbrella = nullptr, bool isBundleLoader = false);
 
 llvm::Optional<InputFile *> loadArchiveMember(MemoryBufferRef, uint32_t modTime,
                                               StringRef archiveName,
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -320,7 +320,7 @@
   case file_magic::macho_dynamically_linked_shared_lib:
   case file_magic::macho_dynamically_linked_shared_lib_stub:
   case file_magic::tapi_file:
-    if (Optional<DylibFile *> dylibFile = loadDylib(mbref))
+    if (Optional<DylibFile *> dylibFile = loadDylib(mbref, nullptr))
       newFile = *dylibFile;
     break;
   case file_magic::bitcode:
@@ -333,7 +333,7 @@
     if (!isBundleLoader)
       error(path + ": unhandled file type");
     if (Optional<DylibFile *> dylibFile =
-            loadDylib(mbref, nullptr, isBundleLoader))
+            loadDylib(mbref, nullptr, nullptr, isBundleLoader))
       newFile = *dylibFile;
     break;
   default:
diff --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp
--- a/lld/MachO/DriverUtils.cpp
+++ b/lld/MachO/DriverUtils.cpp
@@ -175,9 +175,10 @@
 // especially if it's a commonly re-exported core library.
 static DenseMap<CachedHashStringRef, DylibFile *> loadedDylibs;
 
-Optional<DylibFile *> macho::loadDylib(MemoryBufferRef mbref,
-                                       DylibFile *umbrella,
-                                       bool isBundleLoader) {
+Optional<DylibFile *>
+macho::loadDylib(MemoryBufferRef mbref,
+                 const llvm::MachO::InterfaceFile *currentTopLevelTapi,
+                 DylibFile *umbrella, bool isBundleLoader) {
   StringRef path = mbref.getBufferIdentifier();
   DylibFile *&file = loadedDylibs[CachedHashStringRef(path)];
   if (file)
@@ -191,13 +192,15 @@
             ": " + toString(result.takeError()));
       return {};
     }
-    file = make<DylibFile>(**result, umbrella, isBundleLoader);
+    file = make<DylibFile>(**result, currentTopLevelTapi, umbrella,
+                           isBundleLoader);
   } else {
     assert(magic == file_magic::macho_dynamically_linked_shared_lib ||
            magic == file_magic::macho_dynamically_linked_shared_lib_stub ||
            magic == file_magic::macho_executable ||
            magic == file_magic::macho_bundle);
-    file = make<DylibFile>(mbref, umbrella, isBundleLoader);
+    file =
+        make<DylibFile>(mbref, currentTopLevelTapi, umbrella, isBundleLoader);
   }
   return file;
 }
diff --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h
--- a/lld/MachO/InputFiles.h
+++ b/lld/MachO/InputFiles.h
@@ -125,10 +125,13 @@
   // the root dylib to ensure symbols in the child library are correctly bound
   // to the root. On the other hand, if a dylib is being directly loaded
   // (through an -lfoo flag), then `umbrella` should be a nullptr.
-  explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella = nullptr,
+  explicit DylibFile(MemoryBufferRef mb,
+                     const llvm::MachO::InterfaceFile *currentTopLevelTapi,
+                     DylibFile *umbrella = nullptr,
                      bool isBundleLoader = false);
 
   explicit DylibFile(const llvm::MachO::InterfaceFile &interface,
+                     const llvm::MachO::InterfaceFile *currentTopLevelTapi,
                      DylibFile *umbrella = nullptr,
                      bool isBundleLoader = false);
 
diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -530,36 +530,33 @@
 }
 
 // The path can point to either a dylib or a .tbd file.
-static Optional<DylibFile *> loadDylib(StringRef path, DylibFile *umbrella) {
+static Optional<DylibFile *>
+loadDylib(StringRef path, DylibFile *umbrella,
+          const InterfaceFile *currentTopLevelTapi) {
   Optional<MemoryBufferRef> mbref = readFile(path);
   if (!mbref) {
     error("could not read dylib file at " + path);
     return {};
   }
-  return loadDylib(*mbref, umbrella);
+  return loadDylib(*mbref, currentTopLevelTapi, umbrella);
 }
 
 // TBD files are parsed into a series of TAPI documents (InterfaceFiles), with
 // the first document storing child pointers to the rest of them. When we are
 // processing a given TBD file, we store that top-level document here. When
 // processing re-exports, we search its children for potentially matching
-// documents in the same TBD file. Note that the children themselves don't
-// point to further documents, i.e. this is a two-level tree.
-//
-// ld64 allows a TAPI re-export to reference documents nested within other TBD
-// files, but that seems like a strange design, so this is an intentional
-// deviation.
-const InterfaceFile *currentTopLevelTapi = nullptr;
+// documents in the same TBD file.
 
 // Re-exports can either refer to on-disk files, or to documents within .tbd
 // files.
-static Optional<DylibFile *> loadReexportHelper(StringRef path,
-                                                DylibFile *umbrella) {
+static Optional<DylibFile *>
+loadReexportHelper(StringRef path, DylibFile *umbrella,
+                   const InterfaceFile *currentTopLevelTapi) {
   if (path::is_absolute(path, path::Style::posix))
     for (StringRef root : config->systemLibraryRoots)
       if (Optional<std::string> dylibPath =
               resolveDylibPath((root + path).str()))
-        return loadDylib(*dylibPath, umbrella);
+        return loadDylib(*dylibPath, umbrella, currentTopLevelTapi);
 
   // TODO: Expand @loader_path, @executable_path etc
 
@@ -567,13 +564,13 @@
     for (InterfaceFile &child :
          make_pointee_range(currentTopLevelTapi->documents())) {
       if (path == child.getInstallName())
-        return make<DylibFile>(child, umbrella);
+        return make<DylibFile>(child, currentTopLevelTapi, umbrella);
       assert(child.documents().empty());
     }
   }
 
   if (Optional<std::string> dylibPath = resolveDylibPath(path))
-    return loadDylib(*dylibPath, umbrella);
+    return loadDylib(*dylibPath, umbrella, currentTopLevelTapi);
 
   error("unable to locate re-export with install name " + path);
   return {};
@@ -599,14 +596,17 @@
   return false;
 }
 
-void loadReexport(StringRef path, DylibFile *umbrella) {
-  Optional<DylibFile *> reexport = loadReexportHelper(path, umbrella);
+void loadReexport(StringRef path, DylibFile *umbrella,
+                  const InterfaceFile *currentTopLevelTapi) {
+  Optional<DylibFile *> reexport =
+      loadReexportHelper(path, umbrella, currentTopLevelTapi);
   if (reexport && isImplicitlyLinked(path))
     inputFiles.insert(*reexport);
 }
 
-DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
-                     bool isBundleLoader)
+DylibFile::DylibFile(MemoryBufferRef mb,
+                     const InterfaceFile *currentTopLevelTapi,
+                     DylibFile *umbrella, bool isBundleLoader)
     : InputFile(DylibKind, mb), refState(RefState::Unreferenced),
       isBundleLoader(isBundleLoader) {
   assert(!isBundleLoader || !umbrella);
@@ -659,12 +659,13 @@
     auto *c = reinterpret_cast<const dylib_command *>(cmd);
     StringRef reexportPath =
         reinterpret_cast<const char *>(c) + read32le(&c->dylib.name);
-    loadReexport(reexportPath, umbrella);
+    loadReexport(reexportPath, umbrella, currentTopLevelTapi);
   }
 }
 
-DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella,
-                     bool isBundleLoader)
+DylibFile::DylibFile(const InterfaceFile &interface,
+                     const InterfaceFile *currentTopLevelTapi,
+                     DylibFile *umbrella, bool isBundleLoader)
     : InputFile(DylibKind, interface), refState(RefState::Unreferenced),
       isBundleLoader(isBundleLoader) {
   // FIXME: Add test for the missing TBD code path.
@@ -706,17 +707,16 @@
     }
   }
 
-  bool isTopLevelTapi = false;
-  if (currentTopLevelTapi == nullptr) {
-    currentTopLevelTapi = &interface;
-    isTopLevelTapi = true;
-  }
+  const InterfaceFile *top_level = nullptr;
+  // If there is no top-level (mean this tbd the top-level) or if the current
+  // interface has no parent
+  if (currentTopLevelTapi == nullptr || interface.getParent() == nullptr)
+    top_level = &interface;
+  else
+    top_level = interface.getParent(); // Second+-level exporters.
 
   for (InterfaceFileRef intfRef : interface.reexportedLibraries())
-    loadReexport(intfRef.getInstallName(), umbrella);
-
-  if (isTopLevelTapi)
-    currentTopLevelTapi = nullptr;
+    loadReexport(intfRef.getInstallName(), umbrella, top_level);
 }
 
 ArchiveFile::ArchiveFile(std::unique_ptr<object::Archive> &&f)
diff --git a/lld/test/MachO/Inputs/iPhoneSimulator.sdk/usr/lib/libSystem.tbd b/lld/test/MachO/Inputs/iPhoneSimulator.sdk/usr/lib/libSystem.tbd
--- a/lld/test/MachO/Inputs/iPhoneSimulator.sdk/usr/lib/libSystem.tbd
+++ b/lld/test/MachO/Inputs/iPhoneSimulator.sdk/usr/lib/libSystem.tbd
@@ -4,10 +4,13 @@
 platform:         ios
 install-name:     '/usr/lib/libSystem.B.dylib'
 current-version:  1281
+reexported-libraries:
+  - archs:      [i386, x86_64]
+    libraries:  ['/usr/lib/system/libsystem_sim_pthread.dylib']
 exports:
   - archs:      [ i386, x86_64 ]
     re-exports: [ '/usr/lib/system/libcache.dylib' ]
-    symbols:    [ __crashreporter_info__ ]
+    symbols:    [ __crashreporter_info__, _from_second_level_dylib]
 --- !tapi-tbd-v3
 archs:            [ i386, x86_64 ]
 uuids:            [ 'i386: 00000000-0000-0000-0000-000000000002', 'x86_64: 00000000-0000-0000-0000-000000000003' ]
@@ -31,4 +34,32 @@
 exports:
   - archs:      [ i386, x86_64 ]
     symbols:    [ _from_non_reexported_tapi_dylib ]
+
+--- !tapi-tbd-v3
+archs:            [ i386, x86_64 ]
+uuids:            [ 'i386: 00000000-0000-0000-0000-000000000006', 'x86_64: 00000000-0000-0000-0000-000000000006' ]
+platform:         ios
+install-name:     '/usr/lib/system/libsystem_sim_pthread.dylib'
+parent-umbrella:
+  - archs:     [ i386, x86_64 ]
+    umbrella:  System
+reexported-libraries:
+  - archs:      [i386, x86_64]
+    libraries:  ['/usr/lib/system/libsystem_sim_pthread_host.dylib']
+exports:
+  - archs:      [ i386, x86_64 ]
+    symbols:    [ _from_second_level_dylib ]
+    
+--- !tapi-tbd-v3    
+archs:            [ i386, x86_64 ]
+uuids:            [ 'i386: 00000000-0000-0000-0000-000000000006', 'x86_64: 00000000-0000-0000-0000-000000000006' ]
+platform:         ios
+install-name:     '/usr/lib/system/libsystem_sim_pthread_host.dylib'
+parent-umbrella:
+  - archs:     [ i386, x86_64 ]
+    umbrella:  System
+exports:
+  - archs:      [ i386, x86_64 ]
+    symbols:    [ _from_second_level_dylib ]
+
 ...
diff --git a/lld/test/MachO/reexport-nested-lib.s b/lld/test/MachO/reexport-nested-lib.s
new file mode 100644
--- /dev/null
+++ b/lld/test/MachO/reexport-nested-lib.s
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: mkdir -p %t
+
+# RUN: llvm-mc -filetype obj -triple x86_64-apple-darwin %s -o %t/test.o
+# RUN: %lld -o %t/test  -syslibroot %S/Inputs/iPhoneSimulator.sdk -lSystem %t/test.o
+
+.text
+.globl _main
+
+_main:
+  ret
+
+.data
+  .quad _from_second_level_dylib
diff --git a/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h b/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h
--- a/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h
+++ b/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h
@@ -338,6 +338,9 @@
   ///\param Document The library to inline with top level library.
   void addDocument(std::shared_ptr<InterfaceFile> &&Document);
 
+  /// Returns the pointer to parent document if exists or nullptr otherwise.
+  InterfaceFile *getParent() const { return parent; }
+
   /// Get the list of inlined libraries.
   ///
   /// \return Returns a list of the inlined frameworks.
@@ -404,6 +407,8 @@
   bool operator!=(const InterfaceFile &O) const { return !(*this == O); }
 
 private:
+  InterfaceFile *parent = nullptr;
+
   llvm::BumpPtrAllocator Allocator;
   StringRef copyString(StringRef String) {
     if (String.empty())
diff --git a/llvm/lib/TextAPI/MachO/InterfaceFile.cpp b/llvm/lib/TextAPI/MachO/InterfaceFile.cpp
--- a/llvm/lib/TextAPI/MachO/InterfaceFile.cpp
+++ b/llvm/lib/TextAPI/MachO/InterfaceFile.cpp
@@ -124,6 +124,7 @@
                                   const std::shared_ptr<InterfaceFile> &RHS) {
                                  return LHS->InstallName < RHS->InstallName;
                                });
+  Document->parent = this;
   Documents.insert(Pos, Document);
 }