Browse Source

gcc 8 fixes and latest elfhack

Frank-Rainer Grahl 1 month ago
parent
commit
d3928170a7
37 changed files with 3946 additions and 0 deletions
  1. 76 0
      mozilla-release/patches/1424867-1-59a1.patch
  2. 32 0
      mozilla-release/patches/1424867-2-59a1.patch
  3. 51 0
      mozilla-release/patches/1424867-3-59a1.patch
  4. 39 0
      mozilla-release/patches/1430729-59a1.patch
  5. 39 0
      mozilla-release/patches/1431109-59a1.patch
  6. 32 0
      mozilla-release/patches/1435223-59a1.patch
  7. 211 0
      mozilla-release/patches/1438196-60a1.patch
  8. 31 0
      mozilla-release/patches/1461614-62a1.patch
  9. 74 0
      mozilla-release/patches/1464890-63a1.patch
  10. 31 0
      mozilla-release/patches/1477540-63a1.patch
  11. 35 0
      mozilla-release/patches/1519636-xx-elfhack-112a1.patch
  12. 204 0
      mozilla-release/patches/1519636-xx-elfhack-130a1.patch
  13. 98 0
      mozilla-release/patches/1838328-116a1.patch
  14. 88 0
      mozilla-release/patches/1839740-2-119a1.patch
  15. 833 0
      mozilla-release/patches/1839740-3-119a1.patch
  16. 78 0
      mozilla-release/patches/1839741-119a1.patch
  17. 128 0
      mozilla-release/patches/1839746-116a1.patch
  18. 164 0
      mozilla-release/patches/1840931-116a1.patch
  19. 34 0
      mozilla-release/patches/1841212-116a1.patch
  20. 147 0
      mozilla-release/patches/1850867-1-119a1.patch
  21. 30 0
      mozilla-release/patches/1850867-2-119a1.patch
  22. 71 0
      mozilla-release/patches/1854052-119a1.patch
  23. 60 0
      mozilla-release/patches/1854303-119a1.patch
  24. 35 0
      mozilla-release/patches/1854497-119a1.patch
  25. 100 0
      mozilla-release/patches/1855568-1-120a1.patch
  26. 214 0
      mozilla-release/patches/1855568-2-120a1.patch
  27. 181 0
      mozilla-release/patches/1855568-3-120a1.patch
  28. 31 0
      mozilla-release/patches/1855955-PARTIAL-elfhack-120a1.patch
  29. 205 0
      mozilla-release/patches/1856752-120a1.patch
  30. 37 0
      mozilla-release/patches/1863441-121a1.patch
  31. 42 0
      mozilla-release/patches/1863485-121a1.patch
  32. 50 0
      mozilla-release/patches/1864318-122a1.patch
  33. 194 0
      mozilla-release/patches/1892493-127a1.patch
  34. 144 0
      mozilla-release/patches/1898109-128a1.patch
  35. 60 0
      mozilla-release/patches/1903021-129a1.patch
  36. 31 0
      mozilla-release/patches/1903254-129a1.patch
  37. 36 0
      mozilla-release/patches/series

+ 76 - 0
mozilla-release/patches/1424867-1-59a1.patch

@@ -0,0 +1,76 @@
+# HG changeset patch
+# User Sylvestre Ledru <sledru@mozilla.com>
+# Date 1513087859 21600
+# Node ID bf2e50c356342ddf6503c6c21f34841eb7712d91
+# Parent  5d40cb0aed475aee1777c8162528f4f8f0effdc4
+Bug 1424867 - Fix some ignored-qualifiers warnings in url-classifier & reputationservice r=francois
+
+MozReview-Commit-ID: 9lLifMbNlnO
+
+diff --git a/toolkit/components/reputationservice/ApplicationReputation.cpp b/toolkit/components/reputationservice/ApplicationReputation.cpp
+--- a/toolkit/components/reputationservice/ApplicationReputation.cpp
++++ b/toolkit/components/reputationservice/ApplicationReputation.cpp
+@@ -1010,17 +1010,17 @@ PendingLookup::GetSpecHash(nsACString& a
+   rv = cryptoHash->Finish(false, binaryHash);
+   NS_ENSURE_SUCCESS(rv, rv);
+ 
+   // This needs to match HexEncode() in Chrome's
+   // src/base/strings/string_number_conversions.cc
+   static const char* const hex = "0123456789ABCDEF";
+   hexEncodedHash.SetCapacity(2 * binaryHash.Length());
+   for (size_t i = 0; i < binaryHash.Length(); ++i) {
+-    auto c = static_cast<const unsigned char>(binaryHash[i]);
++    auto c = static_cast<unsigned char>(binaryHash[i]);
+     hexEncodedHash.Append(hex[(c >> 4) & 0x0F]);
+     hexEncodedHash.Append(hex[c & 0x0F]);
+   }
+ 
+   return NS_OK;
+ }
+ 
+ nsresult
+diff --git a/toolkit/components/url-classifier/Entries.h b/toolkit/components/url-classifier/Entries.h
+--- a/toolkit/components/url-classifier/Entries.h
++++ b/toolkit/components/url-classifier/Entries.h
+@@ -99,17 +99,17 @@ struct SafebrowsingHash
+ 
+   void ToHexString(nsACString& aStr) const {
+     static const char* const lut = "0123456789ABCDEF";
+     // 32 bytes is the longest hash
+     size_t len = 32;
+ 
+     aStr.SetCapacity(2 * len);
+     for (size_t i = 0; i < len; ++i) {
+-      const char c = static_cast<const char>(buf[i]);
++      const char c = static_cast<char>(buf[i]);
+       aStr.Append(lut[(c >> 4) & 0x0F]);
+       aStr.Append(lut[c & 15]);
+     }
+   }
+ 
+   uint32_t ToUint32() const {
+     uint32_t n;
+     memcpy(&n, buf, sizeof(n));
+diff --git a/toolkit/components/url-classifier/LookupCache.cpp b/toolkit/components/url-classifier/LookupCache.cpp
+--- a/toolkit/components/url-classifier/LookupCache.cpp
++++ b/toolkit/components/url-classifier/LookupCache.cpp
+@@ -54,17 +54,17 @@ void CStringToHexString(const nsACString
+ {
+   static const char* const lut = "0123456789ABCDEF";
+ 
+   size_t len = aIn.Length();
+   MOZ_ASSERT(len <= COMPLETE_SIZE);
+ 
+   aOut.SetCapacity(2 * len);
+   for (size_t i = 0; i < aIn.Length(); ++i) {
+-    const char c = static_cast<const char>(aIn[i]);
++    const char c = static_cast<char>(aIn[i]);
+     aOut.Append(lut[(c >> 4) & 0x0F]);
+     aOut.Append(lut[c & 15]);
+   }
+ }
+ 
+ LookupCache::LookupCache(const nsACString& aTableName,
+                          const nsACString& aProvider,
+                          nsIFile* aRootStoreDir)
+

+ 32 - 0
mozilla-release/patches/1424867-2-59a1.patch

@@ -0,0 +1,32 @@
+# HG changeset patch
+# User Sylvestre Ledru <sledru@mozilla.com>
+# Date 1513087899 21600
+# Node ID cc84eaae17daa2f7bd36accbe6cd7988f78fbcc5
+# Parent  bf2e50c356342ddf6503c6c21f34841eb7712d91
+Bug 1424867 - Fix an ignored-qualifiers warning in nsFind.cpp r=smaug
+
+MozReview-Commit-ID: JcNxEejtkWx
+
+diff --git a/toolkit/components/find/nsFind.cpp b/toolkit/components/find/nsFind.cpp
+--- a/toolkit/components/find/nsFind.cpp
++++ b/toolkit/components/find/nsFind.cpp
+@@ -27,17 +27,17 @@
+ #include "nsRange.h"
+ #include "nsContentUtils.h"
+ #include "mozilla/DebugOnly.h"
+ #include "mozilla/TextEditor.h"
+ 
+ using namespace mozilla;
+ 
+ // Yikes!  Casting a char to unichar can fill with ones!
+-#define CHAR_TO_UNICHAR(c) ((char16_t)(const unsigned char)c)
++#define CHAR_TO_UNICHAR(c) ((char16_t)(unsigned char)c)
+ 
+ static NS_DEFINE_CID(kCContentIteratorCID, NS_CONTENTITERATOR_CID);
+ static NS_DEFINE_CID(kCPreContentIteratorCID, NS_PRECONTENTITERATOR_CID);
+ 
+ #define CH_QUOTE ((char16_t)0x22)
+ #define CH_APOSTROPHE ((char16_t)0x27)
+ #define CH_LEFT_SINGLE_QUOTE ((char16_t)0x2018)
+ #define CH_RIGHT_SINGLE_QUOTE ((char16_t)0x2019)
+

+ 51 - 0
mozilla-release/patches/1424867-3-59a1.patch

@@ -0,0 +1,51 @@
+# HG changeset patch
+# User Sylvestre Ledru <sledru@mozilla.com>
+# Date 1513088035 21600
+# Node ID 3d31313a92eb307d84f2246abd189631fd49fa82
+# Parent  cc84eaae17daa2f7bd36accbe6cd7988f78fbcc5
+Bug 1424867 - Fix an ignored-qualifiers warning in BindingUtils r=smaug
+
+MozReview-Commit-ID: 2bMNgMZwucN
+
+diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp
+--- a/dom/bindings/BindingUtils.cpp
++++ b/dom/bindings/BindingUtils.cpp
+@@ -141,17 +141,17 @@ ThrowInvalidThis(JSContext* aCx, const J
+   if (!funcNameStr.init(aCx, funcName)) {
+     return false;
+   }
+   const ErrNum errorNumber = aSecurityError ?
+                              MSG_METHOD_THIS_UNWRAPPING_DENIED :
+                              MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE;
+   MOZ_RELEASE_ASSERT(GetErrorArgCount(errorNumber) <= 2);
+   JS_ReportErrorNumberUC(aCx, GetErrorMessage, nullptr,
+-                         static_cast<const unsigned>(errorNumber),
++                         static_cast<unsigned>(errorNumber),
+                          funcNameStr.get(), ifaceName.get());
+   return false;
+ }
+ 
+ bool
+ ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
+                  bool aSecurityError,
+                  prototypes::ID aProtoId)
+@@ -248,17 +248,17 @@ TErrorResult<CleanupPolicy>::SetPendingE
+   const uint32_t argCount = message->mArgs.Length();
+   const char16_t* args[JS::MaxNumErrorArguments + 1];
+   for (uint32_t i = 0; i < argCount; ++i) {
+     args[i] = message->mArgs.ElementAt(i).get();
+   }
+   args[argCount] = nullptr;
+ 
+   JS_ReportErrorNumberUCArray(aCx, dom::GetErrorMessage, nullptr,
+-                              static_cast<const unsigned>(message->mErrorNumber),
++                              static_cast<unsigned>(message->mErrorNumber),
+                               argCount > 0 ? args : nullptr);
+ 
+   ClearMessage();
+   mResult = NS_OK;
+ }
+ 
+ template<typename CleanupPolicy>
+ void
+

+ 39 - 0
mozilla-release/patches/1430729-59a1.patch

