ld64: init at 951.9

This commit is contained in:
Randy Eckenrode 2024-04-09 07:48:23 -04:00
parent cdf968c68d
commit f02b50ba18
No known key found for this signature in database
GPG Key ID: 64C1CD4EC2A600D9
9 changed files with 1143 additions and 0 deletions

View File

@ -0,0 +1,181 @@
From 5e92d65ef2b5cc07dc25b5b1bf645b314599f5d1 Mon Sep 17 00:00:00 2001
From: Randy Eckenrode <randy@largeandhighquality.com>
Date: Sat, 6 Apr 2024 20:29:25 -0400
Subject: [PATCH 4/8] Use std::atomics and std::mutex
---
src/ld/InputFiles.cpp | 13 ++++++-------
src/ld/InputFiles.h | 9 +++++----
src/ld/OutputFile.cpp | 13 ++++++-------
src/ld/ld.cpp | 11 +++++------
4 files changed, 22 insertions(+), 24 deletions(-)
diff --git a/src/ld/InputFiles.cpp b/src/ld/InputFiles.cpp
index ec53a60..427ab09 100644
--- a/src/ld/InputFiles.cpp
+++ b/src/ld/InputFiles.cpp
@@ -42,7 +42,6 @@
#include <mach-o/dyld.h>
#include <mach-o/fat.h>
#include <sys/sysctl.h>
-#include <libkern/OSAtomic.h>
#if HAVE_LIBDISPATCH
#include <dispatch/dispatch.h>
#endif
@@ -387,16 +386,16 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts);
if ( objResult != NULL ) {
- OSAtomicAdd64(len, &_totalObjectSize);
- OSAtomicIncrement32(&_totalObjectLoaded);
+ _totalObjectSize += len;
+ ++_totalObjectLoaded;
return objResult;
}
// see if it is an llvm object file
objResult = lto::parse(p, len, info.path, info.modTime, info.ordinal, _options.architecture(), _options.subArchitecture(), _options.logAllFiles(), _options.verboseOptimizationHints());
if ( objResult != NULL ) {
- OSAtomicAdd64(len, &_totalObjectSize);
- OSAtomicIncrement32(&_totalObjectLoaded);
+ _totalObjectSize += len;
+ ++_totalObjectLoaded;
return objResult;
}
@@ -444,8 +443,8 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
ld::archive::File* archiveResult = ::archive::parse(p, len, info.path, info.modTime, info.ordinal, archOpts);
if ( archiveResult != NULL ) {
- OSAtomicAdd64(len, &_totalArchiveSize);
- OSAtomicIncrement32(&_totalArchivesLoaded);
+ _totalArchiveSize += len;
+ ++_totalArchivesLoaded;
return archiveResult;
}
diff --git a/src/ld/InputFiles.h b/src/ld/InputFiles.h
index c18ccf8..ffff26b 100644
--- a/src/ld/InputFiles.h
+++ b/src/ld/InputFiles.h
@@ -46,6 +46,7 @@
#include <pthread.h>
#endif
+#include <atomic>
#include <vector>
#include "Options.h"
@@ -78,10 +79,10 @@ public:
size_t count() const { return _inputFiles.size(); }
// for -print_statistics
- volatile int64_t _totalObjectSize;
- volatile int64_t _totalArchiveSize;
- volatile int32_t _totalObjectLoaded;
- volatile int32_t _totalArchivesLoaded;
+ std::atomic<int64_t> _totalObjectSize;
+ std::atomic<int64_t> _totalArchiveSize;
+ std::atomic<int32_t> _totalObjectLoaded;
+ std::atomic<int32_t> _totalArchivesLoaded;
int32_t _totalDylibsLoaded;
diff --git a/src/ld/OutputFile.cpp b/src/ld/OutputFile.cpp
index e2c0397..15912a2 100644
--- a/src/ld/OutputFile.cpp
+++ b/src/ld/OutputFile.cpp
@@ -43,11 +43,10 @@
#include <mach-o/dyld.h>
#include <mach-o/fat.h>
#include <dispatch/dispatch.h>
-#include <os/lock_private.h>
extern "C" {
#include <corecrypto/ccsha2.h>
}
-#include <string>
+#include <mutex>
#include <string>
#include <list>
#include <algorithm>
@@ -1362,7 +1361,7 @@ void OutputFile::rangeCheckRISCVBranch20(int64_t displacement, ld::Internal& sta
#if SUPPORT_ARCH_arm64e
-static os_lock_unfair_s sAuthenticatedFixupDataLock = OS_LOCK_UNFAIR_INIT; // to serialize building of _authenticatedFixupData
+static std::mutex sAuthenticatedFixupDataLock; // to serialize building of _authenticatedFixupData
#endif
void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::Atom* atom, uint8_t* buffer)
@@ -1737,11 +1736,11 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
}
else {
auto fixupOffset = (uintptr_t)(fixUpLocation - mhAddress);
- os_lock_lock(&sAuthenticatedFixupDataLock);
+ sAuthenticatedFixupDataLock.lock();
assert(_authenticatedFixupData.find(fixupOffset) == _authenticatedFixupData.end());
auto authneticatedData = std::make_pair(authData, accumulator);
_authenticatedFixupData[fixupOffset] = authneticatedData;
- os_lock_unlock(&sAuthenticatedFixupDataLock);
+ sAuthenticatedFixupDataLock.unlock();
// Zero out this entry which we will expect later.
set64LE(fixUpLocation, 0);
}
@@ -1768,11 +1767,11 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
}
else {
auto fixupOffset = (uintptr_t)(fixUpLocation - mhAddress);
- os_lock_lock(&sAuthenticatedFixupDataLock);
+ sAuthenticatedFixupDataLock.lock();
assert(_authenticatedFixupData.find(fixupOffset) == _authenticatedFixupData.end());
auto authneticatedData = std::make_pair(authData, accumulator);
_authenticatedFixupData[fixupOffset] = authneticatedData;
- os_lock_unlock(&sAuthenticatedFixupDataLock);
+ sAuthenticatedFixupDataLock.unlock();
// Zero out this entry which we will expect later.
set64LE(fixUpLocation, 0);
}
diff --git a/src/ld/ld.cpp b/src/ld/ld.cpp
index b7590a3..f1bf9df 100644
--- a/src/ld/ld.cpp
+++ b/src/ld/ld.cpp
@@ -47,9 +47,8 @@ extern "C" double log2 ( double );
#include <mach-o/dyld.h>
#include <dlfcn.h>
#include <AvailabilityMacros.h>
-#include <os/lock_private.h>
-#include <string>
+#include <mutex>
#include <map>
#include <set>
#include <string>
@@ -1603,8 +1602,8 @@ int main(int argc, const char* argv[])
statistics.vmEnd.faults-statistics.vmStart.faults);
fprintf(stderr, "memory active: %lu, wired: %lu\n", statistics.vmEnd.active_count * vm_page_size, statistics.vmEnd.wire_count * vm_page_size);
char temp[40];
- fprintf(stderr, "processed %3u object files, totaling %15s bytes\n", inputFiles._totalObjectLoaded, commatize(inputFiles._totalObjectSize, temp));
- fprintf(stderr, "processed %3u archive files, totaling %15s bytes\n", inputFiles._totalArchivesLoaded, commatize(inputFiles._totalArchiveSize, temp));
+ fprintf(stderr, "processed %3u object files, totaling %15s bytes\n", inputFiles._totalObjectLoaded.load(), commatize(inputFiles._totalObjectSize.load(), temp));
+ fprintf(stderr, "processed %3u archive files, totaling %15s bytes\n", inputFiles._totalArchivesLoaded.load(), commatize(inputFiles._totalArchiveSize.load(), temp));
fprintf(stderr, "processed %3u dylib files\n", inputFiles._totalDylibsLoaded);
fprintf(stderr, "wrote output file totaling %15s bytes\n", commatize(out.fileSize(), temp));
}
@@ -1634,12 +1633,12 @@ int main(int argc, const char* argv[])
#ifndef NDEBUG
// now that the linker is multi-threaded, only allow one assert() to be processed
-static os_lock_unfair_s sAssertLock = OS_LOCK_UNFAIR_INIT;
+static std::mutex sAssertLock;
// implement assert() function to print out a backtrace before aborting
void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr)
{
- os_lock_lock(&sAssertLock);
+ sAssertLock.lock();
Snapshot *snapshot = Snapshot::globalSnapshot;
--
2.45.1

View File

@ -0,0 +1,48 @@
From faa5ab7c6e8d9a6c6157a2b681edad592ce78555 Mon Sep 17 00:00:00 2001
From: Randy Eckenrode <randy@largeandhighquality.com>
Date: Sun, 7 Apr 2024 15:33:36 -0400
Subject: [PATCH 5/8] Support LTO in nixpkgs
---
src/ld/InputFiles.cpp | 11 ++---------
src/ld/parsers/lto_file.cpp | 2 +-
2 files changed, 3 insertions(+), 10 deletions(-)
diff --git a/src/ld/InputFiles.cpp b/src/ld/InputFiles.cpp
index 427ab09..b8a9870 100644
--- a/src/ld/InputFiles.cpp
+++ b/src/ld/InputFiles.cpp
@@ -464,15 +464,8 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
if ( _options.overridePathlibLTO() != NULL ) {
libLTO = _options.overridePathlibLTO();
}
- else if ( _NSGetExecutablePath(ldPath, &bufSize) != -1 ) {
- if ( realpath(ldPath, tmpPath) != NULL ) {
- char* lastSlash = strrchr(tmpPath, '/');
- if ( lastSlash != NULL )
- strcpy(lastSlash, "/../lib/libLTO.dylib");
- libLTO = tmpPath;
- if ( realpath(tmpPath, libLTOPath) != NULL )
- libLTO = libLTOPath;
- }
+ else {
+ libLTO = "@libllvm@/lib/libLTO.dylib";
}
throwf("could not process llvm bitcode object file, because %s could not be loaded", libLTO);
}
diff --git a/src/ld/parsers/lto_file.cpp b/src/ld/parsers/lto_file.cpp
index 5318212..e18e974 100644
--- a/src/ld/parsers/lto_file.cpp
+++ b/src/ld/parsers/lto_file.cpp
@@ -1807,7 +1807,7 @@ bool optimize( const std::vector<const ld::Atom*>& allAtoms,
}; // namespace lto
-static const char *sLTODylib = "@rpath/libLTO.dylib";
+static const char *sLTODylib = "@libllvm@/lib/libLTO.dylib";
static std::atomic<bool> sLTOIsLoaded(false);
static void *getHandle() {
--
2.45.1

View File

@ -0,0 +1,113 @@
From add8bae5577ebe1c98cf7a711f87a3578a51d313 Mon Sep 17 00:00:00 2001
From: Randy Eckenrode <randy@largeandhighquality.com>
Date: Mon, 8 Apr 2024 22:42:40 -0400
Subject: [PATCH 6/8] Add libcd_is_blob_a_linker_signature implementation
---
compat/libcodedirectory.c | 74 +++++++++++++++++++++++++++++++++++++++
src/ld/libcodedirectory.h | 8 +++++
2 files changed, 82 insertions(+)
create mode 100644 compat/libcodedirectory.c
diff --git a/compat/libcodedirectory.c b/compat/libcodedirectory.c
new file mode 100644
index 0000000..e584dfc
--- /dev/null
+++ b/compat/libcodedirectory.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: APSL-2.0
+// libcd_is_blob_a_linker_signature implementation written by Randy Eckenrode © 2024
+
+#include <libcodedirectory.h>
+
+#include <stdbool.h>
+
+// References:
+// - https://forums.developer.apple.com/forums/thread/702351
+// - https://redmaple.tech/blogs/macho-files/#codedirectory-blob
+
+static inline uint32_t read32be(const uint8_t* data)
+{
+ return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3];
+}
+
+static inline bool is_embedded_signature(uint32_t magic) {
+ switch (magic) {
+ case CSMAGIC_EMBEDDED_SIGNATURE:
+ case CSMAGIC_EMBEDDED_SIGNATURE_OLD:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline const uint8_t* find_code_directory(const uint8_t* data, size_t size) {
+ const uint8_t* index_ptr = data + offsetof(CS_SuperBlob, index);
+
+ // There also needs to be space for the actual blobs, but there must be at least enough space
+ // for the blob indexes. If theres not, then somethings wrong, and the blob is invalid.
+ uint32_t count = read32be(data + offsetof(CS_SuperBlob, count));
+ if (count > ((data + size) - index_ptr) / sizeof(CS_BlobIndex)) {
+ return NULL;
+ }
+
+ for (uint32_t n = 0; n < count; ++n) {
+ const uint8_t* current_index_ptr = index_ptr + n * sizeof(CS_BlobIndex);
+ uint32_t type = read32be(current_index_ptr + offsetof(CS_BlobIndex, type));
+ if (type == CSSLOT_CODEDIRECTORY) {
+ uint32_t offset = read32be(current_index_ptr + offsetof(CS_BlobIndex, offset));
+ if (offset > size - sizeof(CS_CodeDirectory)) {
+ return NULL;
+ } else {
+ return data + offset;
+ }
+ }
+ }
+ return NULL;
+}
+
+enum libcd_signature_query_ret
+libcd_is_blob_a_linker_signature(const uint8_t* data, size_t size, int* linker_signed)
+{
+ if (size < sizeof(CS_SuperBlob) + sizeof(CS_BlobIndex) + sizeof(CS_CodeDirectory)) {
+ return LIBCD_SIGNATURE_QUERY_INVALID_ARGUMENT;
+ }
+
+ if (!is_embedded_signature(read32be(data + offsetof(CS_SuperBlob, magic)))) {
+ return LIBCD_SIGNATURE_QUERY_NOT_A_SIGNATURE;
+ }
+
+ const uint8_t* cd = find_code_directory(data, size);
+ if (!cd) {
+ return LIBCD_SIGNATURE_QUERY_INVALID_ARGUMENT;
+ }
+
+ uint32_t flags = read32be(cd + offsetof(CS_CodeDirectory, flags));
+ if ((flags & CS_LINKER_SIGNED) == CS_LINKER_SIGNED) {
+ *linker_signed = 1;
+ }
+
+ return LIBCD_SIGNATURE_QUERY_SUCCESS;
+}
diff --git a/src/ld/libcodedirectory.h b/src/ld/libcodedirectory.h
index 0e989a9..7532648 100644
--- a/src/ld/libcodedirectory.h
+++ b/src/ld/libcodedirectory.h
@@ -116,6 +116,14 @@ enum libcd_set_linkage_ret {
enum libcd_set_linkage_ret libcd_set_linkage(libcd *s, int linkage_hash_type, uint8_t *linkage_hash);
+enum libcd_signature_query_ret {
+ LIBCD_SIGNATURE_QUERY_SUCCESS,
+ LIBCD_SIGNATURE_QUERY_INVALID_ARGUMENT,
+ LIBCD_SIGNATURE_QUERY_NOT_A_SIGNATURE,
+};
+
+enum libcd_signature_query_ret libcd_is_blob_a_linker_signature(const uint8_t* data, size_t size, int* linker_signed);
+
__END_DECLS
#endif // H_LIBCODEDIRECTORY
--
2.45.1

View File

@ -0,0 +1,311 @@
From 36767c7345161baf0ab125f95c8557f8e24f25db Mon Sep 17 00:00:00 2001
From: Randy Eckenrode <randy@largeandhighquality.com>
Date: Tue, 9 Apr 2024 19:28:17 -0400
Subject: [PATCH 7/8] Add OpenSSL-based CoreCrypto digest functions
---
compat/CommonCrypto/CommonDigest.h | 6 +++
compat/CommonCrypto/CommonDigestSPI.c | 21 +++++++++++
compat/CommonCrypto/CommonDigestSPI.h | 14 +++++++
compat/corecrypto/api_defines.h | 10 +++++
compat/corecrypto/ccdigest.c | 53 +++++++++++++++++++++++++++
compat/corecrypto/ccdigest.h | 27 ++++++++++++++
compat/corecrypto/ccdigest_private.h | 19 ++++++++++
compat/corecrypto/ccsha1.c | 22 +++++++++++
compat/corecrypto/ccsha1.h | 9 +++++
compat/corecrypto/ccsha2.c | 22 +++++++++++
compat/corecrypto/ccsha2.h | 9 +++++
11 files changed, 212 insertions(+)
create mode 100644 compat/CommonCrypto/CommonDigest.h
create mode 100644 compat/CommonCrypto/CommonDigestSPI.c
create mode 100644 compat/CommonCrypto/CommonDigestSPI.h
create mode 100644 compat/corecrypto/api_defines.h
create mode 100644 compat/corecrypto/ccdigest.c
create mode 100644 compat/corecrypto/ccdigest.h
create mode 100644 compat/corecrypto/ccdigest_private.h
create mode 100644 compat/corecrypto/ccsha1.c
create mode 100644 compat/corecrypto/ccsha1.h
create mode 100644 compat/corecrypto/ccsha2.c
create mode 100644 compat/corecrypto/ccsha2.h
diff --git a/compat/CommonCrypto/CommonDigest.h b/compat/CommonCrypto/CommonDigest.h
new file mode 100644
index 0000000..a60eba7
--- /dev/null
+++ b/compat/CommonCrypto/CommonDigest.h
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: APSL-2.0
+// CoreCrypto compatibility shims written by Randy Eckenrode © 2024
+
+#pragma once
+
+#define CCSHA256_OUTPUT_SIZE 32
diff --git a/compat/CommonCrypto/CommonDigestSPI.c b/compat/CommonCrypto/CommonDigestSPI.c
new file mode 100644
index 0000000..41269fc
--- /dev/null
+++ b/compat/CommonCrypto/CommonDigestSPI.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: APSL-2.0
+// CoreCrypto compatibility shims written by Randy Eckenrode © 2024
+
+#include "CommonDigestSPI.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <corecrypto/ccsha2.h>
+
+void CCDigest(int type, const uint8_t* bytes, size_t count, uint8_t* digest) {
+ if (type != kCCDigestSHA256) {
+ abort();
+ }
+ const struct ccdigest_info* di = ccsha256_di();
+
+ ccdigest_di_decl(_di, ctx);
+ ccdigest_init(di, ctx);
+ ccdigest_update(di, ctx, count, bytes);
+ ccdigest_final(di, ctx, digest);
+}
diff --git a/compat/CommonCrypto/CommonDigestSPI.h b/compat/CommonCrypto/CommonDigestSPI.h
new file mode 100644
index 0000000..172742a
--- /dev/null
+++ b/compat/CommonCrypto/CommonDigestSPI.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: APSL-2.0
+// CoreCrypto compatibility shims written by Randy Eckenrode © 2024
+
+#pragma once
+
+#include <stdint.h>
+
+#include <corecrypto/ccdigest.h>
+#include <cs_blobs.h>
+
+
+#define kCCDigestSHA256 10
+
+EXTERN_C void CCDigest(int type, const uint8_t* bytes, size_t count, uint8_t* digest);
diff --git a/compat/corecrypto/api_defines.h b/compat/corecrypto/api_defines.h
new file mode 100644
index 0000000..13d1e7a
--- /dev/null
+++ b/compat/corecrypto/api_defines.h
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: APSL-2.0
+// CoreCrypto compatibility shims written by Randy Eckenrode © 2024
+
+#pragma once
+
+#ifdef __cplusplus
+#define EXTERN_C extern "C"
+#else
+#define EXTERN_C
+#endif
diff --git a/compat/corecrypto/ccdigest.c b/compat/corecrypto/ccdigest.c
new file mode 100644
index 0000000..e29dcb8
--- /dev/null
+++ b/compat/corecrypto/ccdigest.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: APSL-2.0
+// CoreCrypto compatibility shims written by Randy Eckenrode © 2024
+
+#include "ccdigest.h"
+#include "ccdigest_private.h"
+
+#include <stdlib.h>
+
+#include <openssl/err.h>
+
+
+struct ccdigest_context* _ccdigest_context_new(void)
+{
+ struct ccdigest_context* ctx = malloc(sizeof(struct ccdigest_context));
+ ctx->context = EVP_MD_CTX_new();
+ return ctx;
+}
+
+struct ccdigest_info* _ccdigest_newprovider(const char* name)
+{
+ struct ccdigest_info* di = malloc(sizeof(struct ccdigest_info));
+ di->provider = EVP_MD_fetch(NULL, name, NULL);
+ return di;
+}
+
+void ccdigest_init(const struct ccdigest_info* di, struct ccdigest_context* ctx)
+{
+ if (!EVP_DigestInit_ex2(ctx->context, di->provider, NULL)) {
+ ERR_print_errors_fp(stderr);
+ abort();
+ }
+}
+
+void ccdigest_update(
+ const struct ccdigest_info* _di,
+ struct ccdigest_context* ctx,
+ size_t count,
+ const void* bytes
+)
+{
+ if (!EVP_DigestUpdate(ctx->context, bytes, count)) {
+ ERR_print_errors_fp(stderr);
+ abort();
+ }
+}
+
+void ccdigest_final(const struct ccdigest_info* _di, struct ccdigest_context* ctx, uint8_t* digest)
+{
+ if (!EVP_DigestFinal_ex(ctx->context, digest, NULL)) {
+ ERR_print_errors_fp(stderr);
+ abort();
+ }
+}
diff --git a/compat/corecrypto/ccdigest.h b/compat/corecrypto/ccdigest.h
new file mode 100644
index 0000000..9af2394
--- /dev/null
+++ b/compat/corecrypto/ccdigest.h
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: APSL-2.0
+// CoreCrypto compatibility shims written by Randy Eckenrode © 2024
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "api_defines.h"
+
+
+struct ccdigest_info;
+struct ccdigest_context;
+
+EXTERN_C struct ccdigest_context* _ccdigest_context_new(void);
+
+#define ccdigest_di_decl(_di, ctxvar) \
+ struct ccdigest_context* (ctxvar) = _ccdigest_context_new()
+
+EXTERN_C void ccdigest_init(const struct ccdigest_info* di, struct ccdigest_context* ctx);
+EXTERN_C void ccdigest_update(
+ const struct ccdigest_info* _di,
+ struct ccdigest_context* ctx,
+ size_t count,
+ const void* bytes
+);
+EXTERN_C void ccdigest_final(const struct ccdigest_info* _di, struct ccdigest_context* ctx, uint8_t* digest);
diff --git a/compat/corecrypto/ccdigest_private.h b/compat/corecrypto/ccdigest_private.h
new file mode 100644
index 0000000..0ea9759
--- /dev/null
+++ b/compat/corecrypto/ccdigest_private.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: APSL-2.0
+// CoreCrypto compatibility shims written by Randy Eckenrode © 2024
+
+#pragma once
+
+#include "api_defines.h"
+
+#include <openssl/evp.h>
+
+
+struct ccdigest_info {
+ EVP_MD* provider;
+};
+
+struct ccdigest_context {
+ EVP_MD_CTX* context;
+};
+
+EXTERN_C struct ccdigest_info* _ccdigest_newprovider(const char* name);
diff --git a/compat/corecrypto/ccsha1.c b/compat/corecrypto/ccsha1.c
new file mode 100644
index 0000000..e02b2b6
--- /dev/null
+++ b/compat/corecrypto/ccsha1.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: APSL-2.0
+// CoreCrypto compatibility shims written by Randy Eckenrode © 2024
+
+#include "ccsha1.h"
+
+#include <assert.h>
+
+#include <cs_blobs.h>
+
+#include "ccdigest_private.h"
+
+
+static struct ccdigest_info* di = NULL;
+
+const struct ccdigest_info* ccsha1_di(void)
+{
+ if (!di) {
+ di = _ccdigest_newprovider("SHA-1");
+ assert(EVP_MD_get_size(di->provider) == CS_SHA1_LEN);
+ }
+ return di;
+}
diff --git a/compat/corecrypto/ccsha1.h b/compat/corecrypto/ccsha1.h
new file mode 100644
index 0000000..8e3f85f
--- /dev/null
+++ b/compat/corecrypto/ccsha1.h
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: APSL-2.0
+// CoreCrypto compatibility shims written by Randy Eckenrode © 2024
+
+#pragma once
+
+#include <corecrypto/ccdigest.h>
+
+
+EXTERN_C const struct ccdigest_info* ccsha1_di(void);
diff --git a/compat/corecrypto/ccsha2.c b/compat/corecrypto/ccsha2.c
new file mode 100644
index 0000000..6504503
--- /dev/null
+++ b/compat/corecrypto/ccsha2.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: APSL-2.0
+// CoreCrypto compatibility shims written by Randy Eckenrode © 2024
+
+#include "ccsha2.h"
+
+#include <assert.h>
+
+#include <cs_blobs.h>
+
+#include "ccdigest_private.h"
+
+
+static struct ccdigest_info* di = NULL;
+
+const struct ccdigest_info* ccsha256_di(void)
+{
+ if (!di) {
+ di = _ccdigest_newprovider("SHA-256");
+ assert(EVP_MD_get_size(di->provider) == CS_SHA256_LEN);
+ }
+ return di;
+}
diff --git a/compat/corecrypto/ccsha2.h b/compat/corecrypto/ccsha2.h
new file mode 100644
index 0000000..9f30e03
--- /dev/null
+++ b/compat/corecrypto/ccsha2.h
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: APSL-2.0
+// CoreCrypto compatibility shims written by Randy Eckenrode © 2024
+
+#pragma once
+
+#include <corecrypto/ccdigest.h>
+
+
+EXTERN_C const struct ccdigest_info* ccsha256_di(void);
--
2.45.1

View File

@ -0,0 +1,25 @@
From 3e80d438e2a3ec50d666f2b6e32007c275d4a08a Mon Sep 17 00:00:00 2001
From: Randy Eckenrode <randy@largeandhighquality.com>
Date: Thu, 11 Apr 2024 23:13:29 -0400
Subject: [PATCH 8/8] Disable searching in standard library locations
---
src/ld/Options.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/ld/Options.cpp b/src/ld/Options.cpp
index 67a9f53..611b583 100644
--- a/src/ld/Options.cpp
+++ b/src/ld/Options.cpp
@@ -4320,7 +4320,7 @@ bool Options::shouldUseBuildVersion(ld::Platform plat, uint32_t minOSvers) const
void Options::buildSearchPaths(int argc, const char* argv[])
{
- bool addStandardLibraryDirectories = true;
+ bool addStandardLibraryDirectories = false;
ld::Platform platform = ld::Platform::unknown;
std::vector<const char*> libraryPaths;
std::vector<const char*> frameworkPaths;
--
2.45.1

View File

@ -0,0 +1,8 @@
#!/usr/bin/env python
import sys
from pathlib import Path
byteseq = (str(int(x)) for x in Path(sys.argv[1]).read_bytes())
print("#pragma once")
print(f"static const char compile_stubs[] = {{ {', '.join(byteseq)} }};")

View File

@ -0,0 +1,249 @@
# Build settings based on the upstream Xcode project.
# See: https://github.com/apple-oss-distributions/ld64/blob/main/ld64.xcodeproj/project.pbxproj
# Project settings
project(
'ld64',
'c', 'cpp',
version : '@version@',
default_options : {'cpp_std': 'c++20'},
)
fs = import('fs')
# Options
target_prefix = get_option('target_prefix')
# Dependencies
cc = meson.get_compiler('c')
cxx = meson.get_compiler('cpp')
python = find_program('python3')
libtapi = cxx.find_library('tapi')
openssl = dependency('openssl', version : '>=3.0')
xar = cc.find_library('xar')
# Feature tests
# macOS 10.12 does not support `DISPATCH_APPLY_AUTO`. Fortunately, `DISPATCH_APPLY_CURRENT_ROOT_QUEUE` has the
# same value and was repurposed in subsequent releases as `DISPATCH_APPLY_AUTO`.
dispatch_apply_auto_test = '''
#include <dispatch/dispatch.h>
int main(int argc, char* argv[]) {
dispatch_queue_t queue = DISPATCH_APPLY_AUTO;
return 0;
}
'''
if not cc.compiles(
dispatch_apply_auto_test,
args : '-Wno-unused-command-line-argument',
name : 'supports DISPATCH_APPLY_AUTO',
)
add_project_arguments(
'-include', 'dispatch/private.h',
'-DDISPATCH_APPLY_AUTO=DISPATCH_APPLY_CURRENT_ROOT_QUEUE',
'-DPRIVATE', # The required API is private on the 10.12 SDK.
language: ['c', 'cpp'],
)
endif
# The return type of `dispatch_get_global_queue` was changed in 10.14.
# Use the older type if the SDK does not support it.
dispatch_queue_global_test = '''
#include <dispatch/dispatch.h>
int main(int argc, char* argv[]) {
dispatch_queue_global_t queue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0);
return 0;
}
'''
if not cc.compiles(
dispatch_queue_global_test,
args : '-Wno-unused-command-line-argument',
name : 'supports dispatch_queue_global_t',
)
add_project_arguments('-Ddispatch_queue_global_t=dispatch_queue_t', language : ['c', 'cpp'])
endif
# Generated files
compile_stubs_h = custom_target(
'compile_stubs.h',
capture : true,
command : [python, '@INPUT0@', '@INPUT1@'],
input : ['gen_compile_stubs.py', 'compile_stubs'],
output : ['compile_stubs.h'],
)
configure_h = custom_target(
'configure_h',
command : ['bash', '@INPUT@'],
env : {
'DERIVED_FILE_DIR' : meson.current_build_dir(),
'RC_ProjectSourceVersion': '@version@'
},
input : ['src/create_configure'],
output : ['configure.h'],
)
incdirs = include_directories(
'compat',
'include',
'src/abstraction',
'src/ld',
'src/ld/code-sign-blobs',
'src/ld/parsers',
'src/ld/passes',
'src/mach_o',
)
# Dynamic libraries
libcodedirectory = library(
'codedirectory',
dependencies : [openssl],
include_directories : incdirs,
install : true,
sources : [
'compat/corecrypto/ccdigest.c',
'compat/corecrypto/ccsha1.c',
'compat/corecrypto/ccsha2.c',
'compat/libcodedirectory.c',
'src/ld/libcodedirectory.c'
],
soversion : 1,
)
install_headers(
'src/ld/cs_blobs.h',
'src/ld/libcodedirectory.h',
)
# Static libraries
libprunetrie = static_library(
'prunetrie',
include_directories : incdirs,
install : true,
override_options : {'b_lto': false},
sources : [
'src/mach_o/Error.cpp',
'src/mach_o/ExportsTrie.cpp',
'src/other/PruneTrie.cpp',
],
)
install_headers(
'src/other/prune_trie.h',
subdir : 'mach-o',
)
# Binaries
ld64 = executable(
f'@target_prefix@ld',
dependencies : [libtapi, openssl, xar],
include_directories : incdirs,
install : true,
# These linker flags mirror those used in a release build of the Xcode project.
# See: https://github.com/apple-oss-distributions/ld64/blob/47f477cb721755419018f7530038b272e9d0cdea/ld64.xcodeproj/project.pbxproj#L1292-L1299.
link_args : [
'-Wl,-exported_symbol,__mh_execute_header',
'-Wl,-stack_size,0x02000000',
'-Wl,-client_name,ld',
],
link_with : [libcodedirectory],
sources : [
compile_stubs_h,
configure_h,
'compat/CommonCrypto/CommonDigestSPI.c',
'compat/corecrypto/ccdigest.c',
'compat/corecrypto/ccsha1.c',
'compat/corecrypto/ccsha2.c',
'src/ld/FatFile.cpp',
'src/ld/InputFiles.cpp',
'src/ld/Mangling.cpp',
'src/ld/Options.cpp',
'src/ld/OutputFile.cpp',
'src/ld/PlatformSupport.cpp',
'src/ld/Resolver.cpp',
'src/ld/ResponseFiles.cpp',
'src/ld/Snapshot.cpp',
'src/ld/SymbolTable.cpp',
'src/ld/code-sign-blobs/blob.cpp',
'src/ld/code-sign-blobs/blob.h',
'src/ld/debugline.c',
'src/ld/ld.cpp',
'src/ld/parsers/archive_file.cpp',
'src/ld/parsers/generic_dylib_file.cpp',
'src/ld/parsers/lto_file.cpp',
'src/ld/parsers/macho_dylib_file.cpp',
'src/ld/parsers/macho_relocatable_file.cpp',
'src/ld/parsers/opaque_section_file.cpp',
'src/ld/parsers/textstub_dylib_file.cpp',
'src/ld/passes/bitcode_bundle.cpp',
'src/ld/passes/branch_island.cpp',
'src/ld/passes/branch_shim.cpp',
'src/ld/passes/code_dedup.cpp',
'src/ld/passes/compact_unwind.cpp',
'src/ld/passes/dtrace_dof.cpp',
'src/ld/passes/dylibs.cpp',
'src/ld/passes/got.cpp',
'src/ld/passes/huge.cpp',
'src/ld/passes/inits.cpp',
'src/ld/passes/objc.cpp',
'src/ld/passes/objc_constants.cpp',
'src/ld/passes/objc_stubs.cpp',
'src/ld/passes/order.cpp',
'src/ld/passes/stubs/stubs.cpp',
'src/ld/passes/thread_starts.cpp',
'src/ld/passes/tlvp.cpp',
'src/mach_o/Error.cpp',
'src/mach_o/ExportsTrie.cpp',
],
)
install_man('doc/man/man1/ld-classic.1')
# Extra tools
unwinddump = executable(
f'@target_prefix@unwinddump',
include_directories : incdirs,
install : true,
sources : [
configure_h,
'src/other/UnwindDump.cpp',
],
)
install_man('doc/man/man1/unwinddump.1')
machocheck = executable(
f'@target_prefix@machocheck',
include_directories : incdirs,
install : true,
sources : [
configure_h,
'src/other/machochecker.cpp',
],
)
objectdump = executable(
f'@target_prefix@ObjectDump',
include_directories : incdirs,
install : true,
sources : [
configure_h,
'src/ld/PlatformSupport.cpp',
'src/ld/debugline.c',
'src/ld/parsers/macho_relocatable_file.cpp',
'src/other/ObjectDump.cpp',
],
)
objcimageinfo = executable(
f'@target_prefix@objcimageinfo',
include_directories : incdirs,
install : true,
sources : [
configure_h,
'src/other/objcimageinfo.cpp',
],
)

View File

@ -0,0 +1,6 @@
option(
'target_prefix',
type : 'string',
value : '',
description: 'Specifies the prefix to use when building for cross-compilation (e.g., `aarch64-apple-darwin`)'
)

View File

@ -0,0 +1,202 @@
{
lib,
stdenv,
fetchFromGitHub,
fetchurl,
darwin,
libtapi,
libunwind,
llvm,
meson,
ninja,
openssl,
pkg-config,
python3,
swiftPackages,
xar,
gitUpdater,
}:
let
# The targetPrefix is prepended to binary names to allow multiple binutils on the PATH to be usable.
targetPrefix = lib.optionalString (
stdenv.targetPlatform != stdenv.hostPlatform
) "${stdenv.targetPlatform.config}-";
# ld64 needs CrashReporterClient.h, which is hard to find, but WebKit2 has it.
# Fetch it directly because the Darwin stdenv bootstrap cant depend on fetchgit.
crashreporter_h = fetchurl {
url = "https://raw.githubusercontent.com/apple-oss-distributions/WebKit2/WebKit2-7605.1.33.0.2/Platform/spi/Cocoa/CrashReporterClientSPI.h";
hash = "sha256-0ybVcwHuGEdThv0PPjYQc3SW0YVOyrM3/L9zG/l1Vtk=";
};
# First version with all the required definitions. This is used in preference to darwin.xnu to make it easier
# to support Linux and because the version of darwin.xnu available on x86_64-darwin in the 10.12 SDK is too old.
xnu = fetchFromGitHub {
name = "xnu-src";
owner = "apple-oss-distributions";
repo = "xnu";
rev = "xnu-6153.11.26";
hash = "sha256-dcnGcp7bIjQxeAn5pXt+mHSYEXb2Ad9Smhd/WUG4kb4=";
};
# Avoid pulling in all of Swift just to build libdispatch
libdispatch = swiftPackages.Dispatch.override { useSwift = false; };
in
stdenv.mkDerivation (finalAttrs: {
pname = "ld64";
version = "951.9";
outputs = [
"out"
"dev"
"lib"
];
src = fetchFromGitHub {
owner = "apple-oss-distributions";
repo = "ld64";
rev = "ld64-${finalAttrs.version}";
hash = "sha256-hLkfqgBwVPlO4gfriYOawTO5E1zSD63ZcNetm1E5I70";
};
xcodeHash = "sha256-+j7Ed/6aD46SJnr3DWPfWuYWylb2FNJRPmWsUVxZJHM=";
postUnpack = ''
unpackFile '${xnu}'
# Verify that the Xcode project has not changed unexpectedly.
hashType=$(echo $xcodeHash | cut -d- -f1)
expectedHash=$(echo $xcodeHash | cut -d- -f2)
hash=$(openssl "$hashType" -binary "$sourceRoot/ld64.xcodeproj/project.pbxproj" | base64)
if [ "$hash" != "$expectedHash" ]; then
echo 'error: hash mismatch in ld64.xcodeproj/project.pbxproj'
echo " specified: $xcodeHash"
echo " got: $hashType-$hash"
echo
echo 'Upstream Xcode project has changed. Update `meson.build` with any changes, then update `xcodeHash`.'
echo 'Use `nix-hash --flat --sri --type sha256 ld64.xcodeproj/project.pbxproj` to regenerate it.'
exit 1
fi
'';
patches = [
# Use std::atomic for atomics. Replaces private APIs (`os/lock_private.h`) with standard APIs.
./0004-Use-std-atomics-and-std-mutex.patch
# ld64 assumes the default libLTO.dylib can be found relative to its bindir, which is
# not the case in nixpkgs. Override it to default to `stdenv.cc`s libLTO.dylib.
./0005-Support-LTO-in-nixpkgs.patch
# Add implementation of missing function required for code directory support.
./0006-Add-libcd_is_blob_a_linker_signature-implementation.patch
# Add OpenSSL implementation of CoreCrypto digest functions. Avoids use of private and non-free APIs.
./0007-Add-OpenSSL-based-CoreCrypto-digest-functions.patch
# ld64 will search `/usr/lib`, `/Library/Frameworks`, etc by default. Disable that.
./0008-Disable-searching-in-standard-library-locations.patch
];
postPatch = ''
substitute ${./meson.build} meson.build \
--subst-var version
cp ${./meson.options} meson.options
# Copy headers for certain private APIs
mkdir -p include
substitute ${crashreporter_h} include/CrashReporterClient.h \
--replace-fail 'USE(APPLE_INTERNAL_SDK)' '0'
# Copy from the source so the headers can be used on Linux and x86_64-darwin
mkdir -p include/System
for dir in arm i386 machine; do
cp -r ../xnu-src/osfmk/$dir include/System/$dir
done
mkdir -p include/sys
cp ../xnu-src/bsd/sys/commpage.h include/sys
# Match the version format used by upstream.
sed -i src/ld/Options.cpp \
-e '1iconst char ld_classicVersionString[] = "@(#)PROGRAM:ld PROJECT:ld64-${finalAttrs.version}\\n";'
# Instead of messing around with trying to extract and run the script from the Xcode project,
# just use our own Python script to generate `compile_stubs.h`
cp ${./gen_compile_stubs.py} gen_compile_stubs.py
# Enable LTO support using LLVMs libLTO.dylib by default.
substituteInPlace src/ld/InputFiles.cpp \
--subst-var-by libllvm '${lib.getLib llvm}'
substituteInPlace src/ld/parsers/lto_file.cpp \
--subst-var-by libllvm '${lib.getLib llvm}'
# Use portable includes
substituteInPlace src/ld/code-sign-blobs/endian.h \
--replace-fail '#include <machine/endian.h>' '#include <sys/types.h>'
'';
strictDeps = true;
nativeBuildInputs = [
meson
ninja
openssl
pkg-config
python3
];
buildInputs = [
libtapi
llvm
libunwind
openssl
xar
] ++ lib.optionals stdenv.isDarwin [ darwin.dyld ] ++ lib.optionals stdenv.isLinux [ libdispatch ];
# Note for overrides: ld64 cannot be built as a debug build because of UB in its iteration implementations,
# which trigger libc++ debug assertions due to trying to take the address of the first element of an emtpy vector.
mesonBuildType = "release";
mesonFlags = [
(lib.mesonOption "b_ndebug" "if-release")
(lib.mesonOption "default_library" (if stdenv.hostPlatform.isStatic then "static" else "shared"))
] ++ lib.optionals (targetPrefix != "") [ (lib.mesonOption "target_prefix" targetPrefix) ];
doInstallCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
# ld64 has a test suite, but many of the tests fail (even with ld from Xcode). Instead
# of running the test suite, rebuild ld64 using itself to link itself as a check.
# LTO is enabled only to confirm that it is set up and working properly in nixpkgs.
installCheckPhase = ''
runHook preInstallCheck
cd "$NIX_BUILD_TOP/$sourceRoot"
export NIX_CFLAGS_COMPILE+=" --ld-path=$out/bin/${targetPrefix}ld"
meson setup build-install-check -Db_lto=true --buildtype=$mesonBuildType
cd build-install-check
ninja ${targetPrefix}ld "-j$NIX_BUILD_CORES"
# Confirm that ld found the LTO library and reports it.
./${targetPrefix}ld -v 2>&1 | grep -q 'LTO support'
runHook postInstallCheck
'';
postInstall = ''
ln -s ld-classic.1 "$out/share/man/man1/ld.1"
ln -s ld.1 "$out/share/man/man1/ld64.1"
moveToOutput lib/libprunetrie.a "$dev"
'';
__structuredAttrs = true;
passthru.updateScript = gitUpdater { rev-prefix = "ld64-"; };
meta = {
description = "The classic linker for Darwin";
homepage = "https://opensource.apple.com/releases/";
license = lib.licenses.apple-psl20;
mainProgram = "ld";
maintainers = with lib.maintainers; [ reckenrode ];
platforms = lib.platforms.darwin; # Porting to other platforms is incomplete. Support only Darwin for now.
};
})