@@ -0,0 +1,39 @@
+# HG changeset patch
+# User Sylvestre Ledru <sledru@mozilla.com>
+# Date 1516115973 -3600
+# Node ID 263b74db7a7cd9d6e35a82e0ec3b75d907f8cacc
+# Parent  3a2a6750304e360bf80df95c149b5ed52414bae1
+Bug 1430729 - Ignore an incorrect warning with gcc (-Wuninitialized) r=froydnj
+
+MozReview-Commit-ID: 2VfQ8E5d0gZ
+
+diff --git a/xpcom/base/StaticPtr.h b/xpcom/base/StaticPtr.h
+--- a/xpcom/base/StaticPtr.h
++++ b/xpcom/base/StaticPtr.h
+@@ -99,17 +99,25 @@ class MOZ_ONLY_USED_TO_AVOID_STATIC_CONS
+ {
+ public:
+   // In debug builds, check that mRawPtr is initialized for us as we expect
+   // by the compiler.  In non-debug builds, don't declare a constructor
+   // so that the compiler can see that the constructor is trivial.
+ #ifdef DEBUG
+   StaticRefPtr()
+   {
++#ifdef __GNUC__
++#pragma GCC diagnostic push
++#pragma GCC diagnostic ignored "-Wuninitialized"
++  // False positive with gcc. See bug 1430729
++#endif
+     MOZ_ASSERT(!mRawPtr);
++#ifdef __GNUC__
++#pragma GCC diagnostic pop
++#endif
+   }
+ #endif
+ 
+   StaticRefPtr<T>& operator=(T* aRhs)
+   {
+     AssignWithAddref(aRhs);
+     return *this;
+   }
+

+ 39 - 0
mozilla-release/patches/1431109-59a1.patch

@@ -0,0 +1,39 @@
+# HG changeset patch
+# User Sylvestre Ledru <sledru@mozilla.com>
+# Date 1516201080 -3600
+# Node ID 1edfd721958383b3bf0c3219ccefb63bd1f55f05
+# Parent  215da04e16beed4f07f0194cee3333715f510777
+Bug 1431109 - Ignore a second incorrect warning with gcc (-Wuninitialized) r=froydnj
+
+MozReview-Commit-ID: 1QiA78wR9xB
+
+diff --git a/xpcom/base/StaticPtr.h b/xpcom/base/StaticPtr.h
+--- a/xpcom/base/StaticPtr.h
++++ b/xpcom/base/StaticPtr.h
+@@ -40,17 +40,25 @@ class MOZ_ONLY_USED_TO_AVOID_STATIC_CONS
+ {
+ public:
+   // In debug builds, check that mRawPtr is initialized for us as we expect
+   // by the compiler.  In non-debug builds, don't declare a constructor
+   // so that the compiler can see that the constructor is trivial.
+ #ifdef DEBUG
+   StaticAutoPtr()
+   {
++#ifdef __GNUC__
++#pragma GCC diagnostic push
++#pragma GCC diagnostic ignored "-Wuninitialized"
++  // False positive with gcc. See bug 1430729
++#endif
+     MOZ_ASSERT(!mRawPtr);
++#ifdef __GNUC__
++#pragma GCC diagnostic pop
++#endif
+   }
+ #endif
+ 
+   StaticAutoPtr<T>& operator=(T* aRhs)
+   {
+     Assign(aRhs);
+     return *this;
+   }
+

+ 32 - 0
mozilla-release/patches/1435223-59a1.patch

@@ -0,0 +1,32 @@
+# HG changeset patch
+# User Sylvestre Ledru <sledru@mozilla.com>
+# Date 1517574109 -3600
+# Node ID 86e0f2c3cc2d8dfdbdfffb2cd1ef77eda441eacb
+# Parent  9e41a686a5eda10bc630d2703fd8516e5804cf5a
+Bug 1435223 - Increase the size of idstring to avoid a warning r=baku
+
+MozReview-Commit-ID: FFOByQdUa0I
+
+diff --git a/dom/gamepad/linux/LinuxGamepad.cpp b/dom/gamepad/linux/LinuxGamepad.cpp
+--- a/dom/gamepad/linux/LinuxGamepad.cpp
++++ b/dom/gamepad/linux/LinuxGamepad.cpp
+@@ -36,17 +36,17 @@ static const char kJoystickPath[] = "/de
+ 
+ //TODO: should find a USB identifier for each device so we can
+ // provide something that persists across connect/disconnect cycles.
+ typedef struct {
+   int index;
+   guint source_id;
+   int numAxes;
+   int numButtons;
+-  char idstring[128];
++  char idstring[256];
+   char devpath[PATH_MAX];
+ } Gamepad;
+ 
+ class LinuxGamepadService {
+ public:
+   LinuxGamepadService() : mMonitor(nullptr),
+                           mMonitorSourceID(0) {
+   }
+

+ 211 - 0
mozilla-release/patches/1438196-60a1.patch

@@ -0,0 +1,211 @@
+# HG changeset patch
+# User David Keeler <dkeeler@mozilla.com>
+# Date 1520269949 28800
+# Node ID e1683e068e9415f1f002931934b2530172dff2d4
+# Parent  1040f6405dd9fe7d463bf5f8704c289903367fa9
+bug 1438196 - fix nsSSLIOLayerMethods definitions r=fkiefer
+
+MozReview-Commit-ID: 4Nu51f1DhSV
+
+diff --git a/security/manager/ssl/nsNSSIOLayer.cpp b/security/manager/ssl/nsNSSIOLayer.cpp
+--- a/security/manager/ssl/nsNSSIOLayer.cpp
++++ b/security/manager/ssl/nsNSSIOLayer.cpp
+@@ -1400,46 +1400,30 @@ nsSSLIOLayerHelpers::nsSSLIOLayerHelpers
+   : mTreatUnsafeNegotiationAsBroken(false)
+   , mTLSIntoleranceInfo()
+   , mVersionFallbackLimit(SSL_LIBRARY_VERSION_TLS_1_0)
+   , mutex("nsSSLIOLayerHelpers.mutex")
+   , mTlsFlags(aTlsFlags)
+ {
+ }
+ 
+-static int
+-_PSM_InvalidInt(void)
++// PSMAvailable and PSMAvailable64 are reachable, but they're unimplemented in
++// PSM, so we set an error and return -1.
++static int32_t
++PSMAvailable(PRFileDesc*)
+ {
+-  MOZ_ASSERT_UNREACHABLE("I/O method is invalid");
+-  PR_SetError(PR_INVALID_METHOD_ERROR, 0);
++  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+   return -1;
+ }
+ 
+ static int64_t
+-_PSM_InvalidInt64(void)
+-{
+-  MOZ_ASSERT_UNREACHABLE("I/O method is invalid");
+-  PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+-  return -1;
+-}
+-
+-static PRStatus
+-_PSM_InvalidStatus(void)
++PSMAvailable64(PRFileDesc*)
+ {
+-  MOZ_ASSERT_UNREACHABLE("I/O method is invalid");
+-  PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+-  return PR_FAILURE;
+-}
+-
+-static PRFileDesc*
+-_PSM_InvalidDesc(void)
+-{
+-  MOZ_ASSERT_UNREACHABLE("I/O method is invalid");
+-  PR_SetError(PR_INVALID_METHOD_ERROR, 0);
+-  return nullptr;
++  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
++  return -1;
+ }
+ 
+ static PRStatus
+ PSMGetsockname(PRFileDesc* fd, PRNetAddr* addr)
+ {
+   if (!getSocketInfoIfRunning(fd, not_reading_or_writing))
+     return PR_FAILURE;
+ 
+@@ -1611,32 +1595,16 @@ PSMConnectcontinue(PRFileDesc* fd, int16
+ {
+   if (!getSocketInfoIfRunning(fd, not_reading_or_writing)) {
+     return PR_FAILURE;
+   }
+ 
+   return fd->lower->methods->connectcontinue(fd, out_flags);
+ }
+ 
+-static int
+-PSMAvailable(void)
+-{
+-  // This is called through PR_Available(), but is not implemented in PSM
+-  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+-  return -1;
+-}
+-
+-static int64_t
+-PSMAvailable64(void)
+-{
+-  // This is called through PR_Available(), but is not implemented in PSM
+-  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+-  return -1;
+-}
+-
+ namespace {
+ 
+ class PrefObserver : public nsIObserver {
+ public:
+   NS_DECL_THREADSAFE_ISUPPORTS
+   NS_DECL_NSIOBSERVER
+   explicit PrefObserver(nsSSLIOLayerHelpers* aOwner) : mOwner(aOwner) {}
+ 
+@@ -1701,59 +1669,89 @@ nsSSLIOLayerHelpers::~nsSSLIOLayerHelper
+         "security.ssl.treat_unsafe_negotiation_as_broken");
+     Preferences::RemoveObserver(mPrefObserver,
+         "security.tls.version.fallback-limit");
+     Preferences::RemoveObserver(mPrefObserver,
+         "security.tls.insecure_fallback_hosts");
+   }
+ }
+ 
++template <typename R, R return_value, typename... Args>
++static R
++InvalidPRIOMethod(Args...)
++{
++  MOZ_ASSERT_UNREACHABLE("I/O method is invalid");
++  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
++  return return_value;
++}
++
+ nsresult
+ nsSSLIOLayerHelpers::Init()
+ {
+   if (!nsSSLIOLayerInitialized) {
+     MOZ_ASSERT(NS_IsMainThread());
+     nsSSLIOLayerInitialized = true;
+     nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
+-    nsSSLIOLayerMethods  = *PR_GetDefaultIOMethods();
+-
+-    nsSSLIOLayerMethods.available = (PRAvailableFN) PSMAvailable;
+-    nsSSLIOLayerMethods.available64 = (PRAvailable64FN) PSMAvailable64;
+-    nsSSLIOLayerMethods.fsync = (PRFsyncFN) _PSM_InvalidStatus;
+-    nsSSLIOLayerMethods.seek = (PRSeekFN) _PSM_InvalidInt;
+-    nsSSLIOLayerMethods.seek64 = (PRSeek64FN) _PSM_InvalidInt64;
+-    nsSSLIOLayerMethods.fileInfo = (PRFileInfoFN) _PSM_InvalidStatus;
+-    nsSSLIOLayerMethods.fileInfo64 = (PRFileInfo64FN) _PSM_InvalidStatus;
+-    nsSSLIOLayerMethods.writev = (PRWritevFN) _PSM_InvalidInt;
+-    nsSSLIOLayerMethods.accept = (PRAcceptFN) _PSM_InvalidDesc;
+-    nsSSLIOLayerMethods.listen = (PRListenFN) _PSM_InvalidStatus;
+-    nsSSLIOLayerMethods.shutdown = (PRShutdownFN) _PSM_InvalidStatus;
+-    nsSSLIOLayerMethods.recvfrom = (PRRecvfromFN) _PSM_InvalidInt;
+-    nsSSLIOLayerMethods.sendto = (PRSendtoFN) _PSM_InvalidInt;
+-    nsSSLIOLayerMethods.acceptread = (PRAcceptreadFN) _PSM_InvalidInt;
+-    nsSSLIOLayerMethods.transmitfile = (PRTransmitfileFN) _PSM_InvalidInt;
+-    nsSSLIOLayerMethods.sendfile = (PRSendfileFN) _PSM_InvalidInt;
+-
++    nsSSLIOLayerMethods = *PR_GetDefaultIOMethods();
++
++    nsSSLIOLayerMethods.fsync =
++      InvalidPRIOMethod<PRStatus, PR_FAILURE, PRFileDesc*>;
++    nsSSLIOLayerMethods.seek =
++      InvalidPRIOMethod<int32_t, -1, PRFileDesc*, int32_t, PRSeekWhence>;
++    nsSSLIOLayerMethods.seek64 =
++      InvalidPRIOMethod<int64_t, -1, PRFileDesc*, int64_t, PRSeekWhence>;
++    nsSSLIOLayerMethods.fileInfo =
++      InvalidPRIOMethod<PRStatus, PR_FAILURE, PRFileDesc*, PRFileInfo*>;
++    nsSSLIOLayerMethods.fileInfo64 =
++      InvalidPRIOMethod<PRStatus, PR_FAILURE, PRFileDesc*, PRFileInfo64*>;
++    nsSSLIOLayerMethods.writev =
++      InvalidPRIOMethod<int32_t, -1, PRFileDesc*, const PRIOVec*, int32_t,
++                        PRIntervalTime>;
++    nsSSLIOLayerMethods.accept =
++      InvalidPRIOMethod<PRFileDesc*, nullptr, PRFileDesc*, PRNetAddr*,
++                        PRIntervalTime>;
++    nsSSLIOLayerMethods.listen =
++      InvalidPRIOMethod<PRStatus, PR_FAILURE, PRFileDesc*, int>;
++    nsSSLIOLayerMethods.shutdown =
++      InvalidPRIOMethod<PRStatus, PR_FAILURE, PRFileDesc*, int>;
++    nsSSLIOLayerMethods.recvfrom =
++      InvalidPRIOMethod<int32_t, -1, PRFileDesc*, void*, int32_t, int,
++                        PRNetAddr*, PRIntervalTime>;
++    nsSSLIOLayerMethods.sendto =
++      InvalidPRIOMethod<int32_t, -1, PRFileDesc*, const void*, int32_t, int,
++                        const PRNetAddr*, PRIntervalTime>;
++    nsSSLIOLayerMethods.acceptread =
++      InvalidPRIOMethod<int32_t, -1, PRFileDesc*, PRFileDesc**, PRNetAddr**,
++                        void*, int32_t, PRIntervalTime>;
++    nsSSLIOLayerMethods.transmitfile =
++      InvalidPRIOMethod<int32_t, -1, PRFileDesc*, PRFileDesc*, const void*,
++                        int32_t, PRTransmitFileFlags, PRIntervalTime>;
++    nsSSLIOLayerMethods.sendfile =
++      InvalidPRIOMethod<int32_t, -1, PRFileDesc*, PRSendFileData*,
++                        PRTransmitFileFlags, PRIntervalTime>;
++
++    nsSSLIOLayerMethods.available = PSMAvailable;
++    nsSSLIOLayerMethods.available64 = PSMAvailable64;
+     nsSSLIOLayerMethods.getsockname = PSMGetsockname;
+     nsSSLIOLayerMethods.getpeername = PSMGetpeername;
+     nsSSLIOLayerMethods.getsocketoption = PSMGetsocketoption;
+     nsSSLIOLayerMethods.setsocketoption = PSMSetsocketoption;
+     nsSSLIOLayerMethods.recv = PSMRecv;
+     nsSSLIOLayerMethods.send = PSMSend;
+     nsSSLIOLayerMethods.connectcontinue = PSMConnectcontinue;
+     nsSSLIOLayerMethods.bind = PSMBind;
+ 
+     nsSSLIOLayerMethods.connect = nsSSLIOLayerConnect;
+     nsSSLIOLayerMethods.close = nsSSLIOLayerClose;
+     nsSSLIOLayerMethods.write = nsSSLIOLayerWrite;
+     nsSSLIOLayerMethods.read = nsSSLIOLayerRead;
+     nsSSLIOLayerMethods.poll = nsSSLIOLayerPoll;
+ 
+     nsSSLPlaintextLayerIdentity = PR_GetUniqueIdentity("Plaintxext PSM layer");
+-    nsSSLPlaintextLayerMethods  = *PR_GetDefaultIOMethods();
++    nsSSLPlaintextLayerMethods = *PR_GetDefaultIOMethods();
+     nsSSLPlaintextLayerMethods.recv = PlaintextRecv;
+   }
+ 
+   loadVersionFallbackLimit();
+ 
+   // non main thread helpers will need to use defaults
+   if (NS_IsMainThread()) {
+     bool enabled = false;
+

+ 31 - 0
mozilla-release/patches/1461614-62a1.patch

@@ -0,0 +1,31 @@
+# HG changeset patch
+# User Sylvestre Ledru <sledru@mozilla.com>
+# Date 1526378062 -7200
+# Node ID 55ca88db8ba95da98cadbfb6f877220332bd2176
+# Parent  b6306fd112d2d33f192ba4cae93edc8478d9ab7f
+Bug 1461614 - Use _DEFAULT_SOURCE on top of _BSD_SOURCE to remove a warning caused by the glibc r=drno
+
+MozReview-Commit-ID: 5Vso0zCzSBx
+
+diff --git a/media/mtransport/third_party/nrappkit/src/log/r_log.c b/media/mtransport/third_party/nrappkit/src/log/r_log.c
+--- a/media/mtransport/third_party/nrappkit/src/log/r_log.c
++++ b/media/mtransport/third_party/nrappkit/src/log/r_log.c
+@@ -37,16 +37,17 @@
+  */
+ 
+ 
+ static char *RCSSTRING __UNUSED__ ="$Id: r_log.c,v 1.10 2008/11/25 22:25:18 adamcain Exp $";
+ 
+ 
+ #ifdef LINUX
+ #define _BSD_SOURCE
++#define _DEFAULT_SOURCE
+ #endif
+ 
+ #include "r_log.h"
+ #include "hex.h"
+ 
+ #include <string.h>
+ #include <errno.h>
+ #ifndef _MSC_VER
+

+ 74 - 0
mozilla-release/patches/1464890-63a1.patch

@@ -0,0 +1,74 @@
+# HG changeset patch
+# User Brian Hackett <bhackett1024@gmail.com>
+# Date 1532131046 0
+# Node ID ff3c10d0cc05d15ec0e3e2d7c4d95c6dd860f0d1
+# Parent  385ff3d8137a2790823c76b3a1f15981b0eff85b
+Bug 1464890 - Use integers instead of raw pointer values as PRemoteSpellCheck IDs, r=ehsan.
+
+diff --git a/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp
+--- a/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp
++++ b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp
+@@ -16,52 +16,51 @@ RemoteSpellcheckEngineChild::~RemoteSpel
+ {
+   // null out the owner's SpellcheckEngineChild to prevent state corruption
+   // during shutdown
+   mOwner->DeleteRemoteEngine();
+ 
+   // ensure we don't leak any promise holders for which we haven't yet
+   // received responses
+   for (UniquePtr<MozPromiseHolder<GenericPromise>>& promiseHolder : mResponsePromises) {
+-    promiseHolder->RejectIfExists(NS_ERROR_ABORT, __func__);
++    if (promiseHolder) {
++      promiseHolder->RejectIfExists(NS_ERROR_ABORT, __func__);
++    }
+   }
+ }
+ 
+ RefPtr<GenericPromise>
+ RemoteSpellcheckEngineChild::SetCurrentDictionaryFromList(
+   const nsTArray<nsString>& aList)
+ {
+   UniquePtr<MozPromiseHolder<GenericPromise>> promiseHolder =
+     MakeUnique<MozPromiseHolder<GenericPromise>>();
+   if (!SendSetDictionaryFromList(
+          aList,
+-         reinterpret_cast<intptr_t>(promiseHolder.get()))) {
++         mResponsePromises.Length())) {
+     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+   }
+   RefPtr<GenericPromise> result = promiseHolder->Ensure(__func__);
+   // promiseHolder will removed by receive message
+   mResponsePromises.AppendElement(std::move(promiseHolder));
+   return result;
+ }
+ 
+ mozilla::ipc::IPCResult
+ RemoteSpellcheckEngineChild::RecvNotifyOfCurrentDictionary(
+                                const nsString& aDictionary,
+                                const intptr_t& aId)
+ {
+-  MozPromiseHolder<GenericPromise>* promiseHolder =
+-    reinterpret_cast<MozPromiseHolder<GenericPromise>*>(aId);
++  MOZ_RELEASE_ASSERT((size_t) aId < mResponsePromises.Length());
+   mOwner->mCurrentDictionary = aDictionary;
+   if (aDictionary.IsEmpty()) {
+-    promiseHolder->RejectIfExists(NS_ERROR_NOT_AVAILABLE, __func__);
++    mResponsePromises[aId]->RejectIfExists(NS_ERROR_NOT_AVAILABLE, __func__);
+   } else {
+-    promiseHolder->ResolveIfExists(true, __func__);
++    mResponsePromises[aId]->ResolveIfExists(true, __func__);
+   }
+-  for (uint32_t i = 0; i < mResponsePromises.Length(); ++i) {
+-    if (mResponsePromises[i].get() == promiseHolder) {
+-      mResponsePromises.RemoveElementAt(i);
+-      break;
+-    }
++  mResponsePromises[aId] = nullptr;
++  while (mResponsePromises.Length() && !mResponsePromises.LastElement()) {
++    (void) mResponsePromises.PopLastElement();
+   }
+   return IPC_OK();
+ }
+ 
+ } //namespace mozilla
+

+ 31 - 0
mozilla-release/patches/1477540-63a1.patch

@@ -0,0 +1,31 @@
+# HG changeset patch
+# User Sylvestre Ledru <sledru@mozilla.com>
+# Date 1532269437 -7200
+# Node ID 061213ccc62a5898157c50ab3c246314e057e45b
+# Parent  0033146ff4cf12a02bf24578465f2aaf12185db1
+Bug 1477540 - Use RemoveLastElement instead of PopLastElement r=bhackett
+
+The later is only interesting when the returned value is used
+
+MozReview-Commit-ID: 8CF5HSkcttf
+
+diff --git a/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp
+--- a/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp
++++ b/extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp
+@@ -53,14 +53,14 @@ RemoteSpellcheckEngineChild::RecvNotifyO
+   mOwner->mCurrentDictionary = aDictionary;
+   if (aDictionary.IsEmpty()) {
+     mResponsePromises[aId]->RejectIfExists(NS_ERROR_NOT_AVAILABLE, __func__);
+   } else {
+     mResponsePromises[aId]->ResolveIfExists(true, __func__);
+   }
+   mResponsePromises[aId] = nullptr;
+   while (mResponsePromises.Length() && !mResponsePromises.LastElement()) {
+-    (void) mResponsePromises.PopLastElement();
++    mResponsePromises.RemoveLastElement();
+   }
+   return IPC_OK();
+ }
+ 
+ } //namespace mozilla
+

+ 35 - 0
mozilla-release/patches/1519636-xx-elfhack-112a1.patch

@@ -0,0 +1,35 @@
+# HG changeset patch
+# User Andi-Bogdan Postelnicu <andi@mozilla.com>
+# Date 1676300527 0
+#      Mon Feb 13 15:02:07 2023 +0000
+# Node ID ebc57d2ea27722237890c550d76ad178926119cb
+# Parent  488ea16d9b8be15f2ec6070ae8fa579a6b97571e
+Bug 1519636 - Reformat recent changes to the Google coding style. r=glandium
+
+Updated with clang-format version 15.0.5 (taskcluster-MKK8dHUpQkGfPLA793lizg)
+# ignore-this-changeset
+
+Differential Revision: https://phabricator.services.mozilla.com/D168658
+
+diff --git a/build/unix/elfhack/test.c b/build/unix/elfhack/test.c
+--- a/build/unix/elfhack/test.c
++++ b/build/unix/elfhack/test.c
+@@ -84,17 +84,17 @@ DEF(phrases)
+ DEF(several)
+ DEF(times)
+ 
+ #else
+ #  pragma GCC visibility push(default)
+ #  include <stdlib.h>
+ #  include <stdio.h>
+ 
+-#  define DEF(w) static const char str_##w[] = #  w;
++#  define DEF(w) static const char str_##w[] = #w;
+ #  include "test.c"
+ #  undef DEF
+ 
+ const char* strings[] = {
+ #  define DEF(w) str_##w,
+ #  include "test.c"
+ #  include "test.c"
+ #  include "test.c"

+ 204 - 0
mozilla-release/patches/1519636-xx-elfhack-130a1.patch

@@ -0,0 +1,204 @@
+# HG changeset patch
+# User Sylvestre Ledru <sledru@mozilla.com>
+# Date 1721214931 0
+#      Wed Jul 17 11:15:31 2024 +0000
+# Node ID dffee1bbc0646b3bafcb39a8dfb85a273f43bdc1
+# Parent  5dceed29eddbcdccfc4120c8fda1b3988b7b7bb1
+Bug 1519636 - Reformat recent changes to the Google coding style r=emilio,necko-reviewers,geckoview-reviewers,application-update-reviewers,media-playback-reviewers,devtools-reviewers,anti-tracking-reviewers,profiler-reviewers,win-reviewers,migration-reviewers,padenot,mconley,nchevobbe,kershaw,gstoll,mstange,bytesized,m_kato
+
+This new version of clang 17 also slightly changed the formatting.
+
+# ignore-this-changeset
+
+Differential Revision: https://phabricator.services.mozilla.com/D215914
+
+diff --git a/build/unix/elfhack/elf.cpp b/build/unix/elfhack/elf.cpp
+--- a/build/unix/elfhack/elf.cpp
++++ b/build/unix/elfhack/elf.cpp
+@@ -588,18 +588,17 @@ Elf64_Off ElfSection::getOffset() {
+ }
+ 
+ int ElfSection::getIndex() {
+   if (index != -1) return index;
+   if (getType() == SHT_NULL) return (index = 0);
+   ElfSection* reference;
+   for (reference = previous;
+        (reference != nullptr) && (reference->getType() == SHT_NULL);
+-       reference = reference->getPrevious())
+-    ;
++       reference = reference->getPrevious());
+   if (reference == nullptr) return (index = 1);
+   return (index = reference->getIndex() + 1);
+ }
+ 
+ Elf_Shdr& ElfSection::getShdr() {
+   getOffset();
+   if (shdr.sh_link == (Elf64_Word)-1)
+     shdr.sh_link = getLink() ? getLink()->getIndex() : 0;
+@@ -639,18 +638,17 @@ void ElfSegment::removeSection(ElfSectio
+ 
+ unsigned int ElfSegment::getFileSize() {
+   if (type == PT_GNU_RELRO) return filesz;
+ 
+   if (sections.empty()) return 0;
+   // Search the last section that is not SHT_NOBITS
+   std::list<ElfSection*>::reverse_iterator i;
+   for (i = sections.rbegin();
+-       (i != sections.rend()) && ((*i)->getType() == SHT_NOBITS); ++i)
+-    ;
++       (i != sections.rend()) && ((*i)->getType() == SHT_NOBITS); ++i);
+   // All sections are SHT_NOBITS
+   if (i == sections.rend()) return 0;
+ 
+   unsigned int end = (*i)->getAddr() + (*i)->getSize();
+ 
+   return end - sections.front()->getAddr();
+ }
+ 
+diff --git a/build/unix/elfhack/elfxx.h b/build/unix/elfhack/elfxx.h
+--- a/build/unix/elfhack/elfxx.h
++++ b/build/unix/elfhack/elfxx.h
+@@ -131,58 +131,58 @@ class ElfValue {
+   virtual unsigned int getValue() { return 0; }
+   virtual ElfSection* getSection() { return nullptr; }
+ };
+ 
+ class ElfPlainValue : public ElfValue {
+   unsigned int value;
+ 
+  public:
+-  ElfPlainValue(unsigned int val) : value(val){};
++  ElfPlainValue(unsigned int val) : value(val) {};
+   unsigned int getValue() { return value; }
+ };
+ 
+ class ElfLocation : public ElfValue {
+   ElfSection* section;
+   unsigned int offset;
+ 
+  public:
+   enum position { ABSOLUTE, RELATIVE };
+-  ElfLocation() : section(nullptr), offset(0){};
++  ElfLocation() : section(nullptr), offset(0) {};
+   ElfLocation(ElfSection* section, unsigned int off,
+               enum position pos = RELATIVE);
+   ElfLocation(unsigned int location, Elf* elf);
+   unsigned int getValue();
+   ElfSection* getSection() { return section; }
+   const char* getBuffer();
+ };
+ 
+ class ElfSize : public ElfValue {
+   ElfSection* section;
+ 
+  public:
+-  ElfSize(ElfSection* s) : section(s){};
++  ElfSize(ElfSection* s) : section(s) {};
+   unsigned int getValue();
+   ElfSection* getSection() { return section; }
+ };
+ 
+ class ElfEntSize : public ElfValue {
+   ElfSection* section;
+ 
+  public:
+-  ElfEntSize(ElfSection* s) : section(s){};
++  ElfEntSize(ElfSection* s) : section(s) {};
+   unsigned int getValue();
+   ElfSection* getSection() { return section; }
+ };
+ 
+ template <typename T>
+ class serializable : public T::Type64 {
+  public:
+-  serializable(){};
+-  serializable(const typename T::Type64& p) : T::Type64(p){};
++  serializable() {};
++  serializable(const typename T::Type64& p) : T::Type64(p) {};
+ 
+  private:
+   template <typename R>
+   void init(const char* buf, size_t len, unsigned char ei_data) {
+     R e;
+     assert(len >= sizeof(e));
+     memcpy(&e, buf, sizeof(e));
+     if (ei_data == ELFDATA2LSB) {
+@@ -488,19 +488,19 @@ class Elf_Ehdr : public serializable<Elf
+   void serialize(std::ofstream& file, unsigned char ei_class,
+                  unsigned char ei_data) {
+     serializable<Elf_Ehdr_Traits>::serialize(file, ei_class, ei_data);
+   }
+ };
+ 
+ class Elf_Phdr : public serializable<Elf_Phdr_Traits> {
+  public:
+-  Elf_Phdr(){};
++  Elf_Phdr() {};
+   Elf_Phdr(std::ifstream& file, unsigned char ei_class, unsigned char ei_data)
+-      : serializable<Elf_Phdr_Traits>(file, ei_class, ei_data){};
++      : serializable<Elf_Phdr_Traits>(file, ei_class, ei_data) {};
+   bool contains(ElfSection* section) {
+     unsigned int size = section->getSize();
+     unsigned int addr = section->getAddr();
+     // This may be biased, but should work in most cases
+     if ((section->getFlags() & SHF_ALLOC) == 0) return false;
+     // Special case for PT_DYNAMIC. Eventually, this should
+     // be better handled than special cases
+     if ((p_type == PT_DYNAMIC) && (section->getType() != SHT_DYNAMIC))
+@@ -558,32 +558,32 @@ class ElfSymtab_Section : public ElfSect
+                        unsigned int type_filter = STT(OBJECT) | STT(FUNC));
+ 
+   // private: // Until we have a real API
+   std::vector<Elf_SymValue> syms;
+ };
+ 
+ class Elf_Rel : public serializable<Elf_Rel_Traits> {
+  public:
+-  Elf_Rel() : serializable<Elf_Rel_Traits>(){};
++  Elf_Rel() : serializable<Elf_Rel_Traits>() {};
+ 
+   Elf_Rel(std::ifstream& file, unsigned char ei_class, unsigned char ei_data)
+-      : serializable<Elf_Rel_Traits>(file, ei_class, ei_data){};
++      : serializable<Elf_Rel_Traits>(file, ei_class, ei_data) {};
+ 
+   static const unsigned int sh_type = SHT_REL;
+   static const unsigned int d_tag = DT_REL;
+   static const unsigned int d_tag_count = DT_RELCOUNT;
+ };
+ 
+ class Elf_Rela : public serializable<Elf_Rela_Traits> {
+  public:
+-  Elf_Rela() : serializable<Elf_Rela_Traits>(){};
++  Elf_Rela() : serializable<Elf_Rela_Traits>() {};
+ 
+   Elf_Rela(std::ifstream& file, unsigned char ei_class, unsigned char ei_data)
+-      : serializable<Elf_Rela_Traits>(file, ei_class, ei_data){};
++      : serializable<Elf_Rela_Traits>(file, ei_class, ei_data) {};
+ 
+   static const unsigned int sh_type = SHT_RELA;
+   static const unsigned int d_tag = DT_RELA;
+   static const unsigned int d_tag_count = DT_RELACOUNT;
+ };
+ 
+ template <class Rel>
+ class ElfRel_Section : public ElfSection {
+@@ -649,18 +649,17 @@ inline unsigned char Elf::getData() { re
+ 
+ inline unsigned char Elf::getType() { return ehdr->e_type; }
+ 
+ inline unsigned char Elf::getMachine() { return ehdr->e_machine; }
+ 
+ inline unsigned int Elf::getSize() {
+   ElfSection* section;
+   for (section = shdr_section /* It's usually not far from the end */;
+-       section->getNext() != nullptr; section = section->getNext())
+-    ;
++       section->getNext() != nullptr; section = section->getNext());
+   return section->getOffset() + section->getSize();
+ }
+ 
+ inline ElfSegment* ElfSection::getSegmentByType(unsigned int type) {
+   for (std::vector<ElfSegment*>::iterator seg = segments.begin();
+        seg != segments.end(); ++seg)
+     if ((*seg)->getType() == type) return *seg;
+   return nullptr;

+ 98 - 0
mozilla-release/patches/1838328-116a1.patch

@@ -0,0 +1,98 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1686732554 0
+#      Wed Jun 14 08:49:14 2023 +0000
+# Node ID 4e863389418f5bebcab8bace945cb80712f8cb7a
+# Parent  bf687698c6425dfc6ca9e3ec388531063854a9e4
+Bug 1838328 - Add a trampoline to call original_init when it's not possible directly, aarch64 edition. r=gsvelto
+
+Differential Revision: https://phabricator.services.mozilla.com/D180901
+
+diff --git a/build/unix/elfhack/elfhack.cpp b/build/unix/elfhack/elfhack.cpp
+--- a/build/unix/elfhack/elfhack.cpp
++++ b/build/unix/elfhack/elfhack.cpp
+@@ -176,20 +176,22 @@ class ElfRelHackCode_Section : public El
+ 
+     entry_point = sym->value.getValue();
+ 
+     // Get all relevant sections from the injected code object.
+     add_code_section(sym->value.getSection());
+ 
+     // If the original init function is located too far away, we're going to
+     // need to use a trampoline. See comment in inject.c.
+-    // Theoretically, we should check for (init - instr) > 0xffffff, where instr
+-    // is the virtual address of the instruction that calls the original init,
+-    // but we don't have it at this point, so punt to just init.
+-    if (init > 0xffffff && parent.getMachine() == EM_ARM) {
++    // Theoretically, we should check for (init - instr) > boundary, where
++    // boundary is the platform-dependent limit, and instr is the virtual
++    // address of the instruction that calls the original init, but we don't
++    // have it at this point, so punt to just init.
++    if ((init > 0xffffff && parent.getMachine() == EM_ARM) ||
++        (init > 0x07ffffff && parent.getMachine() == EM_AARCH64)) {
+       Elf_SymValue* trampoline = symtab->lookup("init_trampoline");
+       if (!trampoline) {
+         throw std::runtime_error(
+             "Couldn't find an 'init_trampoline' symbol in the injected code");
+       }
+ 
+       init_trampoline = trampoline->value.getSection();
+       add_code_section(init_trampoline);
+@@ -509,16 +511,19 @@ class ElfRelHackCode_Section : public El
+       switch (elf->getMachine() | (ELF64_R_TYPE(r->r_info) << 8)) {
+         case REL(X86_64, PC32):
+         case REL(X86_64, PLT32):
+         case REL(386, PC32):
+         case REL(386, GOTPC):
+         case REL(ARM, GOTPC):
+         case REL(ARM, REL32):
+         case REL(AARCH64, PREL32):
++        case REL(AARCH64,
++                 PREL64):  // In theory PREL64 should have its own relocation
++                           // function, but in practice it doesn't matter.
+           apply_relocation<pc32_relocation>(the_code, buf, &*r, addr);
+           break;
+         case REL(ARM, CALL):
+         case REL(ARM, JUMP24):
+         case REL(ARM, PLT32):
+           apply_relocation<arm_plt32_relocation>(the_code, buf, &*r, addr);
+           break;
+         case REL(ARM, THM_PC22 /* THM_CALL */):
+diff --git a/build/unix/elfhack/inject.c b/build/unix/elfhack/inject.c
+--- a/build/unix/elfhack/inject.c
++++ b/build/unix/elfhack/inject.c
+@@ -40,16 +40,34 @@
+       ".LAFTER:\n"
+       "  add ip, pc, ip\n"
+       "  bx ip\n"
+       ".LADDR:\n"
+       "  .word real_original_init-(.LAFTER+8)\n");
+ }
+ #endif
+ 
++// On aarch64, a similar problem exists, but long_call is not an option at all
++// (even GCC doesn't support them on aarch64).
++#ifdef __aarch64__
++__attribute__((section(".text._init_trampoline"), naked)) int init_trampoline(
++    int argc, char** argv, char** env) {
++  __asm__ __volatile__(
++      "  adrp x8, .LADDR\n"
++      "  add x8, x8, :lo12:.LADDR\n"  // adrp + add gives us the full address
++                                      // for .LADDR
++      "  ldr x0, [x8]\n"  // Load the address of real_original_init relative to
++                          // .LADDR
++      "  add x0, x8, x0\n"  // Add the address of .LADDR
++      "  br x0\n"           // Branch to real_original_init
++      ".LADDR:\n"
++      "  .xword real_original_init-.LADDR\n");
++}
++#endif
++
+ extern __attribute__((visibility("hidden"))) void original_init(int argc,
+                                                                 char** argv,
+                                                                 char** env);
+ 
+ extern __attribute__((visibility("hidden"))) Elf_Addr relhack[];
+ extern __attribute__((visibility("hidden"))) Elf_Ehdr elf_header;
+ 
+ extern __attribute__((visibility("hidden"))) int (*mprotect_cb)(void* addr,

+ 88 - 0
mozilla-release/patches/1839740-2-119a1.patch

@@ -0,0 +1,88 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1694893945 0
+#      Sat Sep 16 19:52:25 2023 +0000
+# Node ID ff6f21fecdbe7d7452d911404e680e0847ccd540
+# Parent  462a0de72bb97337c92b185707c6c25059a452c9
+Bug 1839740 - Rename the symbol by elfhack to point to the ELF header. r=firefox-build-system-reviewers,andi
+
+Elfhack acts as a linker, and it uses the `elf_header` symbol to point
+at the ELF header in the injected code that applies relocations.
+Both GNU ld and lld expose a `__ehdr_start` symbol with the same meaning,
+so rename the `elf_header` symbol for compatibility. This will allow to
+reuse the code in the upcoming replacement for elfhack.
+
+Differential Revision: https://phabricator.services.mozilla.com/D187088
+
+diff --git a/build/unix/elfhack/elfhack.cpp b/build/unix/elfhack/elfhack.cpp
+--- a/build/unix/elfhack/elfhack.cpp
++++ b/build/unix/elfhack/elfhack.cpp
+@@ -469,18 +469,18 @@ class ElfRelHackCode_Section : public El
+       // TODO: various checks on the symbol
+       const char* name = symtab->syms[ELF64_R_SYM(r->r_info)].name;
+       unsigned int addr;
+       if (symtab->syms[ELF64_R_SYM(r->r_info)].value.getSection() == nullptr) {
+         if (strcmp(name, "relhack") == 0) {
+           addr = relhack_section.getAddr();
+         } else if (strcmp(name, "relhack_end") == 0) {
+           addr = relhack_section.getAddr() + relhack_section.getSize();
+-        } else if (strcmp(name, "elf_header") == 0) {
+-          // TODO: change this ungly hack to something better
++        } else if (strcmp(name, "__ehdr_start") == 0) {
++          // TODO: change this ugly hack to something better
+           ElfSection* ehdr = parent.getSection(1)->getPrevious()->getPrevious();
+           addr = ehdr->getAddr();
+         } else if (strcmp(name, "original_init") == 0) {
+           if (init_trampoline) {
+             addr = init_trampoline->getAddr();
+           } else {
+             addr = init;
+           }
+diff --git a/build/unix/elfhack/inject.c b/build/unix/elfhack/inject.c
+--- a/build/unix/elfhack/inject.c
++++ b/build/unix/elfhack/inject.c
+@@ -64,40 +64,40 @@
+ #endif
+ 
+ extern __attribute__((visibility("hidden"))) void original_init(int argc,
+                                                                 char** argv,
+                                                                 char** env);
+ 
+ extern __attribute__((visibility("hidden"))) Elf_Addr relhack[];
+ extern __attribute__((visibility("hidden"))) Elf_Addr relhack_end[];
+-extern __attribute__((visibility("hidden"))) Elf_Ehdr elf_header;
++extern __attribute__((visibility("hidden"))) Elf_Ehdr __ehdr_start;
+ 
+ extern __attribute__((visibility("hidden"))) int (*mprotect_cb)(void* addr,
+                                                                 size_t len,
+                                                                 int prot);
+ extern __attribute__((visibility("hidden"))) long (*sysconf_cb)(int name);
+ extern __attribute__((visibility("hidden"))) char relro_start[];
+ extern __attribute__((visibility("hidden"))) char relro_end[];
+ 
+ static inline __attribute__((always_inline)) void do_relocations(void) {
+   Elf_Addr* ptr;
+   for (Elf_Addr* entry = relhack; entry < relhack_end; entry++) {
+     if ((*entry & 1) == 0) {
+-      ptr = (Elf_Addr*)((intptr_t)&elf_header + *entry);
+-      *ptr += (intptr_t)&elf_header;
++      ptr = (Elf_Addr*)((intptr_t)&__ehdr_start + *entry);
++      *ptr += (intptr_t)&__ehdr_start;
+     } else {
+       size_t remaining = (8 * sizeof(Elf_Addr) - 1);
+       Elf_Addr bits = *entry;
+       do {
+         bits >>= 1;
+         remaining--;
+         ptr++;
+         if (bits & 1) {
+-          *ptr += (intptr_t)&elf_header;
++          *ptr += (intptr_t)&__ehdr_start;
+         }
+       } while (bits);
+       ptr += remaining;
+     }
+   }
+ }
+ 
+ __attribute__((section(".text._init_noinit"))) int init_noinit(int argc,

+ 833 - 0
mozilla-release/patches/1839740-3-119a1.patch

@@ -0,0 +1,833 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1694893945 0
+#      Sat Sep 16 19:52:25 2023 +0000
+# Node ID 200dd4ded060b9f7eef115e74e739c7f3596b00b
+# Parent  f20d83892c23b01759eb83dcf72efe6d8c393762
+Bug 1839740 - New relrhack tool, a modern replacement to elfhack. r=firefox-build-system-reviewers,sergesanspaille
+
+Elfhack is the main reason we're not using lld on Linux/Android
+shippable builds, because the way it works doesn't go well with how lld
+lays out ELF binaries. By leveraging the linker itself (BFD and lld both
+having recently gained the ability to generate the compact relocation
+info themselves), we can achieve a similar result to what elfhack is
+doing, while allowing to use lld.
+
+See more in-depth background on https://glandium.org/blog/?p=4297
+
+Differential Revision: https://phabricator.services.mozilla.com/D187089
+
+diff --git a/build/unix/elfhack/Makefile.in b/build/unix/elfhack/Makefile.in
+--- a/build/unix/elfhack/Makefile.in
++++ b/build/unix/elfhack/Makefile.in
+@@ -1,15 +1,16 @@
+ #
+ # This Source Code Form is subject to the terms of the Mozilla Public
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ 
+ include $(topsrcdir)/config/rules.mk
+ 
++ifndef RELRHACK
+ test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX): %$(DLL_SUFFIX): %.$(OBJ_SUFFIX) elfhack
+ 	$(MKSHLIB) $(LDFLAGS) $< -nostartfiles
+ 	@echo ===
+ 	@echo === If you get failures below, please file a bug describing the error
+ 	@echo === and your environment \(compiler and linker versions\), and
+ 	@echo === provide the pre-elfhacked library as an attachment.
+ 	@echo === Use --disable-elf-hack until this is fixed.
+ 	@echo ===
+diff --git a/build/unix/elfhack/inject.c b/build/unix/elfhack/inject.c
+--- a/build/unix/elfhack/inject.c
++++ b/build/unix/elfhack/inject.c
+@@ -9,81 +9,96 @@
+ #include <elf.h>
+ 
+ /* The Android NDK headers define those */
+ #undef Elf_Ehdr
+ #undef Elf_Addr
+ 
+ #if defined(__LP64__)
+ #  define Elf_Ehdr Elf64_Ehdr
++#  define Elf_Phdr Elf64_Phdr
+ #  define Elf_Addr Elf64_Addr
++#  define Elf_Word Elf64_Word
++#  define Elf_Dyn Elf64_Dyn
+ #else
++#  define Elf_Phdr Elf32_Phdr
+ #  define Elf_Ehdr Elf32_Ehdr
+ #  define Elf_Addr Elf32_Addr
++#  define Elf_Word Elf32_Word
++#  define Elf_Dyn Elf32_Dyn
+ #endif
+ 
++#ifdef RELRHACK
++#  include "relrhack.h"
++#  define mprotect_cb mprotect
++#  define sysconf_cb sysconf
++
++#else
+ // On ARM, PC-relative function calls have a limit in how far they can jump,
+ // which might not be enough for e.g. libxul.so. The easy way out would be
+ // to use the long_call attribute, which forces the compiler to generate code
+ // that can call anywhere, but clang doesn't support the attribute yet
+ // (https://bugs.llvm.org/show_bug.cgi?id=40623), and while the command-line
+ // equivalent does exist, it's currently broken
+ // (https://bugs.llvm.org/show_bug.cgi?id=40624). So we create a manual
+ // trampoline, corresponding to the code GCC generates with long_call.
+-#ifdef __arm__
++#  ifdef __arm__
+ __attribute__((section(".text._init_trampoline"), naked)) int init_trampoline(
+     int argc, char** argv, char** env) {
+   __asm__ __volatile__(
+       // thumb doesn't allow to use r12/ip with ldr, and thus would require an
+       // additional push/pop to save/restore the modified register, which would
+       // also change the call into a blx. It's simpler to switch to arm.
+       ".arm\n"
+       "  ldr ip, .LADDR\n"
+       ".LAFTER:\n"
+       "  add ip, pc, ip\n"
+       "  bx ip\n"
+       ".LADDR:\n"
+       "  .word real_original_init-(.LAFTER+8)\n");
+ }
+-#endif
++#  endif
+ 
+ // On aarch64, a similar problem exists, but long_call is not an option at all
+ // (even GCC doesn't support them on aarch64).
+-#ifdef __aarch64__
++#  ifdef __aarch64__
+ __attribute__((section(".text._init_trampoline"), naked)) int init_trampoline(
+     int argc, char** argv, char** env) {
+   __asm__ __volatile__(
+       "  adrp x8, .LADDR\n"
+       "  add x8, x8, :lo12:.LADDR\n"  // adrp + add gives us the full address
+                                       // for .LADDR
+       "  ldr x0, [x8]\n"  // Load the address of real_original_init relative to
+                           // .LADDR
+       "  add x0, x8, x0\n"  // Add the address of .LADDR
+       "  br x0\n"           // Branch to real_original_init
+       ".LADDR:\n"
+       "  .xword real_original_init-.LADDR\n");
+ }
+-#endif
++#  endif
+ 
+ extern __attribute__((visibility("hidden"))) void original_init(int argc,
+                                                                 char** argv,
+                                                                 char** env);
+ 
+ extern __attribute__((visibility("hidden"))) Elf_Addr relhack[];
+ extern __attribute__((visibility("hidden"))) Elf_Addr relhack_end[];
+-extern __attribute__((visibility("hidden"))) Elf_Ehdr __ehdr_start;
+ 
+ extern __attribute__((visibility("hidden"))) int (*mprotect_cb)(void* addr,
+                                                                 size_t len,
+                                                                 int prot);
+ extern __attribute__((visibility("hidden"))) long (*sysconf_cb)(int name);
+ extern __attribute__((visibility("hidden"))) char relro_start[];
+ extern __attribute__((visibility("hidden"))) char relro_end[];
++#endif
+ 
+-static inline __attribute__((always_inline)) void do_relocations(void) {
++extern __attribute__((visibility("hidden"))) Elf_Ehdr __ehdr_start;
++
++static inline __attribute__((always_inline)) void do_relocations(
++    Elf_Addr* relhack, Elf_Addr* relhack_end) {
+   Elf_Addr* ptr;
+   for (Elf_Addr* entry = relhack; entry < relhack_end; entry++) {
+     if ((*entry & 1) == 0) {
+       ptr = (Elf_Addr*)((intptr_t)&__ehdr_start + *entry);
+       *ptr += (intptr_t)&__ehdr_start;
+     } else {
+       size_t remaining = (8 * sizeof(Elf_Addr) - 1);
+       Elf_Addr bits = *entry;
+@@ -95,61 +110,113 @@ static inline __attribute__((always_inli
+           *ptr += (intptr_t)&__ehdr_start;
+         }
+       } while (bits);
+       ptr += remaining;
+     }
+   }
+ }
+ 
++#ifndef RELRHACK
+ __attribute__((section(".text._init_noinit"))) int init_noinit(int argc,
+                                                                char** argv,
+                                                                char** env) {
+-  do_relocations();
++  do_relocations(relhack, relhack_end);
+   return 0;
+ }
+ 
+ __attribute__((section(".text._init"))) int init(int argc, char** argv,
+                                                  char** env) {
+-  do_relocations();
++  do_relocations(relhack, relhack_end);
+   original_init(argc, argv, env);
+   // Ensure there is no tail-call optimization, avoiding the use of the
+   // B.W instruction in Thumb for the call above.
+   return 0;
+ }
++#endif
+ 
+ static inline __attribute__((always_inline)) void do_relocations_with_relro(
+-    void) {
++    Elf_Addr* relhack, Elf_Addr* relhack_end, char* relro_start,
++    char* relro_end) {
+   long page_size = sysconf_cb(_SC_PAGESIZE);
+   uintptr_t aligned_relro_start = ((uintptr_t)relro_start) & ~(page_size - 1);
+   // The relro segment may not end at a page boundary. If that's the case, the
+   // remainder of the page needs to stay read-write, so the last page is never
+   // set read-only. Thus the aligned relro end is page-rounded down.
+   uintptr_t aligned_relro_end = ((uintptr_t)relro_end) & ~(page_size - 1);
+   // By the time the injected code runs, the relro segment is read-only. But
+   // we want to apply relocations in it, so we set it r/w first. We'll restore
+   // it to read-only in relro_post.
+   mprotect_cb((void*)aligned_relro_start,
+               aligned_relro_end - aligned_relro_start, PROT_READ | PROT_WRITE);
+ 
+-  do_relocations();
++  do_relocations(relhack, relhack_end);
+ 
+   mprotect_cb((void*)aligned_relro_start,
+               aligned_relro_end - aligned_relro_start, PROT_READ);
++#ifndef RELRHACK
+   // mprotect_cb and sysconf_cb are allocated in .bss, so we need to restore
+   // them to a NULL value.
+   mprotect_cb = NULL;
+   sysconf_cb = NULL;
++#endif
+ }
+ 
++#ifndef RELRHACK
+ __attribute__((section(".text._init_noinit_relro"))) int init_noinit_relro(
+     int argc, char** argv, char** env) {
+-  do_relocations_with_relro();
++  do_relocations_with_relro(relhack, relhack_end, relro_start, relro_end);
+   return 0;
+ }
+ 
+ __attribute__((section(".text._init_relro"))) int init_relro(int argc,
+                                                              char** argv,
+                                                              char** env) {
+-  do_relocations_with_relro();
++  do_relocations_with_relro(relhack, relhack_end, relro_start, relro_end);
+   original_init(argc, argv, env);
+   return 0;
+ }
++#else
++
++extern __attribute__((visibility("hidden"))) Elf_Dyn _DYNAMIC[];
++
++static void _relrhack_init(void) {
++  // Get the location of the SHT_RELR data from the PT_DYNAMIC segment.
++  uintptr_t elf_header = (uintptr_t)&__ehdr_start;
++  Elf_Addr* relhack = NULL;
++  Elf_Word size = 0;
++  for (Elf_Dyn* dyn = _DYNAMIC; dyn->d_tag != DT_NULL; dyn++) {
++    if ((dyn->d_tag & ~DT_RELRHACK_BIT) == DT_RELR) {
++      relhack = (Elf_Addr*)(elf_header + dyn->d_un.d_ptr);
++    } else if ((dyn->d_tag & ~DT_RELRHACK_BIT) == DT_RELRSZ) {
++      size = dyn->d_un.d_val;
++    }
++  }
++
++  Elf_Addr* relhack_end = (Elf_Addr*)((uintptr_t)relhack + size);
++
++  // Find the location of the PT_GNU_RELRO segment in the program headers.
++  Elf_Phdr* phdr = (Elf_Phdr*)(elf_header + __ehdr_start.e_phoff);
++  char* relro_start = NULL;
++  char* relro_end = NULL;
++  for (int i = 0; i < __ehdr_start.e_phnum; i++) {
++    if (phdr[i].p_type == PT_GNU_RELRO) {
++      relro_start = (char*)(elf_header + phdr[i].p_vaddr);
++      relro_end = (char*)(relro_start + phdr[i].p_memsz);
++      break;
++    }
++  }
++
++  if (relro_start != relro_end) {
++    do_relocations_with_relro(relhack, relhack_end, relro_start, relro_end);
++  } else {
++    do_relocations(relhack, relhack_end);
++  }
++}
++
++extern __attribute__((visibility("hidden"))) void _init(int argc, char** argv,
++                                                        char** env);
++
++void _relrhack_wrap_init(int argc, char** argv, char** env) {
++  _relrhack_init();
++  _init(argc, argv, env);
++}
++#endif
+diff --git a/build/unix/elfhack/inject/moz.build b/build/unix/elfhack/inject/moz.build
+--- a/build/unix/elfhack/inject/moz.build
++++ b/build/unix/elfhack/inject/moz.build
+@@ -15,16 +15,20 @@ cpu = CONFIG['CPU_ARCH']
+ gen_src = '%s.c' % cpu
+ GeneratedFile(gen_src, script='copy_source.py', entry_point='copy',
+               inputs = ['../inject.c'])
+ 
+ SOURCES += [
+     '!%s' % gen_src,
+ ]
+ 
++if CONFIG["RELRHACK"]:
++    DEFINES["RELRHACK"] = True
++    LOCAL_INCLUDES += [".."]
++
+ NO_PGO = True
+ 
+ for v in ('OS_CPPFLAGS', 'OS_CFLAGS', 'DEBUG', 'CLANG_PLUGIN', 'OPTIMIZE',
+           'FRAMEPTR'):
+     flags = []
+     idx = 0
+     for flag in COMPILE_FLAGS[v]:
+         if flag == '-isystem':
+diff --git a/build/unix/elfhack/moz.build b/build/unix/elfhack/moz.build
+--- a/build/unix/elfhack/moz.build
++++ b/build/unix/elfhack/moz.build
+@@ -13,21 +13,30 @@ if not CONFIG['CROSS_COMPILE']:
+         'test-array.c',
+         'test-ctors.c',
+     ]
+ 
+     SOURCES['dummy.c'].flags += ['-fno-lto']
+     SOURCES['test-array.c'].flags += ['-fno-lto']
+     SOURCES['test-ctors.c'].flags += ['-fno-lto']
+ 
+-HOST_SOURCES += [
+-    'elf.cpp',
+-    'elfhack.cpp',
+-]
++if CONFIG["RELRHACK"]:
++    HOST_SOURCES += [
++        "relrhack.cpp",
++    ]
++
++    HostProgram(CONFIG["RELRHACK_LINKER"])
+ 
+-HostProgram('elfhack')
++    HOST_OS_LIBS += CONFIG["RELRHACK_LIBS"]
++else:
++    HOST_SOURCES += [
++        "elf.cpp",
++        "elfhack.cpp",
++    ]
++
++    HostProgram("elfhack")
+ 
+ NO_PGO = True
+ 
+ COMPILE_FLAGS['OS_CXXFLAGS'] = [
+     f for f in COMPILE_FLAGS['OS_CXXFLAGS'] if f != '-fno-exceptions'
+ ] + ['-fexceptions']
+ 
+diff --git a/build/unix/elfhack/relrhack.cpp b/build/unix/elfhack/relrhack.cpp
+new file mode 100644
+--- /dev/null
++++ b/build/unix/elfhack/relrhack.cpp
+@@ -0,0 +1,451 @@
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++// This program acts as a linker wrapper. Its executable name is meant
++// to be that of a linker, and it will find the next linker with the same
++// name in $PATH. However, if for some reason the next linker cannot be
++// found this way, the caller may pass its path via the --real-linker
++// option.
++//
++// More in-depth background on https://glandium.org/blog/?p=4297
++
++#include "relrhack.h"
++#include <algorithm>
++#include <cstring>
++#include <filesystem>
++#include <fstream>
++#include <iostream>
++#include <optional>
++#include <spawn.h>
++#include <sstream>
++#include <sys/wait.h>
++#include <unistd.h>
++#include <vector>
++
++namespace fs = std::filesystem;
++
++template <int bits>
++struct Elf {};
++
++#define ELF(bits)                        \
++  template <>                            \
++  struct Elf<bits> {                     \
++    using Ehdr = Elf##bits##_Ehdr;       \
++    using Phdr = Elf##bits##_Phdr;       \
++    using Shdr = Elf##bits##_Shdr;       \
++    using Dyn = Elf##bits##_Dyn;         \
++    using Addr = Elf##bits##_Addr;       \
++    using Word = Elf##bits##_Word;       \
++    using Off = Elf##bits##_Off;         \
++    using Verneed = Elf##bits##_Verneed; \
++    using Vernaux = Elf##bits##_Vernaux; \
++  }
++
++ELF(32);
++ELF(64);
++
++template <int bits>
++struct RelR : public Elf<bits> {
++  using Elf_Ehdr = typename Elf<bits>::Ehdr;
++  using Elf_Phdr = typename Elf<bits>::Phdr;
++  using Elf_Shdr = typename Elf<bits>::Shdr;
++  using Elf_Dyn = typename Elf<bits>::Dyn;
++  using Elf_Addr = typename Elf<bits>::Addr;
++  using Elf_Word = typename Elf<bits>::Word;
++  using Elf_Off = typename Elf<bits>::Off;
++  using Elf_Verneed = typename Elf<bits>::Verneed;
++  using Elf_Vernaux = typename Elf<bits>::Vernaux;
++
++  // Translate a virtual address into an offset in the file based on the program
++  // headers' PT_LOAD.
++  static Elf_Addr get_offset(const std::vector<Elf_Phdr>& phdr, Elf_Addr addr) {
++    for (const auto& p : phdr) {
++      if (p.p_type == PT_LOAD && addr >= p.p_vaddr &&
++          addr < p.p_vaddr + p.p_filesz) {
++        return addr - (p.p_vaddr - p.p_paddr);
++      }
++    }
++    return 0;
++  }
++
++  static bool hack(std::fstream& f);
++};
++
++template <typename T>
++T read_one_at(std::istream& in, off_t pos) {
++  T result;
++  in.seekg(pos, std::ios::beg);
++  in.read(reinterpret_cast<char*>(&result), sizeof(T));
++  return result;
++}
++
++template <typename T>
++std::vector<T> read_vector_at(std::istream& in, off_t pos, size_t num) {
++  std::vector<T> result(num);
++  in.seekg(pos, std::ios::beg);
++  in.read(reinterpret_cast<char*>(result.data()), num * sizeof(T));
++  return result;
++}
++
++template <int bits>
++bool RelR<bits>::hack(std::fstream& f) {
++  auto ehdr = read_one_at<Elf_Ehdr>(f, 0);
++  if (ehdr.e_phentsize != sizeof(Elf_Phdr)) {
++    throw std::runtime_error("Invalid ELF?");
++  }
++  auto phdr = read_vector_at<Elf_Phdr>(f, ehdr.e_phoff, ehdr.e_phnum);
++  const auto& dyn_phdr =
++      std::find_if(phdr.begin(), phdr.end(),
++                   [](const auto& p) { return p.p_type == PT_DYNAMIC; });
++  if (dyn_phdr == phdr.end()) {
++    return false;
++  }
++  if (dyn_phdr->p_filesz % sizeof(Elf_Dyn)) {
++    throw std::runtime_error("Invalid ELF?");
++  }
++  // Find the location and size of several sections from the .dynamic section
++  // contents:
++  // - SHT_RELR section, which contains the packed-relative-relocs.
++  // - SHT_VERNEED section, which contains the symbol versions needed.
++  // - SHT_STRTAB section, which contains the string table for, among other
++  // things, those symbol versions.
++  // At the same time, we also change DT_RELR* tags to add DT_RELRHACK_BIT.
++  auto dyn = read_vector_at<Elf_Dyn>(f, dyn_phdr->p_offset,
++                                     dyn_phdr->p_filesz / sizeof(Elf_Dyn));
++  off_t dyn_offset = dyn_phdr->p_offset;
++  Elf_Addr strtab_off = 0, verneed_off = 0, relr_off = 0;
++  Elf_Off strsz = 0, verneednum = 0, relrsz = 0, relent = 0;
++  std::vector<std::pair<off_t, Elf_Off>> relr_tags;
++  for (const auto& d : dyn) {
++    if (d.d_tag == DT_NULL) {
++      break;
++    }
++    switch (d.d_tag) {
++      case DT_RELR:
++      case DT_RELRENT:
++      case DT_RELRSZ:
++        if (d.d_tag == DT_RELR) {
++          if (relr_off) {
++            throw std::runtime_error("DT_RELR appears twice?");
++          }
++          relr_off = get_offset(phdr, d.d_un.d_ptr);
++        } else if (d.d_tag == DT_RELRSZ) {
++          if (relrsz) {
++            throw std::runtime_error("DT_RELRSZ appears twice?");
++          }
++          relrsz = d.d_un.d_val;
++        }
++        relr_tags.push_back({dyn_offset, d.d_tag | DT_RELRHACK_BIT});
++        break;
++      case DT_RELAENT:
++      case DT_RELENT:
++        relent = d.d_un.d_val;
++        break;
++      case DT_STRTAB:
++        strtab_off = get_offset(phdr, d.d_un.d_ptr);
++        break;
++      case DT_STRSZ:
++        strsz = d.d_un.d_val;
++        break;
++      case DT_VERNEED:
++        verneed_off = get_offset(phdr, d.d_un.d_ptr);
++        break;
++      case DT_VERNEEDNUM:
++        verneednum = d.d_un.d_val;
++        break;
++    }
++    dyn_offset += sizeof(Elf_Dyn);
++  }
++
++  // Estimate the size of the unpacked relative relocations corresponding
++  // to the SHT_RELR section.
++  auto relr = read_vector_at<Elf_Addr>(f, relr_off, relrsz / sizeof(Elf_Addr));
++  size_t relocs = 0;
++  for (const auto& entry : relr) {
++    if ((entry & 1) == 0) {
++      // LSB is 0, this is a pointer for a single relocation.
++      relocs++;
++    } else {
++      // LSB is 1, remaining bits are a bitmap. Each bit represents a
++      // relocation.
++      relocs += __builtin_popcount(entry) - 1;
++    }
++  }
++  // If the packed relocations + some overhead (we pick 4K arbitrarily, the
++  // real size would require digging into the section sizes of the injected
++  // .o file, which is not worth the error) is larger than the estimated
++  // unpacked relocations, we'll just relink without packed relocations.
++  if (relocs * relent < relrsz + 4096) {
++    return false;
++  }
++
++  if (verneednum && verneed_off && strsz && strtab_off) {
++    // Scan SHT_VERNEED for the GLIBC_ABI_DT_RELR version on the libc
++    // library.
++    auto strtab = read_vector_at<char>(f, strtab_off, strsz);
++    // Guarantee a nul character at the end of the string table.
++    strtab.push_back(0);
++    while (verneednum--) {
++      auto verneed = read_one_at<Elf_Verneed>(f, verneed_off);
++      if (std::string_view{"libc.so.6"} == &strtab.at(verneed.vn_file)) {
++        Elf_Addr vernaux_off = verneed_off + verneed.vn_aux;
++        Elf_Addr relr = 0;
++        Elf_Vernaux reuse;
++        for (auto n = 0; n < verneed.vn_cnt; n++) {
++          auto vernaux = read_one_at<Elf_Vernaux>(f, vernaux_off);
++          if (std::string_view{"GLIBC_ABI_DT_RELR"} ==
++              &strtab.at(vernaux.vna_name)) {
++            relr = vernaux_off;
++          } else {
++            reuse = vernaux;
++          }
++          vernaux_off += vernaux.vna_next;
++        }
++        // In the case where we do have the GLIBC_ABI_DT_RELR version, we
++        // need to edit the binary to make the following changes:
++        // - Remove the GLIBC_ABI_DT_RELR version, we replace it with an
++        // arbitrary other version entry, which is simpler than completely
++        // removing it. We need to remove it because older versions of glibc
++        // don't have the version (after all, that's why the symbol version
++        // is there in the first place, to avoid running against older versions
++        // of glibc that don't support packed relocations).
++        // - Alter the DT_RELR* tags in the dynamic section, so that they
++        // are not recognized by ld.so, because, while all versions of ld.so
++        // ignore tags they don't know, glibc's ld.so versions that support
++        // packed relocations don't want to load a binary that has DT_RELR*
++        // tags but *not* a dependency on the GLIBC_ABI_DT_RELR version.
++        if (relr) {
++          f.seekg(relr, std::ios::beg);
++          // Don't overwrite vn_aux.
++          f.write(reinterpret_cast<char*>(&reuse),
++                  sizeof(reuse) - sizeof(Elf_Word));
++          for (const auto& [offset, tag] : relr_tags) {
++            f.seekg(offset, std::ios::beg);
++            f.write(reinterpret_cast<const char*>(&tag), sizeof(tag));
++          }
++        }
++      }
++      verneed_off += verneed.vn_next;
++    }
++  }
++  off_t shdr_offset = ehdr.e_shoff + offsetof(Elf_Shdr, sh_type);
++  auto shdr = read_vector_at<Elf_Shdr>(f, ehdr.e_shoff, ehdr.e_shnum);
++  for (const auto& s : shdr) {
++    // Some tools don't like sections of types they don't know, so change
++    // SHT_RELR, which might be unknown on older systems, to SHT_PROGBITS.
++    if (s.sh_type == SHT_RELR) {
++      Elf_Word progbits = SHT_PROGBITS;
++      f.seekg(shdr_offset, std::ios::beg);
++      f.write(reinterpret_cast<const char*>(&progbits), sizeof(progbits));
++    }
++    shdr_offset += sizeof(Elf_Shdr);
++  }
++  return true;
++}
++
++std::vector<std::string> get_path() {
++  std::vector<std::string> result;
++  std::stringstream stream{std::getenv("PATH")};
++  std::string item;
++
++  while (std::getline(stream, item, ':')) {
++    result.push_back(std::move(item));
++  }
++
++  return result;
++}
++
++std::optional<fs::path> next_program(fs::path& this_program,
++                                     std::optional<fs::path>& program) {
++  auto program_name = program ? *program : this_program.filename();
++  for (const auto& dir : get_path()) {
++    auto path = fs::path(dir) / program_name;
++    auto status = fs::status(path);
++    if ((status.type() == fs::file_type::regular) &&
++        ((status.permissions() & fs::perms::owner_exec) ==
++         fs::perms::owner_exec) &&
++        !fs::equivalent(path, this_program))
++      return path;
++  }
++  return std::nullopt;
++}
++
++unsigned char get_elf_class(unsigned char (&e_ident)[EI_NIDENT]) {
++  if (std::string_view{reinterpret_cast<char*>(e_ident), SELFMAG} !=
++      std::string_view{ELFMAG, SELFMAG}) {
++    throw std::runtime_error("Not ELF?");
++  }
++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
++  if (e_ident[EI_DATA] != ELFDATA2LSB) {
++    throw std::runtime_error("Not Little Endian ELF?");
++  }
++#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++  if (e_ident[EI_DATA] != ELFDATA2MSB) {
++    throw std::runtime_error("Not Big Endian ELF?");
++  }
++#else
++#  error Unknown byte order.
++#endif
++  if (e_ident[EI_VERSION] != 1) {
++    throw std::runtime_error("Not ELF version 1?");
++  }
++  auto elf_class = e_ident[EI_CLASS];
++  if (elf_class != ELFCLASS32 && elf_class != ELFCLASS64) {
++    throw std::runtime_error("Not 32 or 64-bits ELF?");
++  }
++  return elf_class;
++}
++
++unsigned char get_elf_class(std::istream& in) {
++  unsigned char e_ident[EI_NIDENT];
++  in.read(reinterpret_cast<char*>(e_ident), sizeof(e_ident));
++  return get_elf_class(e_ident);
++}
++
++uint16_t get_elf_machine(std::istream& in) {
++  // As far as e_machine is concerned, both Elf32_Ehdr and Elf64_Ehdr are equal.
++  Elf32_Ehdr ehdr;
++  in.read(reinterpret_cast<char*>(&ehdr), sizeof(ehdr));
++  // get_elf_class will throw exceptions for the cases we don't handle.
++  get_elf_class(ehdr.e_ident);
++  return ehdr.e_machine;
++}
++
++int run_command(std::vector<const char*>& args) {
++  pid_t child_pid;
++  if (posix_spawn(&child_pid, args[0], nullptr, nullptr,
++                  const_cast<char* const*>(args.data()), environ) != 0) {
++    throw std::runtime_error("posix_spawn failed");
++  }
++
++  int status;
++  waitpid(child_pid, &status, 0);
++  return WEXITSTATUS(status);
++}
++
++int main(int argc, char* argv[]) {
++  auto this_program = fs::absolute(argv[0]);
++
++  std::vector<const char*> args;
++
++  int i, crti = 0;
++  std::optional<fs::path> output = std::nullopt;
++  std::optional<fs::path> real_linker = std::nullopt;
++  bool shared = false;
++  uint16_t elf_machine = EM_NONE;
++  // Scan argv in order to prepare the following:
++  // - get the output file. That's the file we may need to adjust.
++  // - get the --real-linker if one was passed.
++  // - detect whether we're linking a shared library or something else. As of
++  // now, only shared libraries are handled. Technically speaking, programs
++  // could be handled as well, but for the purpose of Firefox, that actually
++  // doesn't work because programs contain a memory allocator that ends up
++  // being called before the injected code has any chance to apply relocations,
++  // and the allocator itself needs the relocations to have been applied.
++  // - detect the position of crti.o so that we can inject our own object
++  // right after it, and also to detect the machine type to pick the right
++  // object to inject.
++  //
++  // At the same time, we also construct a new list of arguments, with
++  // --real-linker filtered out. We'll later inject arguments in that list.
++  for (i = 1, argv++; i < argc && *argv; argv++, i++) {
++    std::string_view arg{*argv};
++    if (arg == "-shared") {
++      shared = true;
++    } else if (arg == "-o") {
++      args.push_back(*(argv++));
++      ++i;
++      output = *argv;
++    } else if (arg == "--real-linker") {
++      ++i;
++      real_linker = *(++argv);
++      continue;
++    } else if (elf_machine == EM_NONE && fs::path(arg).filename() == "crti.o") {
++      crti = i;
++      std::fstream f{std::string(arg), f.binary | f.in};
++      f.exceptions(f.failbit);
++      elf_machine = get_elf_machine(f);
++    }
++    args.push_back(*argv);
++  }
++
++  if (!output) {
++    std::cerr << "Could not determine output file." << std::endl;
++    return 1;
++  }
++
++  if (!crti) {
++    std::cerr << "Could not find crti.o on the command line." << std::endl;
++    return 1;
++  }
++
++  if (!real_linker || !real_linker->has_parent_path()) {
++    auto linker = next_program(this_program, real_linker);
++    if (!linker) {
++      std::cerr << "Could not find next "
++                << (real_linker ? real_linker->filename()
++                                : this_program.filename())
++                << std::endl;
++      return 1;
++    }
++    real_linker = linker;
++  }
++  args.insert(args.begin(), real_linker->c_str());
++  args.push_back(nullptr);
++
++  std::string stem;
++  switch (elf_machine) {
++    case EM_NONE:
++      std::cerr << "Could not determine target machine type." << std::endl;
++      return 1;
++    case EM_386:
++      stem = "x86";
++      break;
++    case EM_X86_64:
++      stem = "x86_64";
++      break;
++    case EM_ARM:
++      stem = "arm";
++      break;
++    case EM_AARCH64:
++      stem = "aarch64";
++      break;
++    default:
++      std::cerr << "Unsupported target machine type." << std::endl;
++      return 1;
++  }
++
++  if (shared) {
++    std::vector<const char*> hacked_args(args);
++    auto inject = this_program.parent_path() / "inject" / (stem + ".o");
++    hacked_args.insert(hacked_args.begin() + crti + 1, inject.c_str());
++    hacked_args.insert(hacked_args.end() - 1, {"-z", "pack-relative-relocs",
++                                               "-init=_relrhack_wrap_init"});
++    int status = run_command(hacked_args);
++    if (status) {
++      return status;
++    }
++    bool hacked = false;
++    try {
++      std::fstream f{*output, f.binary | f.in | f.out};
++      f.exceptions(f.failbit);
++      auto elf_class = get_elf_class(f);
++      f.seekg(0, std::ios::beg);
++      if (elf_class == ELFCLASS32) {
++        hacked = RelR<32>::hack(f);
++      } else if (elf_class == ELFCLASS64) {
++        hacked = RelR<64>::hack(f);
++      }
++    } catch (const std::runtime_error& err) {
++      std::cerr << "Failed to hack " << output->string() << ": " << err.what()
++                << std::endl;
++      return 1;
++    }
++    if (hacked) {
++      return 0;
++    }
++  }
++
++  return run_command(args);
++}
+diff --git a/build/unix/elfhack/relrhack.h b/build/unix/elfhack/relrhack.h
+new file mode 100644
+--- /dev/null
++++ b/build/unix/elfhack/relrhack.h
+@@ -0,0 +1,25 @@
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef __RELRHACK_H__
++#define __RELRHACK_H__
++
++#include <elf.h>
++
++#define DT_RELRHACK_BIT 0x8000000
++
++#ifndef DT_RELRSZ
++#  define DT_RELRSZ 35
++#endif
++#ifndef DT_RELR
++#  define DT_RELR 36
++#endif
++#ifndef DT_RELRENT
++#  define DT_RELRENT 37
++#endif
++#ifndef SHR_RELR
++#  define SHT_RELR 19
++#endif
++
++#endif /* __RELRHACK_H__ */
+diff --git a/build/unix/moz.build b/build/unix/moz.build
+--- a/build/unix/moz.build
++++ b/build/unix/moz.build
+@@ -2,14 +2,14 @@
+ # vim: set filetype=python:
+ # This Source Code Form is subject to the terms of the Mozilla Public
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ 
+ if CONFIG['MOZ_LIBSTDCXX_TARGET_VERSION'] or CONFIG['MOZ_LIBSTDCXX_HOST_VERSION']:
+     DIRS += ['stdc++compat']
+ 
+-if CONFIG['USE_ELF_HACK']:
++if CONFIG["USE_ELF_HACK"] or CONFIG["RELRHACK"]:
+     DIRS += ['elfhack']
+ 
+ FINAL_TARGET_FILES += [
+     'run-mozilla.sh',
+ ]

+ 78 - 0
mozilla-release/patches/1839741-119a1.patch

@@ -0,0 +1,78 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1693531234 0
+#      Fri Sep 01 01:20:34 2023 +0000
+# Node ID 190d58f47bdc34ed70643c4eb8a19bd674f23990
+# Parent  2cea0cb022c42b002373dedb8600404d0feb938f
+Bug 1839741 - Upgrade binutils to 2.41. r=firefox-build-system-reviewers,ahochheiden
+
+Because it bumps the alignment requirement on aarch64, we make the
+elfhack test create more relocations to make the .rela.dyn section large
+enough for the test to pass.
+
+Differential Revision: https://phabricator.services.mozilla.com/D181684
+
+diff --git a/build/unix/build-binutils/build-binutils.sh.1839741.later b/build/unix/build-binutils/build-binutils.sh.1839741.later
+new file mode 100644
+--- /dev/null
++++ b/build/unix/build-binutils/build-binutils.sh.1839741.later
+@@ -0,0 +1,17 @@
++--- build-binutils.sh
+++++ build-binutils.sh
++@@ -1,13 +1,13 @@
++ #!/bin/bash
++ 
++ set -x
++ 
++-make_flags="-j$(nproc)"
+++make_flags="-j$(nproc) MAKEINFO=true"
++ 
++ root_dir="$1"
++ 
++ cd $root_dir/binutils-source
++ 
++ patch -p1 <<'EOF'
++ From 4476cc67e657d6b26cd453c555a611f1ab956660 Mon Sep 17 00:00:00 2001
++ From: "H.J. Lu" <hjl.tools@gmail.com>
+diff --git a/build/unix/elfhack/test.c b/build/unix/elfhack/test.c
+--- a/build/unix/elfhack/test.c
++++ b/build/unix/elfhack/test.c
+@@ -123,16 +123,38 @@ int bigger_hole[] = {
+ };
+ 
+ const char* strings3[] = {
+ #  include "test.c"
+ #  include "test.c"
+ #  include "test.c"
+ #  include "test.c"
+ #  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
++#  include "test.c"
+ #  undef DEF
+ };
+ 
+ static int ret = 1;
+ 
+ int print_status() {
+   fprintf(stderr, "%s\n", ret ? "FAIL" : "PASS");
+   return ret;

+ 128 - 0
mozilla-release/patches/1839746-116a1.patch

@@ -0,0 +1,128 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1687478207 0
+#      Thu Jun 22 23:56:47 2023 +0000
+# Node ID aa6bc40ee97d9b3176aa2ed5e4646edeccc9ece2
+# Parent  6e3431f2c7903a5e1be7b275212837c6b4f2f990
+Bug 1839746 - Make elfhack generate and handle a more standard SHT_RELR section. r=gsvelto
+
+Bug 1747782 changed the format to SHT_RELR, but what's produced is still
+different from a real SHT_RELR section, because it uses a terminating
+nul entry.
+
+Differential Revision: https://phabricator.services.mozilla.com/D181689
+
+diff --git a/build/unix/elfhack/elfhack.cpp b/build/unix/elfhack/elfhack.cpp
+--- a/build/unix/elfhack/elfhack.cpp
++++ b/build/unix/elfhack/elfhack.cpp
+@@ -54,16 +54,19 @@ class ElfRelHack_Section : public ElfSec
+   ElfRelHack_Section(Elf_Shdr& s)
+       : ElfSection(s, nullptr, nullptr),
+         block_size((8 * s.sh_entsize - 1) * s.sh_entsize) {
+     name = elfhack_data;
+   };
+ 
+   void serialize(std::ofstream& file, unsigned char ei_class,
+                  unsigned char ei_data) {
++    if (bitmap) {
++      relr.push_back((bitmap << 1) | 1);
++    }
+     for (std::vector<Elf64_Addr>::iterator i = relr.begin(); i != relr.end();
+          ++i) {
+       Elf_Addr out;
+       out.value = *i;
+       out.serialize(file, ei_class, ei_data);
+     }
+   }
+ 
+@@ -96,17 +99,17 @@ class ElfRelHack_Section : public ElfSec
+         }
+         relr.push_back(offset);
+         block_start = offset + shdr.sh_entsize;
+         break;
+       }
+       bitmap |= 1ULL << ((offset - block_start) / shdr.sh_entsize);
+       break;
+     }
+-    shdr.sh_size = relr.size() * shdr.sh_entsize;
++    shdr.sh_size = (relr.size() + (bitmap ? 1 : 0)) * shdr.sh_entsize;
+   }
+ 
+  private:
+   std::vector<Elf64_Addr> relr;
+   size_t block_size;
+   Elf64_Addr block_start = 0;
+   Elf64_Addr bitmap = 0;
+ };
+@@ -464,16 +467,18 @@ class ElfRelHackCode_Section : public El
+     for (typename std::vector<Rel_Type>::iterator r = rel->rels.begin();
+          r != rel->rels.end(); ++r) {
+       // TODO: various checks on the symbol
+       const char* name = symtab->syms[ELF64_R_SYM(r->r_info)].name;
+       unsigned int addr;
+       if (symtab->syms[ELF64_R_SYM(r->r_info)].value.getSection() == nullptr) {
+         if (strcmp(name, "relhack") == 0) {
+           addr = relhack_section.getAddr();
++        } else if (strcmp(name, "relhack_end") == 0) {
++          addr = relhack_section.getAddr() + relhack_section.getSize();
+         } else if (strcmp(name, "elf_header") == 0) {
+           // TODO: change this ungly hack to something better
+           ElfSection* ehdr = parent.getSection(1)->getPrevious()->getPrevious();
+           addr = ehdr->getAddr();
+         } else if (strcmp(name, "original_init") == 0) {
+           if (init_trampoline) {
+             addr = init_trampoline->getAddr();
+           } else {
+@@ -1013,18 +1018,16 @@ int do_relocation_section(Elf* elf, unsi
+       } else if (addr.value != addend) {
+         fprintf(stderr,
+                 "Relocation addend inconsistent with content. Skipping\n");
+         return -1;
+       }
+       relhack->push_back(i->r_offset);
+     }
+   }
+-  // Last entry must be a nullptr
+-  relhack->push_back(0);
+ 
+   if (init_array) {
+     // Some linkers create a DT_INIT_ARRAY section that, for all purposes,
+     // is empty: it only contains 0x0 or 0xffffffff pointers with no
+     // relocations. In some other cases, there can be null pointers with no
+     // relocations in the middle of the section. Example: crtend_so.o in the
+     // Android NDK contains a sized .init_array with a null pointer and no
+     // relocation, which ends up in all Android libraries, and in some cases it
+diff --git a/build/unix/elfhack/inject.c b/build/unix/elfhack/inject.c
+--- a/build/unix/elfhack/inject.c
++++ b/build/unix/elfhack/inject.c
+@@ -63,28 +63,29 @@
+ }
+ #endif
+ 
+ extern __attribute__((visibility("hidden"))) void original_init(int argc,
+                                                                 char** argv,
+                                                                 char** env);
+ 
+ extern __attribute__((visibility("hidden"))) Elf_Addr relhack[];
++extern __attribute__((visibility("hidden"))) Elf_Addr relhack_end[];
+ extern __attribute__((visibility("hidden"))) Elf_Ehdr elf_header;
+ 
+ extern __attribute__((visibility("hidden"))) int (*mprotect_cb)(void* addr,
+                                                                 size_t len,
+                                                                 int prot);
+ extern __attribute__((visibility("hidden"))) long (*sysconf_cb)(int name);
+ extern __attribute__((visibility("hidden"))) char relro_start[];
+ extern __attribute__((visibility("hidden"))) char relro_end[];
+ 
+ static inline __attribute__((always_inline)) void do_relocations(void) {
+   Elf_Addr* ptr;
+-  for (Elf_Addr* entry = relhack; *entry; entry++) {
++  for (Elf_Addr* entry = relhack; entry < relhack_end; entry++) {
+     if ((*entry & 1) == 0) {
+       ptr = (Elf_Addr*)((intptr_t)&elf_header + *entry);
+       *ptr += (intptr_t)&elf_header;
+     } else {
+       size_t remaining = (8 * sizeof(Elf_Addr) - 1);
+       Elf_Addr bits = *entry;
+       do {
+         bits >>= 1;

+ 164 - 0
mozilla-release/patches/1840931-116a1.patch

@@ -0,0 +1,164 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1688068580 0
+#      Thu Jun 29 19:56:20 2023 +0000
+# Node ID 51b78cf4881b07422c0c6e590e863b095257e9e1
+# Parent  eef8bff2d6117cc88dcca9ab4718be0f5186924b
+Bug 1840931 - More properly handle files > 4GB in elfhack. r=gsvelto
+
+I'm pretty sure there are other theoretical problems in the code,
+notably when a single section is larger than 4GB, but by the time
+we reach that limit, bug 1839740 will have been fixed.
+
+Differential Revision: https://phabricator.services.mozilla.com/D182447
+
+diff --git a/build/unix/elfhack/elf.cpp b/build/unix/elfhack/elf.cpp
+--- a/build/unix/elfhack/elf.cpp
++++ b/build/unix/elfhack/elf.cpp
+@@ -344,17 +344,17 @@ ElfSection* Elf::getSection(int index) {
+         break;
+       default:
+         sections[index] = new ElfSection(*tmp_shdr[index], tmp_file, this);
+     }
+   }
+   return sections[index];
+ }
+ 
+-ElfSection* Elf::getSectionAt(unsigned int offset) {
++ElfSection* Elf::getSectionAt(Elf64_Off offset) {
+   for (int i = 1; i < ehdr->e_shnum; i++) {
+     ElfSection* section = getSection(i);
+     if ((section != nullptr) && (section->getFlags() & SHF_ALLOC) &&
+         !(section->getFlags() & SHF_TLS) && (offset >= section->getAddr()) &&
+         (offset < section->getAddr() + section->getSize()))
+       return section;
+   }
+   return nullptr;
+@@ -529,38 +529,38 @@ ElfSection::ElfSection(Elf_Shdr& s, std:
+   // Only SHT_REL/SHT_RELA sections use sh_info to store a section
+   // number.
+   if ((shdr.sh_type == SHT_REL) || (shdr.sh_type == SHT_RELA))
+     info.section = shdr.sh_info ? parent->getSection(shdr.sh_info) : nullptr;
+   else
+     info.index = shdr.sh_info;
+ }
+ 
+-unsigned int ElfSection::getAddr() {
++Elf64_Addr ElfSection::getAddr() {
+   if (shdr.sh_addr != (Elf64_Addr)-1) return shdr.sh_addr;
+ 
+   // It should be safe to adjust sh_addr for all allocated sections that
+   // are neither SHT_NOBITS nor SHT_PROGBITS
+   if ((previous != nullptr) && isRelocatable()) {
+     unsigned int addr = previous->getAddr();
+     if (previous->getType() != SHT_NOBITS) addr += previous->getSize();
+ 
+     if (addr & (getAddrAlign() - 1)) addr = (addr | (getAddrAlign() - 1)) + 1;
+ 
+     return (shdr.sh_addr = addr);
+   }
+   return shdr.sh_addr;
+ }
+ 
+-unsigned int ElfSection::getOffset() {
++Elf64_Off ElfSection::getOffset() {
+   if (shdr.sh_offset != (Elf64_Off)-1) return shdr.sh_offset;
+ 
+   if (previous == nullptr) return (shdr.sh_offset = 0);
+ 
+-  unsigned int offset = previous->getOffset();
++  Elf64_Off offset = previous->getOffset();
+ 
+   ElfSegment* ptload = getSegmentByType(PT_LOAD);
+   ElfSegment* prev_ptload = previous->getSegmentByType(PT_LOAD);
+ 
+   if (ptload && (ptload == prev_ptload)) {
+     offset += getAddr() - previous->getAddr();
+     return (shdr.sh_offset = offset);
+   }
+diff --git a/build/unix/elfhack/elfhack.cpp b/build/unix/elfhack/elfhack.cpp
+--- a/build/unix/elfhack/elfhack.cpp
++++ b/build/unix/elfhack/elfhack.cpp
+@@ -1255,18 +1255,18 @@ int do_relocation_section(Elf* elf, unsi
+         "Expected to find an .eh_frame section adjacent to .eh_frame_hdr");
+   }
+   if (eh_frame && first->getAddr() > relhack->getAddr() &&
+       second->getAddr() < first_executable->getAddr()) {
+     // The distance between both sections needs to be preserved because
+     // eh_frame_hdr contains relative offsets to eh_frame. Well, they could be
+     // relocated too, but it's not worth the effort for the few number of bytes
+     // this would save.
+-    unsigned int distance = second->getAddr() - first->getAddr();
+-    unsigned int origAddr = eh_frame->getAddr();
++    Elf64_Off distance = second->getAddr() - first->getAddr();
++    Elf64_Addr origAddr = eh_frame->getAddr();
+     ElfSection* previous = first->getPrevious();
+     first->getShdr().sh_addr = (previous->getAddr() + previous->getSize() +
+                                 first->getAddrAlign() - 1) &
+                                ~(first->getAddrAlign() - 1);
+     second->getShdr().sh_addr =
+         (first->getAddr() + std::min(first->getSize(), distance) +
+          second->getAddrAlign() - 1) &
+         ~(second->getAddrAlign() - 1);
+diff --git a/build/unix/elfhack/elfxx.h b/build/unix/elfhack/elfxx.h
+--- a/build/unix/elfhack/elfxx.h
++++ b/build/unix/elfhack/elfxx.h
+@@ -280,17 +280,17 @@ typedef serializable<Elf_Shdr_Traits> El
+ class Elf {
+  public:
+   Elf(std::ifstream& file);
+   ~Elf();
+ 
+   /* index == -1 is treated as index == ehdr.e_shstrndx */
+   ElfSection* getSection(int index);
+ 
+-  ElfSection* getSectionAt(unsigned int offset);
++  ElfSection* getSectionAt(Elf64_Off offset);
+ 
+   ElfSegment* getSegmentByType(unsigned int type, ElfSegment* last = nullptr);
+ 
+   ElfDynamic_Section* getDynSection();
+ 
+   void normalize();
+   void write(std::ofstream& file);
+ 
+@@ -329,18 +329,18 @@ class ElfSection {
+ 
+   ElfSection(Elf_Shdr& s, std::ifstream* file, Elf* parent);
+ 
+   virtual ~ElfSection() { free(data); }
+ 
+   const char* getName() { return name; }
+   unsigned int getType() { return shdr.sh_type; }
+   unsigned int getFlags() { return shdr.sh_flags; }
+-  unsigned int getAddr();
+-  unsigned int getSize() { return shdr.sh_size; }
++  Elf64_Addr getAddr();
++  Elf64_Off getSize() { return shdr.sh_size; }
+   unsigned int getAddrAlign() { return shdr.sh_addralign; }
+   unsigned int getEntSize() { return shdr.sh_entsize; }
+   const char* getData() { return data; }
+   ElfSection* getLink() { return link; }
+   SectionInfo getInfo() { return info; }
+ 
+   void shrink(unsigned int newsize) {
+     if (newsize < shdr.sh_size) {
+@@ -353,17 +353,17 @@ class ElfSection {
+     if (newsize > shdr.sh_size) {
+       data = static_cast<char*>(realloc(data, newsize));
+       memset(data + shdr.sh_size, 0, newsize - shdr.sh_size);
+       shdr.sh_size = newsize;
+       markDirty();
+     }
+   }
+ 
+-  unsigned int getOffset();
++  Elf64_Off getOffset();
+   int getIndex();
+   Elf_Shdr& getShdr();
+ 
+   ElfSection* getNext() { return next; }
+   ElfSection* getPrevious() { return previous; }
+ 
+   virtual bool isRelocatable() {
+     return ((getType() == SHT_SYMTAB) || (getType() == SHT_STRTAB) ||

+ 34 - 0
mozilla-release/patches/1841212-116a1.patch

@@ -0,0 +1,34 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1688112703 0
+#      Fri Jun 30 08:11:43 2023 +0000
+# Node ID 79902abafde5b5ba232818f5bf6dd256bd74dc45
+# Parent  6c993ee838a36b063da8c5aa6c2fd4d1fd0dfbe9
+Bug 1841212 - Build elfhack injected code without eh_frame. r=firefox-build-system-reviewers,sergesanspaille
+
+Differential Revision: https://phabricator.services.mozilla.com/D182542
+
+diff --git a/build/unix/elfhack/inject/moz.build b/build/unix/elfhack/inject/moz.build
+--- a/build/unix/elfhack/inject/moz.build
++++ b/build/unix/elfhack/inject/moz.build
+@@ -29,12 +29,19 @@ for v in ('OS_CPPFLAGS', 'OS_CFLAGS', 'D
+     for flag in COMPILE_FLAGS[v]:
+         if flag == '-isystem':
+             flags.append(''.join(COMPILE_FLAGS[v][idx:idx + 2]))
+         elif flag.startswith(('-m', '-I', '-isystem')):
+             flags.append(flag)
+         idx += 1
+     COMPILE_FLAGS[v] = flags
+ 
+-COMPILE_FLAGS['OS_CFLAGS'] += ['-O2', '-fno-stack-protector', '-fno-lto']
++COMPILE_FLAGS["OS_CFLAGS"] += [
++    "-O2",
++    "-fno-stack-protector",
++    "-fno-lto",
++    # The injected code runs early enough that it supporting unwinding is useless.
++    # Moreover, elfhack doesn't inject the eh_frame section anyways.
++    "-fno-asynchronous-unwind-tables",
++]
+ 
+ AllowCompilerWarnings()
+ NoVisibilityFlags()

+ 147 - 0
mozilla-release/patches/1850867-1-119a1.patch

@@ -0,0 +1,147 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1695097937 0
+#      Tue Sep 19 04:32:17 2023 +0000
+# Node ID cc547cd2d8669f3a4779dc73c0631f3db9a2bf15
+# Parent  fccdfffe71fc6e4ef8d108f9711a705db0014db3
+Bug 1850867 - Add relrhack support for Android. r=firefox-build-system-reviewers,andi
+
+Differential Revision: https://phabricator.services.mozilla.com/D188410
+
+diff --git a/build/unix/elfhack/inject.c b/build/unix/elfhack/inject.c
+--- a/build/unix/elfhack/inject.c
++++ b/build/unix/elfhack/inject.c
+@@ -207,16 +207,21 @@ static void _relrhack_init(void) {
+ 
+   if (relro_start != relro_end) {
+     do_relocations_with_relro(relhack, relhack_end, relro_start, relro_end);
+   } else {
+     do_relocations(relhack, relhack_end);
+   }
+ }
+ 
++// The Android CRT doesn't contain an init function.
++#  ifndef ANDROID
+ extern __attribute__((visibility("hidden"))) void _init(int argc, char** argv,
+                                                         char** env);
++#  endif
+ 
+ void _relrhack_wrap_init(int argc, char** argv, char** env) {
+   _relrhack_init();
++#  ifndef ANDROID
+   _init(argc, argv, env);
++#  endif
+ }
+ #endif
+diff --git a/build/unix/elfhack/inject/moz.build b/build/unix/elfhack/inject/moz.build
+--- a/build/unix/elfhack/inject/moz.build
++++ b/build/unix/elfhack/inject/moz.build
+@@ -5,19 +5,22 @@
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ 
+ # dummy library name to avoid skipping building the source here, which
+ # we only need the object for.
+ Library('elfhack_inject')
+ 
+ DIST_INSTALL = False
+ 
+-cpu = CONFIG['CPU_ARCH']
++stem = CONFIG["CPU_ARCH"]
++if CONFIG["OS_TARGET"] == "Android":
++    stem += "-android"
+ 
+-gen_src = '%s.c' % cpu
++
++gen_src = '%s.c' % stem
+ GeneratedFile(gen_src, script='copy_source.py', entry_point='copy',
+               inputs = ['../inject.c'])
+ 
+ SOURCES += [
+     '!%s' % gen_src,
+ ]
+ 
+ if CONFIG["RELRHACK"]:
+diff --git a/build/unix/elfhack/relrhack.cpp b/build/unix/elfhack/relrhack.cpp
+--- a/build/unix/elfhack/relrhack.cpp
++++ b/build/unix/elfhack/relrhack.cpp
+@@ -328,16 +328,17 @@ int main(int argc, char* argv[]) {
+   auto this_program = fs::absolute(argv[0]);
+ 
+   std::vector<const char*> args;
+ 
+   int i, crti = 0;
+   std::optional<fs::path> output = std::nullopt;
+   std::optional<fs::path> real_linker = std::nullopt;
+   bool shared = false;
++  bool is_android = false;
+   uint16_t elf_machine = EM_NONE;
+   // Scan argv in order to prepare the following:
+   // - get the output file. That's the file we may need to adjust.
+   // - get the --real-linker if one was passed.
+   // - detect whether we're linking a shared library or something else. As of
+   // now, only shared libraries are handled. Technically speaking, programs
+   // could be handled as well, but for the purpose of Firefox, that actually
+   // doesn't work because programs contain a memory allocator that ends up
+@@ -356,32 +357,36 @@ int main(int argc, char* argv[]) {
+     } else if (arg == "-o") {
+       args.push_back(*(argv++));
+       ++i;
+       output = *argv;
+     } else if (arg == "--real-linker") {
+       ++i;
+       real_linker = *(++argv);
+       continue;
+-    } else if (elf_machine == EM_NONE && fs::path(arg).filename() == "crti.o") {
+-      crti = i;
+-      std::fstream f{std::string(arg), f.binary | f.in};
+-      f.exceptions(f.failbit);
+-      elf_machine = get_elf_machine(f);
++    } else if (elf_machine == EM_NONE) {
++      auto filename = fs::path(arg).filename();
++      if (filename == "crti.o" || filename == "crtbegin_so.o") {
++        is_android = (filename == "crtbegin_so.o");
++        crti = i;
++        std::fstream f{std::string(arg), f.binary | f.in};
++        f.exceptions(f.failbit);
++        elf_machine = get_elf_machine(f);
++      }
+     }
+     args.push_back(*argv);
+   }
+ 
+   if (!output) {
+     std::cerr << "Could not determine output file." << std::endl;
+     return 1;
+   }
+ 
+   if (!crti) {
+-    std::cerr << "Could not find crti.o on the command line." << std::endl;
++    std::cerr << "Could not find CRT object on the command line." << std::endl;
+     return 1;
+   }
+ 
+   if (!real_linker || !real_linker->has_parent_path()) {
+     auto linker = next_program(this_program, real_linker);
+     if (!linker) {
+       std::cerr << "Could not find next "
+                 << (real_linker ? real_linker->filename()
+@@ -410,16 +415,19 @@ int main(int argc, char* argv[]) {
+       break;
+     case EM_AARCH64:
+       stem = "aarch64";
+       break;
+     default:
+       std::cerr << "Unsupported target machine type." << std::endl;
+       return 1;
+   }
++  if (is_android) {
++    stem += "-android";
++  }
+ 
+   if (shared) {
+     std::vector<const char*> hacked_args(args);
+     auto inject = this_program.parent_path() / "inject" / (stem + ".o");
+     hacked_args.insert(hacked_args.begin() + crti + 1, inject.c_str());
+     hacked_args.insert(hacked_args.end() - 1, {"-z", "pack-relative-relocs",
+                                                "-init=_relrhack_wrap_init"});
+     int status = run_command(hacked_args);

+ 30 - 0
mozilla-release/patches/1850867-2-119a1.patch

@@ -0,0 +1,30 @@
+# HG changeset patch
+# User Sandor Molnar <smolnar@mozilla.com>
+# Date 1695099165 -10800
+#      Tue Sep 19 07:52:45 2023 +0300
+# Node ID 6589c0d4d3d3aaed578f6d60cc1831f6cdf79b7c
+# Parent  ffc2489790a98910be70e1caa665019dc409f5d5
+Bug 1850867 - Fix android bustages. a=fix
+
+diff --git a/build/unix/elfhack/inject/moz.build b/build/unix/elfhack/inject/moz.build
+--- a/build/unix/elfhack/inject/moz.build
++++ b/build/unix/elfhack/inject/moz.build
+@@ -6,17 +6,17 @@
+ 
+ # dummy library name to avoid skipping building the source here, which
+ # we only need the object for.
+ Library('elfhack_inject')
+ 
+ DIST_INSTALL = False
+ 
+ stem = CONFIG["CPU_ARCH"]
+-if CONFIG["OS_TARGET"] == "Android":
++if CONFIG["RELRHACK"] and CONFIG["OS_TARGET"] == "Android":
+     stem += "-android"
+ 
+ 
+ gen_src = '%s.c' % stem
+ GeneratedFile(gen_src, script='copy_source.py', entry_point='copy',
+               inputs = ['../inject.c'])
+ 
+ SOURCES += [

+ 71 - 0
mozilla-release/patches/1854052-119a1.patch

@@ -0,0 +1,71 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1695247297 0
+#      Wed Sep 20 22:01:37 2023 +0000
+# Node ID 876f2d3af07270a941216773ce6de49d2e4ae79a
+# Parent  d1815c454a6ac43b615a18ff23cb10ea6712211b
+Bug 1854052 - Don't build elfhack tests when building with relrhack. r=firefox-build-system-reviewers,andi
+
+They are not useful (and the corresponding Makefile doesn't use them
+anyways, so they're built for nothing).
+
+Differential Revision: https://phabricator.services.mozilla.com/D188679
+
+diff --git a/build/unix/elfhack/moz.build b/build/unix/elfhack/moz.build
+--- a/build/unix/elfhack/moz.build
++++ b/build/unix/elfhack/moz.build
+@@ -2,41 +2,43 @@
+ # vim: set filetype=python:
+ # This Source Code Form is subject to the terms of the Mozilla Public
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ 
+ DIST_INSTALL = False
+ DIRS += ['inject']
+ 
+-if not CONFIG['CROSS_COMPILE']:
+-    SOURCES += [
+-        'dummy.c',
+-        'test-array.c',
+-        'test-ctors.c',
+-    ]
+-
+-    SOURCES['dummy.c'].flags += ['-fno-lto']
+-    SOURCES['test-array.c'].flags += ['-fno-lto']
+-    SOURCES['test-ctors.c'].flags += ['-fno-lto']
+-
+ if CONFIG["RELRHACK"]:
+     HOST_SOURCES += [
+         "relrhack.cpp",
+     ]
+ 
+     HostProgram(CONFIG["RELRHACK_LINKER"])
+ 
+     HOST_OS_LIBS += CONFIG["RELRHACK_LIBS"]
+ else:
+     HOST_SOURCES += [
+         "elf.cpp",
+         "elfhack.cpp",
+     ]
+ 
+     HostProgram("elfhack")
+ 
++    if not CONFIG["CROSS_COMPILE"]:
++        SOURCES += [
++            "dummy.c",
++        ]
++        SOURCES["dummy.c"].flags += ["-fno-lto"]
++
++    SOURCES += [
++        "test-array.c",
++        "test-ctors.c",
++    ]
++    SOURCES["test-array.c"].flags += ["-fno-lto"]
++    SOURCES["test-ctors.c"].flags += ["-fno-lto"]
++
+ NO_PGO = True
+ 
+ COMPILE_FLAGS['OS_CXXFLAGS'] = [
+     f for f in COMPILE_FLAGS['OS_CXXFLAGS'] if f != '-fno-exceptions'
+ ] + ['-fexceptions']
+ 

+ 60 - 0
mozilla-release/patches/1854303-119a1.patch

@@ -0,0 +1,60 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1695349434 0
+#      Fri Sep 22 02:23:54 2023 +0000
+# Node ID 7587dfe6e9b5a4bda3d47ed3fc77fba1b8a9a6ed
+# Parent  899675235f7ec82ce716225ce26a6ce50e0f1208
+Bug 1854303 - Apply the PT_DYNAMIC tag changes properly. r=firefox-build-system-reviewers,ahochheiden
+
+They are supposed to be applied unconditionally, not only when there is
+a GLIBC_ABI_DT_RELR version in the libc.
+
+Differential Revision: https://phabricator.services.mozilla.com/D188894
+
+diff --git a/build/unix/elfhack/relrhack.cpp b/build/unix/elfhack/relrhack.cpp
+--- a/build/unix/elfhack/relrhack.cpp
++++ b/build/unix/elfhack/relrhack.cpp
+@@ -175,16 +175,22 @@ bool RelR<bits>::hack(std::fstream& f) {
+   // If the packed relocations + some overhead (we pick 4K arbitrarily, the
+   // real size would require digging into the section sizes of the injected
+   // .o file, which is not worth the error) is larger than the estimated
+   // unpacked relocations, we'll just relink without packed relocations.
+   if (relocs * relent < relrsz + 4096) {
+     return false;
+   }
+ 
++  // Apply the PT_DYNAMIC tag changes we've recorded.
++  for (const auto& [offset, tag] : relr_tags) {
++    f.seekg(offset, std::ios::beg);
++    f.write(reinterpret_cast<const char*>(&tag), sizeof(tag));
++  }
++
+   if (verneednum && verneed_off && strsz && strtab_off) {
+     // Scan SHT_VERNEED for the GLIBC_ABI_DT_RELR version on the libc
+     // library.
+     auto strtab = read_vector_at<char>(f, strtab_off, strsz);
+     // Guarantee a nul character at the end of the string table.
+     strtab.push_back(0);
+     while (verneednum--) {
+       auto verneed = read_one_at<Elf_Verneed>(f, verneed_off);
+@@ -215,20 +221,16 @@ bool RelR<bits>::hack(std::fstream& f) {
+         // ignore tags they don't know, glibc's ld.so versions that support
+         // packed relocations don't want to load a binary that has DT_RELR*
+         // tags but *not* a dependency on the GLIBC_ABI_DT_RELR version.
+         if (relr) {
+           f.seekg(relr, std::ios::beg);
+           // Don't overwrite vn_aux.
+           f.write(reinterpret_cast<char*>(&reuse),
+                   sizeof(reuse) - sizeof(Elf_Word));
+-          for (const auto& [offset, tag] : relr_tags) {
+-            f.seekg(offset, std::ios::beg);
+-            f.write(reinterpret_cast<const char*>(&tag), sizeof(tag));
+-          }
+         }
+       }
+       verneed_off += verneed.vn_next;
+     }
+   }
+   off_t shdr_offset = ehdr.e_shoff + offsetof(Elf_Shdr, sh_type);
+   auto shdr = read_vector_at<Elf_Shdr>(f, ehdr.e_shoff, ehdr.e_shnum);
+   for (const auto& s : shdr) {

+ 35 - 0
mozilla-release/patches/1854497-119a1.patch

@@ -0,0 +1,35 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1695349680 0
+#      Fri Sep 22 02:28:00 2023 +0000
+# Node ID 3f83d676cc21623528360ee851bb6eff32439f07
+# Parent  b87a35a88e67efbea6557613f97ebc9c438197f8
+Bug 1854497 - In elfhack checks, don't look for parens. r=firefox-build-system-reviewers,ahochheiden
+
+Old versions of llvm-readelf didn't have parens in its output for `-d`.
+So instead of looking for parens, look for word boundaries.
+
+Differential Revision: https://phabricator.services.mozilla.com/D188897
+
+diff --git a/build/unix/elfhack/Makefile.in b/build/unix/elfhack/Makefile.in
+--- a/build/unix/elfhack/Makefile.in
++++ b/build/unix/elfhack/Makefile.in
+@@ -10,17 +10,17 @@ test-array$(DLL_SUFFIX) test-ctors$(DLL_
+ 	$(MKSHLIB) $(LDFLAGS) $< -nostartfiles
+ 	@echo ===
+ 	@echo === If you get failures below, please file a bug describing the error
+ 	@echo === and your environment \(compiler and linker versions\), and
+ 	@echo === provide the pre-elfhacked library as an attachment.
+ 	@echo === Use --disable-elf-hack until this is fixed.
+ 	@echo ===
+ 	# Fail if the library doesn't have $(DT_TYPE) .dynamic info
+-	$(TOOLCHAIN_PREFIX)readelf -d $@ | grep '($(DT_TYPE))'
++	$(TOOLCHAIN_PREFIX)readelf -d $@ | grep '\b$(DT_TYPE)\b'
+ 	@rm -f $@.bak
+ 	$(CURDIR)/elfhack -b -f $@
+ 	# Fail if the backup file doesn't exist
+ 	[ -f '$@.bak' ]
+ 	# Fail if the new library doesn't contain less relocations
+ 	[ $$($(TOOLCHAIN_PREFIX)objdump -R $@.bak | wc -l) -gt $$(objdump -R $@ | wc -l) ]
+ 
+ test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX): DSO_SONAME=$@

+ 100 - 0
mozilla-release/patches/1855568-1-120a1.patch

@@ -0,0 +1,100 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1696376690 0
+#      Tue Oct 03 23:44:50 2023 +0000
+# Node ID 871f72b6c738c2dc4d062801e0f56ba17debe4fd
+# Parent  65da50253a19b9adc6a900d4b221bda30156b885
+Bug 1855568 - Refactor writes in relrhack. r=sergesanspaille
+
+In a manner similar to what's done for reads.
+
+Differential Revision: https://phabricator.services.mozilla.com/D189892
+
+diff --git a/build/unix/elfhack/relrhack.cpp b/build/unix/elfhack/relrhack.cpp
+--- a/build/unix/elfhack/relrhack.cpp
++++ b/build/unix/elfhack/relrhack.cpp
+@@ -83,16 +83,26 @@ T read_one_at(std::istream& in, off_t po
+ template <typename T>
+ std::vector<T> read_vector_at(std::istream& in, off_t pos, size_t num) {
+   std::vector<T> result(num);
+   in.seekg(pos, std::ios::beg);
+   in.read(reinterpret_cast<char*>(result.data()), num * sizeof(T));
+   return result;
+ }
+ 
++void write_at(std::ostream& out, off_t pos, const char* buf, size_t len) {
++  out.seekp(pos, std::ios::beg);
++  out.write(buf, len);
++}
++
++template <typename T>
++void write_one_at(std::ostream& out, off_t pos, const T& data) {
++  write_at(out, pos, reinterpret_cast<const char*>(&data), sizeof(T));
++}
++
+ template <int bits>
+ bool RelR<bits>::hack(std::fstream& f) {
+   auto ehdr = read_one_at<Elf_Ehdr>(f, 0);
+   if (ehdr.e_phentsize != sizeof(Elf_Phdr)) {
+     throw std::runtime_error("Invalid ELF?");
+   }
+   auto phdr = read_vector_at<Elf_Phdr>(f, ehdr.e_phoff, ehdr.e_phnum);
+   const auto& dyn_phdr =
+@@ -177,18 +187,17 @@ bool RelR<bits>::hack(std::fstream& f) {
+   // .o file, which is not worth the error) is larger than the estimated
+   // unpacked relocations, we'll just relink without packed relocations.
+   if (relocs * relent < relrsz + 4096) {
+     return false;
+   }
+ 
+   // Apply the PT_DYNAMIC tag changes we've recorded.
+   for (const auto& [offset, tag] : relr_tags) {
+-    f.seekg(offset, std::ios::beg);
+-    f.write(reinterpret_cast<const char*>(&tag), sizeof(tag));
++    write_one_at(f, offset, tag);
+   }
+ 
+   if (verneednum && verneed_off && strsz && strtab_off) {
+     // Scan SHT_VERNEED for the GLIBC_ABI_DT_RELR version on the libc
+     // library.
+     auto strtab = read_vector_at<char>(f, strtab_off, strsz);
+     // Guarantee a nul character at the end of the string table.
+     strtab.push_back(0);
+@@ -217,34 +226,31 @@ bool RelR<bits>::hack(std::fstream& f) {
+         // is there in the first place, to avoid running against older versions
+         // of glibc that don't support packed relocations).
+         // - Alter the DT_RELR* tags in the dynamic section, so that they
+         // are not recognized by ld.so, because, while all versions of ld.so
+         // ignore tags they don't know, glibc's ld.so versions that support
+         // packed relocations don't want to load a binary that has DT_RELR*
+         // tags but *not* a dependency on the GLIBC_ABI_DT_RELR version.
+         if (relr) {
+-          f.seekg(relr, std::ios::beg);
+           // Don't overwrite vn_aux.
+-          f.write(reinterpret_cast<char*>(&reuse),
+-                  sizeof(reuse) - sizeof(Elf_Word));
++          write_at(f, relr, reinterpret_cast<char*>(&reuse),
++                   sizeof(reuse) - sizeof(Elf_Word));
+         }
+       }
+       verneed_off += verneed.vn_next;
+     }
+   }
+   off_t shdr_offset = ehdr.e_shoff + offsetof(Elf_Shdr, sh_type);
+   auto shdr = read_vector_at<Elf_Shdr>(f, ehdr.e_shoff, ehdr.e_shnum);
+   for (const auto& s : shdr) {
+     // Some tools don't like sections of types they don't know, so change
+     // SHT_RELR, which might be unknown on older systems, to SHT_PROGBITS.
+     if (s.sh_type == SHT_RELR) {
+-      Elf_Word progbits = SHT_PROGBITS;
+-      f.seekg(shdr_offset, std::ios::beg);
+-      f.write(reinterpret_cast<const char*>(&progbits), sizeof(progbits));
++      write_one_at(f, shdr_offset, Elf_Word(SHT_PROGBITS));
+     }
+     shdr_offset += sizeof(Elf_Shdr);
+   }
+   return true;
+ }
+ 
+ std::vector<std::string> get_path() {
+   std::vector<std::string> result;

+ 214 - 0
mozilla-release/patches/1855568-2-120a1.patch

@@ -0,0 +1,214 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1696376690 0
+#      Tue Oct 03 23:44:50 2023 +0000
+# Node ID b99fc81764f7fec9578f98080bb4466e4f0f872b
+# Parent  871f72b6c738c2dc4d062801e0f56ba17debe4fd
+Bug 1855568 - Refactor how the PT_DYNAMIC info is collected. r=sergesanspaille
+
+We're soon going to collect a little more, and the current way of doing
+so is not super convenient.
+
+Differential Revision: https://phabricator.services.mozilla.com/D189893
+
+diff --git a/build/unix/elfhack/relrhack.cpp b/build/unix/elfhack/relrhack.cpp
+--- a/build/unix/elfhack/relrhack.cpp
++++ b/build/unix/elfhack/relrhack.cpp
+@@ -16,16 +16,18 @@
+ #include <filesystem>
+ #include <fstream>
+ #include <iostream>
+ #include <optional>
+ #include <spawn.h>
+ #include <sstream>
+ #include <sys/wait.h>
+ #include <unistd.h>
++#include <unordered_map>
++#include <utility>
+ #include <vector>
+ 
+ namespace fs = std::filesystem;
+ 
+ template <int bits>
+ struct Elf {};
+ 
+ #define ELF(bits)                        \
+@@ -52,16 +54,48 @@ struct RelR : public Elf<bits> {
+   using Elf_Shdr = typename Elf<bits>::Shdr;
+   using Elf_Dyn = typename Elf<bits>::Dyn;
+   using Elf_Addr = typename Elf<bits>::Addr;
+   using Elf_Word = typename Elf<bits>::Word;
+   using Elf_Off = typename Elf<bits>::Off;
+   using Elf_Verneed = typename Elf<bits>::Verneed;
+   using Elf_Vernaux = typename Elf<bits>::Vernaux;
+ 
++#define TAG_NAME(t) \
++  { t, #t }
++  class DynInfo {
++   public:
++    using Tag = decltype(Elf_Dyn::d_tag);
++    using Value = decltype(Elf_Dyn::d_un.d_val);
++    bool is_wanted(Tag tag) const { return tag_names.count(tag); }
++    void insert(off_t offset, Tag tag, Value val) {
++      data[tag] = std::make_pair(offset, val);
++    }
++    off_t offset(Tag tag) const { return data.at(tag).first; }
++    bool contains(Tag tag) const { return data.count(tag); }
++    Value& operator[](Tag tag) {
++      if (!is_wanted(tag)) {
++        std::stringstream msg;
++        msg << "Tag 0x" << std::hex << tag << " is not in DynInfo::tag_names";
++        throw std::runtime_error(msg.str());
++      }
++      return data[tag].second;
++    }
++    const char* name(Tag tag) const { return tag_names.at(tag); }
++
++   private:
++    std::unordered_map<Tag, std::pair<off_t, Value>> data;
++
++    const std::unordered_map<Tag, const char*> tag_names = {
++        TAG_NAME(DT_RELR),    TAG_NAME(DT_RELRENT), TAG_NAME(DT_RELRSZ),
++        TAG_NAME(DT_RELAENT), TAG_NAME(DT_RELENT),  TAG_NAME(DT_STRTAB),
++        TAG_NAME(DT_STRSZ),   TAG_NAME(DT_VERNEED), TAG_NAME(DT_VERNEEDNUM),
++    };
++  };
++
+   // Translate a virtual address into an offset in the file based on the program
+   // headers' PT_LOAD.
+   static Elf_Addr get_offset(const std::vector<Elf_Phdr>& phdr, Elf_Addr addr) {
+     for (const auto& p : phdr) {
+       if (p.p_type == PT_LOAD && addr >= p.p_vaddr &&
+           addr < p.p_vaddr + p.p_filesz) {
+         return addr - (p.p_vaddr - p.p_paddr);
+       }
+@@ -109,70 +143,49 @@ bool RelR<bits>::hack(std::fstream& f) {
+       std::find_if(phdr.begin(), phdr.end(),
+                    [](const auto& p) { return p.p_type == PT_DYNAMIC; });
+   if (dyn_phdr == phdr.end()) {
+     return false;
+   }
+   if (dyn_phdr->p_filesz % sizeof(Elf_Dyn)) {
+     throw std::runtime_error("Invalid ELF?");
+   }
+-  // Find the location and size of several sections from the .dynamic section
+-  // contents:
+-  // - SHT_RELR section, which contains the packed-relative-relocs.
+-  // - SHT_VERNEED section, which contains the symbol versions needed.
+-  // - SHT_STRTAB section, which contains the string table for, among other
+-  // things, those symbol versions.
+-  // At the same time, we also change DT_RELR* tags to add DT_RELRHACK_BIT.
+   auto dyn = read_vector_at<Elf_Dyn>(f, dyn_phdr->p_offset,
+                                      dyn_phdr->p_filesz / sizeof(Elf_Dyn));
+   off_t dyn_offset = dyn_phdr->p_offset;
+-  Elf_Addr strtab_off = 0, verneed_off = 0, relr_off = 0;
+-  Elf_Off strsz = 0, verneednum = 0, relrsz = 0, relent = 0;
+-  std::vector<std::pair<off_t, Elf_Off>> relr_tags;
++  DynInfo dyn_info;
+   for (const auto& d : dyn) {
+     if (d.d_tag == DT_NULL) {
+       break;
+     }
+-    switch (d.d_tag) {
+-      case DT_RELR:
+-      case DT_RELRENT:
+-      case DT_RELRSZ:
+-        if (d.d_tag == DT_RELR) {
+-          if (relr_off) {
+-            throw std::runtime_error("DT_RELR appears twice?");
+-          }
+-          relr_off = get_offset(phdr, d.d_un.d_ptr);
+-        } else if (d.d_tag == DT_RELRSZ) {
+-          if (relrsz) {
+-            throw std::runtime_error("DT_RELRSZ appears twice?");
+-          }
+-          relrsz = d.d_un.d_val;
+-        }
+-        relr_tags.push_back({dyn_offset, d.d_tag | DT_RELRHACK_BIT});
+-        break;
+-      case DT_RELAENT:
+-      case DT_RELENT:
+-        relent = d.d_un.d_val;
+-        break;
+-      case DT_STRTAB:
+-        strtab_off = get_offset(phdr, d.d_un.d_ptr);
+-        break;
+-      case DT_STRSZ:
+-        strsz = d.d_un.d_val;
+-        break;
+-      case DT_VERNEED:
+-        verneed_off = get_offset(phdr, d.d_un.d_ptr);
+-        break;
+-      case DT_VERNEEDNUM:
+-        verneednum = d.d_un.d_val;
+-        break;
++
++    if (dyn_info.is_wanted(d.d_tag)) {
++      if (dyn_info.contains(d.d_tag)) {
++        std::stringstream msg;
++        msg << dyn_info.name(d.d_tag) << " appears twice?";
++        throw std::runtime_error(msg.str());
++      }
++      dyn_info.insert(dyn_offset, d.d_tag, d.d_un.d_val);
+     }
+     dyn_offset += sizeof(Elf_Dyn);
+   }
+ 
++  // Find the location and size of the SHT_RELR section, which contains the
++  // packed-relative-relocs.
++  Elf_Addr relr_off =
++      dyn_info.contains(DT_RELR) ? get_offset(phdr, dyn_info[DT_RELR]) : 0;
++  Elf_Off relrsz = dyn_info[DT_RELRSZ];
++  if (dyn_info.contains(DT_RELENT) && dyn_info.contains(DT_RELAENT)) {
++    std::stringstream msg;
++    msg << "Both DT_RELENT and DT_RELAENT appear?";
++    throw std::runtime_error(msg.str());
++  }
++  Elf_Off relent =
++      dyn_info.contains(DT_RELENT) ? dyn_info[DT_RELENT] : dyn_info[DT_RELAENT];
++
+   // Estimate the size of the unpacked relative relocations corresponding
+   // to the SHT_RELR section.
+   auto relr = read_vector_at<Elf_Addr>(f, relr_off, relrsz / sizeof(Elf_Addr));
+   size_t relocs = 0;
+   for (const auto& entry : relr) {
+     if ((entry & 1) == 0) {
+       // LSB is 0, this is a pointer for a single relocation.
+       relocs++;
+@@ -185,25 +198,31 @@ bool RelR<bits>::hack(std::fstream& f) {
+   // If the packed relocations + some overhead (we pick 4K arbitrarily, the
+   // real size would require digging into the section sizes of the injected
+   // .o file, which is not worth the error) is larger than the estimated
+   // unpacked relocations, we'll just relink without packed relocations.
+   if (relocs * relent < relrsz + 4096) {
+     return false;
+   }
+ 
+-  // Apply the PT_DYNAMIC tag changes we've recorded.
+-  for (const auto& [offset, tag] : relr_tags) {
+-    write_one_at(f, offset, tag);
++  // Change DT_RELR* tags to add DT_RELRHACK_BIT.
++  for (const auto tag : {DT_RELR, DT_RELRSZ, DT_RELRENT}) {
++    write_one_at(f, dyn_info.offset(tag), tag | DT_RELRHACK_BIT);
+   }
+ 
+-  if (verneednum && verneed_off && strsz && strtab_off) {
++  if (dyn_info.contains(DT_VERNEEDNUM) && dyn_info.contains(DT_VERNEED) &&
++      dyn_info.contains(DT_STRSZ) && dyn_info.contains(DT_STRTAB)) {
+     // Scan SHT_VERNEED for the GLIBC_ABI_DT_RELR version on the libc
+     // library.
+-    auto strtab = read_vector_at<char>(f, strtab_off, strsz);
++    Elf_Addr verneed_off = get_offset(phdr, dyn_info[DT_VERNEED]);
++    Elf_Off verneednum = dyn_info[DT_VERNEEDNUM];
++    // SHT_STRTAB section, which contains the string table for, among other
++    // things, the symbol versions in the SHT_VERNEED section.
++    auto strtab = read_vector_at<char>(f, get_offset(phdr, dyn_info[DT_STRTAB]),
++                                       dyn_info[DT_STRSZ]);
+     // Guarantee a nul character at the end of the string table.
+     strtab.push_back(0);
+     while (verneednum--) {
+       auto verneed = read_one_at<Elf_Verneed>(f, verneed_off);
+       if (std::string_view{"libc.so.6"} == &strtab.at(verneed.vn_file)) {
+         Elf_Addr vernaux_off = verneed_off + verneed.vn_aux;
+         Elf_Addr relr = 0;
+         Elf_Vernaux reuse;

+ 181 - 0
mozilla-release/patches/1855568-3-120a1.patch

@@ -0,0 +1,181 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1696376691 0
+#      Tue Oct 03 23:44:51 2023 +0000
+# Node ID d8a68b5a66872ef580ebe24332f59378cb0f825c
+# Parent  b99fc81764f7fec9578f98080bb4466e4f0f872b
+Bug 1855568 - Ensure that .relr.plt follows and is adjacent to .rel.dyn. r=sergesanspaille
+
+Differential Revision: https://phabricator.services.mozilla.com/D189894
+
+diff --git a/build/unix/elfhack/relrhack.cpp b/build/unix/elfhack/relrhack.cpp
+--- a/build/unix/elfhack/relrhack.cpp
++++ b/build/unix/elfhack/relrhack.cpp
+@@ -80,19 +80,21 @@ struct RelR : public Elf<bits> {
+       return data[tag].second;
+     }
+     const char* name(Tag tag) const { return tag_names.at(tag); }
+ 
+    private:
+     std::unordered_map<Tag, std::pair<off_t, Value>> data;
+ 
+     const std::unordered_map<Tag, const char*> tag_names = {
+-        TAG_NAME(DT_RELR),    TAG_NAME(DT_RELRENT), TAG_NAME(DT_RELRSZ),
+-        TAG_NAME(DT_RELAENT), TAG_NAME(DT_RELENT),  TAG_NAME(DT_STRTAB),
+-        TAG_NAME(DT_STRSZ),   TAG_NAME(DT_VERNEED), TAG_NAME(DT_VERNEEDNUM),
++        TAG_NAME(DT_JMPREL),  TAG_NAME(DT_PLTRELSZ), TAG_NAME(DT_RELR),
++        TAG_NAME(DT_RELRENT), TAG_NAME(DT_RELRSZ),   TAG_NAME(DT_RELA),
++        TAG_NAME(DT_RELASZ),  TAG_NAME(DT_RELAENT),  TAG_NAME(DT_REL),
++        TAG_NAME(DT_RELSZ),   TAG_NAME(DT_RELENT),   TAG_NAME(DT_STRTAB),
++        TAG_NAME(DT_STRSZ),   TAG_NAME(DT_VERNEED),  TAG_NAME(DT_VERNEEDNUM),
+     };
+   };
+ 
+   // Translate a virtual address into an offset in the file based on the program
+   // headers' PT_LOAD.
+   static Elf_Addr get_offset(const std::vector<Elf_Phdr>& phdr, Elf_Addr addr) {
+     for (const auto& p : phdr) {
+       if (p.p_type == PT_LOAD && addr >= p.p_vaddr &&
+@@ -127,16 +129,22 @@ void write_at(std::ostream& out, off_t p
+   out.write(buf, len);
+ }
+ 
+ template <typename T>
+ void write_one_at(std::ostream& out, off_t pos, const T& data) {
+   write_at(out, pos, reinterpret_cast<const char*>(&data), sizeof(T));
+ }
+ 
++template <typename T>
++void write_vector_at(std::ostream& out, off_t pos, const std::vector<T>& vec) {
++  write_at(out, pos, reinterpret_cast<const char*>(&vec.front()),
++           vec.size() * sizeof(T));
++}
++
+ template <int bits>
+ bool RelR<bits>::hack(std::fstream& f) {
+   auto ehdr = read_one_at<Elf_Ehdr>(f, 0);
+   if (ehdr.e_phentsize != sizeof(Elf_Phdr)) {
+     throw std::runtime_error("Invalid ELF?");
+   }
+   auto phdr = read_vector_at<Elf_Phdr>(f, ehdr.e_phoff, ehdr.e_phnum);
+   const auto& dyn_phdr =
+@@ -168,20 +176,25 @@ bool RelR<bits>::hack(std::fstream& f) {
+     dyn_offset += sizeof(Elf_Dyn);
+   }
+ 
+   // Find the location and size of the SHT_RELR section, which contains the
+   // packed-relative-relocs.
+   Elf_Addr relr_off =
+       dyn_info.contains(DT_RELR) ? get_offset(phdr, dyn_info[DT_RELR]) : 0;
+   Elf_Off relrsz = dyn_info[DT_RELRSZ];
+-  if (dyn_info.contains(DT_RELENT) && dyn_info.contains(DT_RELAENT)) {
+-    std::stringstream msg;
+-    msg << "Both DT_RELENT and DT_RELAENT appear?";
+-    throw std::runtime_error(msg.str());
++  const decltype(Elf_Dyn::d_tag) rel_tags[3][2] = {
++      {DT_REL, DT_RELA}, {DT_RELSZ, DT_RELASZ}, {DT_RELENT, DT_RELAENT}};
++  for (const auto& [rel_tag, rela_tag] : rel_tags) {
++    if (dyn_info.contains(rel_tag) && dyn_info.contains(rela_tag)) {
++      std::stringstream msg;
++      msg << "Both " << dyn_info.name(rel_tag) << " and "
++          << dyn_info.name(rela_tag) << " appear?";
++      throw std::runtime_error(msg.str());
++    }
+   }
+   Elf_Off relent =
+       dyn_info.contains(DT_RELENT) ? dyn_info[DT_RELENT] : dyn_info[DT_RELAENT];
+ 
+   // Estimate the size of the unpacked relative relocations corresponding
+   // to the SHT_RELR section.
+   auto relr = read_vector_at<Elf_Addr>(f, relr_off, relrsz / sizeof(Elf_Addr));
+   size_t relocs = 0;
+@@ -203,16 +216,48 @@ bool RelR<bits>::hack(std::fstream& f) {
+     return false;
+   }
+ 
+   // Change DT_RELR* tags to add DT_RELRHACK_BIT.
+   for (const auto tag : {DT_RELR, DT_RELRSZ, DT_RELRENT}) {
+     write_one_at(f, dyn_info.offset(tag), tag | DT_RELRHACK_BIT);
+   }
+ 
++  // ld.so in glibc 2.16 to 2.23 expects .rel.plt to strictly follow .rel.dyn.
++  // (https://sourceware.org/bugzilla/show_bug.cgi?id=14341)
++  // BFD ld places .relr.dyn after .rel.plt, so this works fine, but lld places
++  // it between both sections, which doesn't work out for us. In that case, we
++  // want to swap .relr.dyn and .rel.plt.
++  Elf_Addr rel_end = dyn_info.contains(DT_REL)
++                         ? (dyn_info[DT_REL] + dyn_info[DT_RELSZ])
++                         : (dyn_info[DT_RELA] + dyn_info[DT_RELASZ]);
++  // Location of the .rel.plt section.
++  Elf_Addr jmprel = dyn_info.contains(DT_JMPREL) ? dyn_info[DT_JMPREL] : 0;
++  if (dyn_info.contains(DT_JMPREL) && dyn_info[DT_PLTRELSZ] &&
++      dyn_info[DT_JMPREL] != rel_end) {
++    if (dyn_info[DT_RELR] != rel_end) {
++      throw std::runtime_error("RELR section doesn't follow REL/RELA?");
++    }
++    if (dyn_info[DT_JMPREL] != dyn_info[DT_RELR] + dyn_info[DT_RELRSZ]) {
++      throw std::runtime_error("PLT REL/RELA doesn't follow RELR?");
++    }
++    auto plt_rel = read_vector_at<char>(
++        f, get_offset(phdr, dyn_info[DT_JMPREL]), dyn_info[DT_PLTRELSZ]);
++    // Write the content of both sections swapped, and adjust the
++    // corresponding PT_DYNAMIC entries.
++    write_vector_at(f, relr_off, plt_rel);
++    write_vector_at(f, relr_off + plt_rel.size(), relr);
++    dyn_info[DT_JMPREL] = rel_end;
++    dyn_info[DT_RELR] = rel_end + plt_rel.size();
++    for (const auto tag : {DT_JMPREL, DT_RELR}) {
++      write_one_at(f, dyn_info.offset(tag) + sizeof(typename DynInfo::Tag),
++                   dyn_info[tag]);
++    }
++  }
++
+   if (dyn_info.contains(DT_VERNEEDNUM) && dyn_info.contains(DT_VERNEED) &&
+       dyn_info.contains(DT_STRSZ) && dyn_info.contains(DT_STRTAB)) {
+     // Scan SHT_VERNEED for the GLIBC_ABI_DT_RELR version on the libc
+     // library.
+     Elf_Addr verneed_off = get_offset(phdr, dyn_info[DT_VERNEED]);
+     Elf_Off verneednum = dyn_info[DT_VERNEEDNUM];
+     // SHT_STRTAB section, which contains the string table for, among other
+     // things, the symbol versions in the SHT_VERNEED section.
+@@ -253,23 +298,37 @@ bool RelR<bits>::hack(std::fstream& f) {
+           // Don't overwrite vn_aux.
+           write_at(f, relr, reinterpret_cast<char*>(&reuse),
+                    sizeof(reuse) - sizeof(Elf_Word));
+         }
+       }
+       verneed_off += verneed.vn_next;
+     }
+   }
+-  off_t shdr_offset = ehdr.e_shoff + offsetof(Elf_Shdr, sh_type);
++  off_t shdr_offset = ehdr.e_shoff;
+   auto shdr = read_vector_at<Elf_Shdr>(f, ehdr.e_shoff, ehdr.e_shnum);
+-  for (const auto& s : shdr) {
++  for (auto& s : shdr) {
+     // Some tools don't like sections of types they don't know, so change
+     // SHT_RELR, which might be unknown on older systems, to SHT_PROGBITS.
+     if (s.sh_type == SHT_RELR) {
+-      write_one_at(f, shdr_offset, Elf_Word(SHT_PROGBITS));
++      s.sh_type = SHT_PROGBITS;
++      // If DT_RELR has been adjusted to swap with DT_JMPREL, also adjust
++      // the corresponding SHT_RELR section header.
++      if (s.sh_addr != dyn_info[DT_RELR]) {
++        s.sh_offset += dyn_info[DT_RELR] - s.sh_addr;
++        s.sh_addr = dyn_info[DT_RELR];
++      }
++      write_one_at(f, shdr_offset, s);
++    }
++    // If DT_JMPREL has been adjusted to swap with DT_RELR, also adjust
++    // the corresponding section header.
++    if (jmprel && (s.sh_addr == jmprel) && (s.sh_addr != dyn_info[DT_JMPREL])) {
++      s.sh_offset -= s.sh_addr - dyn_info[DT_JMPREL];
++      s.sh_addr = dyn_info[DT_JMPREL];
++      write_one_at(f, shdr_offset, s);
+     }
+     shdr_offset += sizeof(Elf_Shdr);
+   }
+   return true;
+ }
+ 
+ std::vector<std::string> get_path() {
+   std::vector<std::string> result;

+ 31 - 0
mozilla-release/patches/1855955-PARTIAL-elfhack-120a1.patch

@@ -0,0 +1,31 @@
+# HG changeset patch
+# User serge-sans-paille <sguelton@mozilla.com>
+# Date 1695996953 0
+#      Fri Sep 29 14:15:53 2023 +0000
+# Node ID ec65ca2f7db18fefc250aca74197ba901e6a0a8c
+# Parent  a120317e670ae06f583fd6bd0a0de57ed19ad01d
+Bug 1855955 - Remove useless <iostream> includes r=emilio
+
+Differential Revision: https://phabricator.services.mozilla.com/D189648
+
+diff --git a/build/unix/elfhack/elfxx.h b/build/unix/elfhack/elfxx.h
+--- a/build/unix/elfhack/elfxx.h
++++ b/build/unix/elfhack/elfxx.h
+@@ -1,17 +1,16 @@
+ /* This Source Code Form is subject to the terms of the Mozilla Public
+  * License, v. 2.0. If a copy of the MPL was not distributed with this
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include <stdexcept>
+ #include <list>
+ #include <vector>
+ #include <cstring>
+-#include <iostream>
+ #include <fstream>
+ #include <algorithm>
+ #include <elf.h>
+ #include <asm/byteorder.h>
+ 
+ // Technically, __*_to_cpu and __cpu_to* function are equivalent,
+ // so swap can use either of both.
+ #define def_swap(endian, type, bits)                    \

+ 205 - 0
mozilla-release/patches/1856752-120a1.patch

@@ -0,0 +1,205 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1696495244 0
+#      Thu Oct 05 08:40:44 2023 +0000
+# Node ID 352fa7471fb72db127fc25a7723d201abec7bd50
+# Parent  526604ee2cd434fcf94020c1c8b6b96d253a6e83
+Bug 1856752 - Allow more leniency wrt swapping .relr.dyn and .rel.plt sections. r=sergesanspaille
+
+On ARM, lld places the .ARM.exidx section between .rel.dyn/.relr.dyn and
+.rel.plt. This means we can't swap .relr.dyn and .rel.plt (well, we
+could, if we also moved and rewrote the .ARM.exidx section, but that's
+more work than we ought to do).
+But we only need to swap the sections when we want the binary to be
+compatible with older versions of glibc, which we don't care about on
+desktop ARM Linux (we don't ship such builds), and don't need at all
+on ARM Android. Ultimately, this is a bug in lld
+(https://github.com/llvm/llvm-project/issues/68178).
+
+Differential Revision: https://phabricator.services.mozilla.com/D190006
+
+diff --git a/build/unix/elfhack/moz.build b/build/unix/elfhack/moz.build
+--- a/build/unix/elfhack/moz.build
++++ b/build/unix/elfhack/moz.build
+@@ -10,16 +10,19 @@ DIRS += ["inject"]
+ if CONFIG["RELRHACK"]:
+     HOST_SOURCES += [
+         "relrhack.cpp",
+     ]
+ 
+     HostProgram(CONFIG["RELRHACK_LINKER"])
+ 
+     HOST_OS_LIBS += CONFIG["RELRHACK_LIBS"]
++
++    if CONFIG["MOZ_STDCXX_COMPAT"]:
++        HOST_DEFINES["MOZ_STDCXX_COMPAT"] = True
+ else:
+     HOST_SOURCES += [
+         "elf.cpp",
+         "elfhack.cpp",
+     ]
+ 
+     HostProgram("elfhack")
+ 
+diff --git a/build/unix/elfhack/relrhack.cpp b/build/unix/elfhack/relrhack.cpp
+--- a/build/unix/elfhack/relrhack.cpp
++++ b/build/unix/elfhack/relrhack.cpp
+@@ -14,24 +14,30 @@
+ #include <algorithm>
+ #include <cstring>
+ #include <filesystem>
+ #include <fstream>
+ #include <iostream>
+ #include <optional>
+ #include <spawn.h>
+ #include <sstream>
++#include <stdexcept>
+ #include <sys/wait.h>
+ #include <unistd.h>
+ #include <unordered_map>
+ #include <utility>
+ #include <vector>
+ 
+ namespace fs = std::filesystem;
+ 
++class CantSwapSections : public std::runtime_error {
++ public:
++  CantSwapSections(const char* what) : std::runtime_error(what) {}
++};
++
+ template <int bits>
+ struct Elf {};
+ 
+ #define ELF(bits)                        \
+   template <>                            \
+   struct Elf<bits> {                     \
+     using Ehdr = Elf##bits##_Ehdr;       \
+     using Phdr = Elf##bits##_Phdr;       \
+@@ -216,63 +222,34 @@ bool RelR<bits>::hack(std::fstream& f) {
+     return false;
+   }
+ 
+   // Change DT_RELR* tags to add DT_RELRHACK_BIT.
+   for (const auto tag : {DT_RELR, DT_RELRSZ, DT_RELRENT}) {
+     write_one_at(f, dyn_info.offset(tag), tag | DT_RELRHACK_BIT);
+   }
+ 
+-  // ld.so in glibc 2.16 to 2.23 expects .rel.plt to strictly follow .rel.dyn.
+-  // (https://sourceware.org/bugzilla/show_bug.cgi?id=14341)
+-  // BFD ld places .relr.dyn after .rel.plt, so this works fine, but lld places
+-  // it between both sections, which doesn't work out for us. In that case, we
+-  // want to swap .relr.dyn and .rel.plt.
+-  Elf_Addr rel_end = dyn_info.contains(DT_REL)
+-                         ? (dyn_info[DT_REL] + dyn_info[DT_RELSZ])
+-                         : (dyn_info[DT_RELA] + dyn_info[DT_RELASZ]);
+-  // Location of the .rel.plt section.
+-  Elf_Addr jmprel = dyn_info.contains(DT_JMPREL) ? dyn_info[DT_JMPREL] : 0;
+-  if (dyn_info.contains(DT_JMPREL) && dyn_info[DT_PLTRELSZ] &&
+-      dyn_info[DT_JMPREL] != rel_end) {
+-    if (dyn_info[DT_RELR] != rel_end) {
+-      throw std::runtime_error("RELR section doesn't follow REL/RELA?");
+-    }
+-    if (dyn_info[DT_JMPREL] != dyn_info[DT_RELR] + dyn_info[DT_RELRSZ]) {
+-      throw std::runtime_error("PLT REL/RELA doesn't follow RELR?");
+-    }
+-    auto plt_rel = read_vector_at<char>(
+-        f, get_offset(phdr, dyn_info[DT_JMPREL]), dyn_info[DT_PLTRELSZ]);
+-    // Write the content of both sections swapped, and adjust the
+-    // corresponding PT_DYNAMIC entries.
+-    write_vector_at(f, relr_off, plt_rel);
+-    write_vector_at(f, relr_off + plt_rel.size(), relr);
+-    dyn_info[DT_JMPREL] = rel_end;
+-    dyn_info[DT_RELR] = rel_end + plt_rel.size();
+-    for (const auto tag : {DT_JMPREL, DT_RELR}) {
+-      write_one_at(f, dyn_info.offset(tag) + sizeof(typename DynInfo::Tag),
+-                   dyn_info[tag]);
+-    }
+-  }
++  bool is_glibc = false;
+ 
+   if (dyn_info.contains(DT_VERNEEDNUM) && dyn_info.contains(DT_VERNEED) &&
+       dyn_info.contains(DT_STRSZ) && dyn_info.contains(DT_STRTAB)) {
+     // Scan SHT_VERNEED for the GLIBC_ABI_DT_RELR version on the libc
+     // library.
+     Elf_Addr verneed_off = get_offset(phdr, dyn_info[DT_VERNEED]);
+     Elf_Off verneednum = dyn_info[DT_VERNEEDNUM];
+     // SHT_STRTAB section, which contains the string table for, among other
+     // things, the symbol versions in the SHT_VERNEED section.
+     auto strtab = read_vector_at<char>(f, get_offset(phdr, dyn_info[DT_STRTAB]),
+                                        dyn_info[DT_STRSZ]);
+     // Guarantee a nul character at the end of the string table.
+     strtab.push_back(0);
+     while (verneednum--) {
+       auto verneed = read_one_at<Elf_Verneed>(f, verneed_off);
+       if (std::string_view{"libc.so.6"} == &strtab.at(verneed.vn_file)) {
++        is_glibc = true;
+         Elf_Addr vernaux_off = verneed_off + verneed.vn_aux;
+         Elf_Addr relr = 0;
+         Elf_Vernaux reuse;
+         for (auto n = 0; n < verneed.vn_cnt; n++) {
+           auto vernaux = read_one_at<Elf_Vernaux>(f, vernaux_off);
+           if (std::string_view{"GLIBC_ABI_DT_RELR"} ==
+               &strtab.at(vernaux.vna_name)) {
+             relr = vernaux_off;
+@@ -298,16 +275,61 @@ bool RelR<bits>::hack(std::fstream& f) {
+           // Don't overwrite vn_aux.
+           write_at(f, relr, reinterpret_cast<char*>(&reuse),
+                    sizeof(reuse) - sizeof(Elf_Word));
+         }
+       }
+       verneed_off += verneed.vn_next;
+     }
+   }
++
++  // Location of the .rel.plt section.
++  Elf_Addr jmprel = dyn_info.contains(DT_JMPREL) ? dyn_info[DT_JMPREL] : 0;
++  if (is_glibc) {
++#ifndef MOZ_STDCXX_COMPAT
++    try {
++#endif
++      // ld.so in glibc 2.16 to 2.23 expects .rel.plt to strictly follow
++      // .rel.dyn. (https://sourceware.org/bugzilla/show_bug.cgi?id=14341)
++      // BFD ld places .relr.dyn after .rel.plt, so this works fine, but lld
++      // places it between both sections, which doesn't work out for us. In that
++      // case, we want to swap .relr.dyn and .rel.plt.
++      Elf_Addr rel_end = dyn_info.contains(DT_REL)
++                             ? (dyn_info[DT_REL] + dyn_info[DT_RELSZ])
++                             : (dyn_info[DT_RELA] + dyn_info[DT_RELASZ]);
++      if (dyn_info.contains(DT_JMPREL) && dyn_info[DT_PLTRELSZ] &&
++          dyn_info[DT_JMPREL] != rel_end) {
++        if (dyn_info[DT_RELR] != rel_end) {
++          throw CantSwapSections("RELR section doesn't follow REL/RELA?");
++        }
++        if (dyn_info[DT_JMPREL] != dyn_info[DT_RELR] + dyn_info[DT_RELRSZ]) {
++          throw CantSwapSections("PLT REL/RELA doesn't follow RELR?");
++        }
++        auto plt_rel = read_vector_at<char>(
++            f, get_offset(phdr, dyn_info[DT_JMPREL]), dyn_info[DT_PLTRELSZ]);
++        // Write the content of both sections swapped, and adjust the
++        // corresponding PT_DYNAMIC entries.
++        write_vector_at(f, relr_off, plt_rel);
++        write_vector_at(f, relr_off + plt_rel.size(), relr);
++        dyn_info[DT_JMPREL] = rel_end;
++        dyn_info[DT_RELR] = rel_end + plt_rel.size();
++        for (const auto tag : {DT_JMPREL, DT_RELR}) {
++          write_one_at(f, dyn_info.offset(tag) + sizeof(typename DynInfo::Tag),
++                       dyn_info[tag]);
++        }
++      }
++#ifndef MOZ_STDCXX_COMPAT
++    } catch (const CantSwapSections& err) {
++      // When binary compatibility with older libstdc++/glibc is not enabled, we
++      // only emit a warning about why swapping the sections is not happening.
++      std::cerr << "WARNING: " << err.what() << std::endl;
++    }
++#endif
++  }
++
+   off_t shdr_offset = ehdr.e_shoff;
+   auto shdr = read_vector_at<Elf_Shdr>(f, ehdr.e_shoff, ehdr.e_shnum);
+   for (auto& s : shdr) {
+     // Some tools don't like sections of types they don't know, so change
+     // SHT_RELR, which might be unknown on older systems, to SHT_PROGBITS.
+     if (s.sh_type == SHT_RELR) {
+       s.sh_type = SHT_PROGBITS;
+       // If DT_RELR has been adjusted to swap with DT_JMPREL, also adjust

+ 37 - 0
mozilla-release/patches/1863441-121a1.patch

@@ -0,0 +1,37 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1699488085 0
+#      Thu Nov 09 00:01:25 2023 +0000
+# Node ID fd3f50f4dce00592f4da8f972037ced4a0c9f5be
+# Parent  f4b0aa910d47ce7605752c8e9553cbb8390efbde
+Bug 1863441 - Don't filter out flags for debug info when building relrhack injected code. r=firefox-build-system-reviewers,sergesanspaille
+
+When the injected code is used by elfhack, the debug info is thrown away
+because elfhack doesn't know what to do with it, but in the case of
+relrhack, the normal linker can handle it, so there's no reason not to
+include the debug info anymore.
+
+Differential Revision: https://phabricator.services.mozilla.com/D192904
+
+diff --git a/build/unix/elfhack/inject/moz.build b/build/unix/elfhack/inject/moz.build
+--- a/build/unix/elfhack/inject/moz.build
++++ b/build/unix/elfhack/inject/moz.build
+@@ -31,17 +31,17 @@ NO_PGO = True
+ 
+ for v in ('OS_CPPFLAGS', 'OS_CFLAGS', 'DEBUG', 'CLANG_PLUGIN', 'OPTIMIZE',
+           'FRAMEPTR'):
+     flags = []
+     idx = 0
+     for flag in COMPILE_FLAGS[v]:
+         if flag == '-isystem':
+             flags.append(''.join(COMPILE_FLAGS[v][idx:idx + 2]))
+-        elif flag.startswith(('-m', '-I', '-isystem')):
++        elif flag.startswith(('-g', '-m', '-I', '-isystem')):
+             flags.append(flag)
+         idx += 1
+     COMPILE_FLAGS[v] = flags
+ 
+ COMPILE_FLAGS["OS_CFLAGS"] += [
+     "-O2",
+     "-fno-stack-protector",
+     "-fno-lto",

+ 42 - 0
mozilla-release/patches/1863485-121a1.patch

@@ -0,0 +1,42 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1699474393 0
+#      Wed Nov 08 20:13:13 2023 +0000
+# Node ID 88937c2f2b6c63107456cc24bb79c2ee2b212428
+# Parent  c8561b4726a263fc879ac016f59f2f26d831a55d
+Bug 1863485 - Properly update section headers when swapping .rel.plt and .relr.dyn of the same size. r=firefox-build-system-reviewers,sergesanspaille
+
+When .rel.plt and .relr.dyn are the same size, after the section header
+for .relr.dyn has been updated, it matches the condition for .rel.plt,
+and we ended up undoing the change.
+
+Differential Revision: https://phabricator.services.mozilla.com/D192981
+
+diff --git a/build/unix/elfhack/relrhack.cpp b/build/unix/elfhack/relrhack.cpp
+--- a/build/unix/elfhack/relrhack.cpp
++++ b/build/unix/elfhack/relrhack.cpp
+@@ -334,20 +334,20 @@ bool RelR<bits>::hack(std::fstream& f) {
+       s.sh_type = SHT_PROGBITS;
+       // If DT_RELR has been adjusted to swap with DT_JMPREL, also adjust
+       // the corresponding SHT_RELR section header.
+       if (s.sh_addr != dyn_info[DT_RELR]) {
+         s.sh_offset += dyn_info[DT_RELR] - s.sh_addr;
+         s.sh_addr = dyn_info[DT_RELR];
+       }
+       write_one_at(f, shdr_offset, s);
+-    }
+-    // If DT_JMPREL has been adjusted to swap with DT_RELR, also adjust
+-    // the corresponding section header.
+-    if (jmprel && (s.sh_addr == jmprel) && (s.sh_addr != dyn_info[DT_JMPREL])) {
++    } else if (jmprel && (s.sh_addr == jmprel) &&
++               (s.sh_addr != dyn_info[DT_JMPREL])) {
++      // If DT_JMPREL has been adjusted to swap with DT_RELR, also adjust
++      // the corresponding section header.
+       s.sh_offset -= s.sh_addr - dyn_info[DT_JMPREL];
+       s.sh_addr = dyn_info[DT_JMPREL];
+       write_one_at(f, shdr_offset, s);
+     }
+     shdr_offset += sizeof(Elf_Shdr);
+   }
+   return true;
+ }

+ 50 - 0
mozilla-release/patches/1864318-122a1.patch

@@ -0,0 +1,50 @@
+# HG changeset patch
+# User serge-sans-paille <sguelton@mozilla.com>
+# Date 1701960617 0
+#      Thu Dec 07 14:50:17 2023 +0000
+# Node ID 41b9df30e3fdb2a95aac55643e079900c06102c8
+# Parent  7a24915c2c6daf19bd45c48071871c4c5d6d76b5
+Bug 1864318 - Faster elfhack core loop r=glandium
+
+This is 5% faster on my setup, mostly thanks to unrolling being
+possible.
+
+We also skip the early loop exit. Most of the bits of `bits` are generally set, so it's ok to do a
+few more extra operations if we do them faster.
+
+Differential Revision: https://phabricator.services.mozilla.com/D193366
+
+diff --git a/build/unix/elfhack/inject.c b/build/unix/elfhack/inject.c
+--- a/build/unix/elfhack/inject.c
++++ b/build/unix/elfhack/inject.c
+@@ -95,27 +95,25 @@ extern __attribute__((visibility("hidden
+ static inline __attribute__((always_inline)) void do_relocations(
+     Elf_Addr* relhack, Elf_Addr* relhack_end) {
+   Elf_Addr* ptr;
+   for (Elf_Addr* entry = relhack; entry < relhack_end; entry++) {
+     if ((*entry & 1) == 0) {
+       ptr = (Elf_Addr*)((intptr_t)&__ehdr_start + *entry);
+       *ptr += (intptr_t)&__ehdr_start;
+     } else {
+-      size_t remaining = (8 * sizeof(Elf_Addr) - 1);
+       Elf_Addr bits = *entry;
++      Elf_Addr* end = ptr + 8 * sizeof(Elf_Addr) - 1;
+       do {
++        ptr++;
+         bits >>= 1;
+-        remaining--;
+-        ptr++;
+         if (bits & 1) {
+           *ptr += (intptr_t)&__ehdr_start;
+         }
+-      } while (bits);
+-      ptr += remaining;
++      } while (ptr < end);
+     }
+   }
+ }
+ 
+ #ifndef RELRHACK
+ __attribute__((section(".text._init_noinit"))) int init_noinit(int argc,
+                                                                char** argv,
+                                                                char** env) {

+ 194 - 0
mozilla-release/patches/1892493-127a1.patch

@@ -0,0 +1,194 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1714424316 0
+#      Mon Apr 29 20:58:36 2024 +0000
+# Node ID 71795f53ee46bb3faa959bb5359959e2a3dbfcbe
+# Parent  a009318c45735902ff3cf69d99787ea5b48f610d
+Bug 1892493 - Support reading a response file when that's the only thing on the command line. r=sergesanspaille
+
+Differential Revision: https://phabricator.services.mozilla.com/D208284
+
+diff --git a/build/unix/elfhack/relrhack.cpp b/build/unix/elfhack/relrhack.cpp
+--- a/build/unix/elfhack/relrhack.cpp
++++ b/build/unix/elfhack/relrhack.cpp
+@@ -7,30 +7,33 @@
+ // name in $PATH. However, if for some reason the next linker cannot be
+ // found this way, the caller may pass its path via the --real-linker
+ // option.
+ //
+ // More in-depth background on https://glandium.org/blog/?p=4297
+ 
+ #include "relrhack.h"
+ #include <algorithm>
++#include <cstdio>
+ #include <cstring>
+ #include <filesystem>
+ #include <fstream>
+ #include <iostream>
+ #include <optional>
+ #include <spawn.h>
+ #include <sstream>
+ #include <stdexcept>
+ #include <sys/wait.h>
+ #include <unistd.h>
+ #include <unordered_map>
+ #include <utility>
+ #include <vector>
+ 
++#include "mozilla/ScopeExit.h"
++
+ namespace fs = std::filesystem;
+ 
+ class CantSwapSections : public std::runtime_error {
+  public:
+   CantSwapSections(const char* what) : std::runtime_error(what) {}
+ };
+ 
+ template <int bits>
+@@ -415,20 +418,50 @@ uint16_t get_elf_machine(std::istream& i
+   // As far as e_machine is concerned, both Elf32_Ehdr and Elf64_Ehdr are equal.
+   Elf32_Ehdr ehdr;
+   in.read(reinterpret_cast<char*>(&ehdr), sizeof(ehdr));
+   // get_elf_class will throw exceptions for the cases we don't handle.
+   get_elf_class(ehdr.e_ident);
+   return ehdr.e_machine;
+ }
+ 
+-int run_command(std::vector<const char*>& args) {
++int run_command(std::vector<const char*>& args, bool use_response_file) {
++  std::string at_file;
++  const char** argv = args.data();
++  std::array<const char*, 3> args_with_atfile{};
++  if (use_response_file) {
++    const char* tmpdir = getenv("TMPDIR");
++    if (!tmpdir) {
++      tmpdir = "/tmp";
++    }
++    std::string tmpfile = tmpdir;
++    tmpfile += "/relrhackXXXXXX";
++    int fd = mkstemp(tmpfile.data());
++    if (fd < 0) {
++      std::cerr << "Failed to create temporary file." << std::endl;
++      return 1;
++    }
++    close(fd);
++    std::ofstream f{tmpfile, f.binary};
++    for (auto arg = std::next(args.begin()); arg != args.end(); ++arg) {
++      f << *arg << "\n";
++    }
++    at_file = "@";
++    at_file += tmpfile;
++    args_with_atfile = {args.front(), at_file.c_str(), nullptr};
++    argv = args_with_atfile.data();
++  }
++  auto guard = mozilla::MakeScopeExit([&] {
++    if (!at_file.empty()) {
++      unlink(at_file.c_str() + 1);
++    }
++  });
+   pid_t child_pid;
+   if (posix_spawn(&child_pid, args[0], nullptr, nullptr,
+-                  const_cast<char* const*>(args.data()), environ) != 0) {
++                  const_cast<char* const*>(argv), environ) != 0) {
+     throw std::runtime_error("posix_spawn failed");
+   }
+ 
+   int status;
+   waitpid(child_pid, &status, 0);
+   return WEXITSTATUS(status);
+ }
+ 
+@@ -437,32 +470,62 @@ int main(int argc, char* argv[]) {
+ 
+   std::vector<const char*> args;
+ 
+   int i, crti = 0;
+   std::optional<fs::path> output = std::nullopt;
+   std::optional<fs::path> real_linker = std::nullopt;
+   bool shared = false;
+   bool is_android = false;
++  bool use_response_file = false;
++  std::vector<char> response_file;
++  std::vector<const char*> response_file_args;
+   uint16_t elf_machine = EM_NONE;
+   // Scan argv in order to prepare the following:
+   // - get the output file. That's the file we may need to adjust.
+   // - get the --real-linker if one was passed.
+   // - detect whether we're linking a shared library or something else. As of
+   // now, only shared libraries are handled. Technically speaking, programs
+   // could be handled as well, but for the purpose of Firefox, that actually
+   // doesn't work because programs contain a memory allocator that ends up
+   // being called before the injected code has any chance to apply relocations,
+   // and the allocator itself needs the relocations to have been applied.
+   // - detect the position of crti.o so that we can inject our own object
+   // right after it, and also to detect the machine type to pick the right
+   // object to inject.
+   //
+   // At the same time, we also construct a new list of arguments, with
+   // --real-linker filtered out. We'll later inject arguments in that list.
++  if (argc == 2 && argv[1] && argv[1][0] == '@') {
++    // When GCC is given a response file, it wraps all arguments into a
++    // new response file with all arguments, even if originally there were
++    // arguments and a response file.
++    // In that case, we can't scan for arguments, so we need to read the
++    // response file. And as we change the arguments, we'll need to write
++    // a new one.
++    std::ifstream f{argv[1] + 1, f.binary | f.ate};
++    if (!f) {
++      std::cerr << "Failed to read " << argv[1] + 1 << std::endl;
++      return 1;
++    }
++    size_t len = f.tellg();
++    response_file = read_vector_at<char>(f, 0, len);
++    std::replace(response_file.begin(), response_file.end(), '\n', '\0');
++    if (len && response_file[len - 1] != '\0') {
++      response_file.push_back('\0');
++    }
++    response_file_args.push_back(argv[0]);
++    for (const char* a = response_file.data();
++         a < response_file.data() + response_file.size(); a += strlen(a) + 1) {
++      response_file_args.push_back(a);
++    }
++    argv = const_cast<char**>(response_file_args.data());
++    argc = response_file_args.size();
++    use_response_file = true;
++  }
+   for (i = 1, argv++; i < argc && *argv; argv++, i++) {
+     std::string_view arg{*argv};
+     if (arg == "-shared") {
+       shared = true;
+     } else if (arg == "-o") {
+       args.push_back(*(argv++));
+       ++i;
+       output = *argv;
+@@ -533,17 +596,17 @@ int main(int argc, char* argv[]) {
+   }
+ 
+   if (shared) {
+     std::vector<const char*> hacked_args(args);
+     auto inject = this_program.parent_path() / "inject" / (stem + ".o");
+     hacked_args.insert(hacked_args.begin() + crti + 1, inject.c_str());
+     hacked_args.insert(hacked_args.end() - 1, {"-z", "pack-relative-relocs",
+                                                "-init=_relrhack_wrap_init"});
+-    int status = run_command(hacked_args);
++    int status = run_command(hacked_args, use_response_file);
+     if (status) {
+       return status;
+     }
+     bool hacked = false;
+     try {
+       std::fstream f{*output, f.binary | f.in | f.out};
+       f.exceptions(f.failbit);
+       auto elf_class = get_elf_class(f);
+@@ -558,10 +621,10 @@ int main(int argc, char* argv[]) {
+                 << std::endl;
+       return 1;
+     }
+     if (hacked) {
+       return 0;
+     }
+   }
+ 
+-  return run_command(args);
++  return run_command(args, use_response_file);
+ }

+ 144 - 0
mozilla-release/patches/1898109-128a1.patch

@@ -0,0 +1,144 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1716409379 0
+#      Wed May 22 20:22:59 2024 +0000
+# Node ID 770c96d9f19151317af3b9c0667bb0600915b40e
+# Parent  228d9dc6c1326525ec487c7c3680c4d5f8862348
+Bug 1898109 - Allow the Android system linker to handle RELR relocations itself. r=sergesanspaille
+
+Differential Revision: https://phabricator.services.mozilla.com/D211122
+
+diff --git a/build/unix/elfhack/inject.c b/build/unix/elfhack/inject.c
+--- a/build/unix/elfhack/inject.c
++++ b/build/unix/elfhack/inject.c
+@@ -205,21 +205,37 @@ static void _relrhack_init(void) {
+ 
+   if (relro_start != relro_end) {
+     do_relocations_with_relro(relhack, relhack_end, relro_start, relro_end);
+   } else {
+     do_relocations(relhack, relhack_end);
+   }
+ }
+ 
++#  ifdef ANDROID
++// This creates a value that uses a relative relocation.
++// In the case we've not set DT_RELRHACK_BIT on the RELR tags in the
++// dynamic section, if the dynamic loader applied the relocation,
++// the value will correctly point to the function address in memory.
++__attribute__((visibility("hidden"))) void (*__relrhack_init)(void) =
++    _relrhack_init;
++#  endif
++
+ // The Android CRT doesn't contain an init function.
+ #  ifndef ANDROID
+ extern __attribute__((visibility("hidden"))) void _init(int argc, char** argv,
+                                                         char** env);
+ #  endif
+ 
+ void _relrhack_wrap_init(int argc, char** argv, char** env) {
++#  ifdef ANDROID
++  // When the dynamic loader has applied the relocations itself, do nothing.
++  // (see comment above __relrhack_init)
++  if (__relrhack_init == _relrhack_init) {
++    return;
++  }
++#  endif
+   _relrhack_init();
+ #  ifndef ANDROID
+   _init(argc, argv, env);
+ #  endif
+ }
+ #endif
+diff --git a/build/unix/elfhack/relrhack.cpp b/build/unix/elfhack/relrhack.cpp
+--- a/build/unix/elfhack/relrhack.cpp
++++ b/build/unix/elfhack/relrhack.cpp
+@@ -109,17 +109,17 @@ struct RelR : public Elf<bits> {
+       if (p.p_type == PT_LOAD && addr >= p.p_vaddr &&
+           addr < p.p_vaddr + p.p_filesz) {
+         return addr - (p.p_vaddr - p.p_paddr);
+       }
+     }
+     return 0;
+   }
+ 
+-  static bool hack(std::fstream& f);
++  static bool hack(std::fstream& f, bool set_relrhack_bit);
+ };
+ 
+ template <typename T>
+ T read_one_at(std::istream& in, off_t pos) {
+   T result;
+   in.seekg(pos, std::ios::beg);
+   in.read(reinterpret_cast<char*>(&result), sizeof(T));
+   return result;
+@@ -145,17 +145,17 @@ void write_one_at(std::ostream& out, off
+ 
+ template <typename T>
+ void write_vector_at(std::ostream& out, off_t pos, const std::vector<T>& vec) {
+   write_at(out, pos, reinterpret_cast<const char*>(&vec.front()),
+            vec.size() * sizeof(T));
+ }
+ 
+ template <int bits>
+-bool RelR<bits>::hack(std::fstream& f) {
++bool RelR<bits>::hack(std::fstream& f, bool set_relrhack_bit) {
+   auto ehdr = read_one_at<Elf_Ehdr>(f, 0);
+   if (ehdr.e_phentsize != sizeof(Elf_Phdr)) {
+     throw std::runtime_error("Invalid ELF?");
+   }
+   auto phdr = read_vector_at<Elf_Phdr>(f, ehdr.e_phoff, ehdr.e_phnum);
+   const auto& dyn_phdr =
+       std::find_if(phdr.begin(), phdr.end(),
+                    [](const auto& p) { return p.p_type == PT_DYNAMIC; });
+@@ -220,19 +220,21 @@ bool RelR<bits>::hack(std::fstream& f) {
+   // If the packed relocations + some overhead (we pick 4K arbitrarily, the
+   // real size would require digging into the section sizes of the injected
+   // .o file, which is not worth the error) is larger than the estimated
+   // unpacked relocations, we'll just relink without packed relocations.
+   if (relocs * relent < relrsz + 4096) {
+     return false;
+   }
+ 
+-  // Change DT_RELR* tags to add DT_RELRHACK_BIT.
+-  for (const auto tag : {DT_RELR, DT_RELRSZ, DT_RELRENT}) {
+-    write_one_at(f, dyn_info.offset(tag), tag | DT_RELRHACK_BIT);
++  if (set_relrhack_bit) {
++    // Change DT_RELR* tags to add DT_RELRHACK_BIT.
++    for (const auto tag : {DT_RELR, DT_RELRSZ, DT_RELRENT}) {
++      write_one_at(f, dyn_info.offset(tag), tag | DT_RELRHACK_BIT);
++    }
+   }
+ 
+   bool is_glibc = false;
+ 
+   if (dyn_info.contains(DT_VERNEEDNUM) && dyn_info.contains(DT_VERNEED) &&
+       dyn_info.contains(DT_STRSZ) && dyn_info.contains(DT_STRTAB)) {
+     // Scan SHT_VERNEED for the GLIBC_ABI_DT_RELR version on the libc
+     // library.
+@@ -606,20 +608,24 @@ int main(int argc, char* argv[]) {
+       return status;
+     }
+     bool hacked = false;
+     try {
+       std::fstream f{*output, f.binary | f.in | f.out};
+       f.exceptions(f.failbit);
+       auto elf_class = get_elf_class(f);
+       f.seekg(0, std::ios::beg);
++      // On Android, we don't set the relrhack bit so that the system linker
++      // can handle the RELR relocations when supported. On desktop, the
++      // glibc unfortunately rejects the binaries without the bit set.
++      // (see comment about GLIBC_ABI_DT_RELR)
+       if (elf_class == ELFCLASS32) {
+-        hacked = RelR<32>::hack(f);
++        hacked = RelR<32>::hack(f, /* set_relrhack_bit = */ !is_android);
+       } else if (elf_class == ELFCLASS64) {
+-        hacked = RelR<64>::hack(f);
++        hacked = RelR<64>::hack(f, /* set_relrhack_bit = */ !is_android);
+       }
+     } catch (const std::runtime_error& err) {
+       std::cerr << "Failed to hack " << output->string() << ": " << err.what()
+                 << std::endl;
+       return 1;
+     }
+     if (hacked) {
+       return 0;

+ 60 - 0
mozilla-release/patches/1903021-129a1.patch

@@ -0,0 +1,60 @@
+# HG changeset patch
+# User Mike Hommey <mh+mozilla@glandium.org>
+# Date 1718914515 0
+#      Thu Jun 20 20:15:15 2024 +0000
+# Node ID ae87b6009cbc6d2c56bf33cc85dae00cf9dfa23d
+# Parent  19cb5f5effde6401fcf4d17bbad29c33b63628ec
+Bug 1903021 - Avoid use after vector resize. r=sergesanspaille
+
+Differential Revision: https://phabricator.services.mozilla.com/D214330
+
+diff --git a/build/unix/elfhack/elfhack.cpp b/build/unix/elfhack/elfhack.cpp
+--- a/build/unix/elfhack/elfhack.cpp
++++ b/build/unix/elfhack/elfhack.cpp
+@@ -1111,17 +1111,17 @@ int do_relocation_section(Elf* elf, unsi
+   // corresponding function, which means it needs access to a pointer to it. We
+   // get such a pointer by making the linker apply a relocation for the symbol
+   // at an address our code can read. The problem here is that there is not much
+   // relocated space where we can put such a pointer, so we abuse the bss
+   // section temporarily (it will be restored to a null value before any code
+   // can actually use it)
+   if (elf->getSegmentByType(PT_GNU_RELRO)) {
+     ElfSection* gnu_versym = dyn->getSectionForType(DT_VERSYM);
+-    auto lookup = [&symtab, &gnu_versym](const char* symbol) {
++    auto ensure_symbol = [&symtab, &gnu_versym](const char* symbol) {
+       Elf_SymValue* sym_value = symtab->lookup(symbol, STT(FUNC));
+       if (!sym_value) {
+         symtab->syms.emplace_back();
+         sym_value = &symtab->syms.back();
+         symtab->grow(symtab->syms.size() * symtab->getEntSize());
+         sym_value->name =
+             ((ElfStrtab_Section*)symtab->getLink())->getStr(symbol);
+         sym_value->info = ELF64_ST_INFO(STB_GLOBAL, STT_FUNC);
+@@ -1133,21 +1133,23 @@ int do_relocation_section(Elf* elf, unsi
+         // The DT_VERSYM data (in the .gnu.version section) has the same number
+         // of entries as the symbols table. Since we added one entry there, we
+         // need to add one entry here. Zeroes in the extra data means no version
+         // for that symbol, which is the simplest thing to do.
+         if (gnu_versym) {
+           gnu_versym->grow(gnu_versym->getSize() + gnu_versym->getEntSize());
+         }
+       }
+-      return sym_value;
+     };
+-
+-    Elf_SymValue* mprotect = lookup("mprotect");
+-    Elf_SymValue* sysconf = lookup("sysconf");
++    // ensure_symbol may trigger a symbol table vector resize, so only lookup
++    // the symbols after we're done touching the symbol table.
++    ensure_symbol("mprotect");
++    ensure_symbol("sysconf");
++    Elf_SymValue* mprotect = symtab->lookup("mprotect", STT(FUNC));
++    Elf_SymValue* sysconf = symtab->lookup("sysconf", STT(FUNC));
+ 
+     // Add relocations for the mprotect and sysconf symbols.
+     auto add_relocation_to = [&new_rels, &symtab, rel_type2](
+                                  Elf_SymValue* symbol, unsigned int location) {
+       new_rels.emplace_back();
+       Rel_Type& rel = new_rels.back();
+       memset(&rel, 0, sizeof(rel));
+       rel.r_info = ELF64_R_INFO(

+ 31 - 0
mozilla-release/patches/1903254-129a1.patch

@@ -0,0 +1,31 @@
+# HG changeset patch
+# User Pier Angelo Vendrame <pierov@torproject.org>
+# Date 1718789493 0
+#      Wed Jun 19 09:31:33 2024 +0000
+# Node ID 9646841d9d86983cb12d9c95e6c8819def0a5a2b
+# Parent  3722777fb6807c957b33e0374c86b728e96c6c21
+Bug 1903254 - Explicitly include <array> in relrhack.cpp r=glandium
+
+Differential Revision: https://phabricator.services.mozilla.com/D214097
+
+diff --git a/build/unix/elfhack/relrhack.cpp b/build/unix/elfhack/relrhack.cpp
+--- a/build/unix/elfhack/relrhack.cpp
++++ b/build/unix/elfhack/relrhack.cpp
+@@ -7,16 +7,17 @@
+ // name in $PATH. However, if for some reason the next linker cannot be
+ // found this way, the caller may pass its path via the --real-linker
+ // option.
+ //
+ // More in-depth background on https://glandium.org/blog/?p=4297
+ 
+ #include "relrhack.h"
+ #include <algorithm>
++#include <array>
+ #include <cstdio>
+ #include <cstring>
+ #include <filesystem>
+ #include <fstream>
+ #include <iostream>
+ #include <optional>
+ #include <spawn.h>
+ #include <sstream>

+ 36 - 0
mozilla-release/patches/series

@@ -7318,3 +7318,39 @@ TOP-NOBUG-blockquad0-25319.patch
 1449530-2-61a1.patch
 1862395-incorrect-version-resistfingerprinting-v2-25320.patch
 1737436-use-mozilla-compat-version-define-25320.patch
+1424867-1-59a1.patch
+1424867-2-59a1.patch
+1424867-3-59a1.patch
+1430729-59a1.patch
+1431109-59a1.patch
+1435223-59a1.patch
+1438196-60a1.patch
+1461614-62a1.patch
+1464890-63a1.patch
+1477540-63a1.patch
+1519636-xx-elfhack-112a1.patch
+1838328-116a1.patch
+1839746-116a1.patch
+1840931-116a1.patch
+1841212-116a1.patch
+1839741-119a1.patch
+1839740-2-119a1.patch
+1839740-3-119a1.patch
+1850867-1-119a1.patch
+1850867-2-119a1.patch
+1854052-119a1.patch
+1854303-119a1.patch
+1854497-119a1.patch
+1855955-PARTIAL-elfhack-120a1.patch
+1855568-1-120a1.patch
+1855568-2-120a1.patch
+1855568-3-120a1.patch
+1856752-120a1.patch
+1863485-121a1.patch
+1863441-121a1.patch
+1864318-122a1.patch
+1892493-127a1.patch
+1898109-128a1.patch
+1903254-129a1.patch
+1903021-129a1.patch
+1519636-xx-elfhack-130a1.patch