Andreas Klebinger pushed to branch wip/andreask/linker_fix at Glasgow Haskell Compiler / GHC
Commits:
-
e3e1bec3
by Andreas Klebinger at 2026-04-03T11:32:27+00:00
-
ac470315
by Andreas Klebinger at 2026-04-03T11:32:36+00:00
-
2c44763e
by Andreas Klebinger at 2026-04-03T11:32:36+00:00
-
0d51a744
by Andreas Klebinger at 2026-04-03T11:32:36+00:00
-
583b53e2
by Andreas Klebinger at 2026-04-03T11:34:25+00:00
-
a34b3fa5
by Andreas Klebinger at 2026-04-03T12:33:16+00:00
8 changed files:
- rts/Linker.c
- rts/LinkerInternals.h
- rts/linker/LoadArchive.c
- rts/linker/LoadNativeObjPosix.c
- rts/linker/MachO.c
- rts/linker/MachO.h
- rts/linker/PEi386.c
- rts/linker/SymbolExtras.c
Changes:
| ... | ... | @@ -1240,7 +1240,7 @@ void freeObjectCode (ObjectCode *oc) |
| 1240 | 1240 | |
| 1241 | 1241 | ObjectCode*
|
| 1242 | 1242 | mkOc( ObjectType type, pathchar *path, char *image, int imageSize,
|
| 1243 | - bool mapped, pathchar *archiveMemberName, int misalignment ) {
|
|
| 1243 | + bool mapped, pathchar *archiveMemberName ) {
|
|
| 1244 | 1244 | ObjectCode* oc;
|
| 1245 | 1245 | |
| 1246 | 1246 | |
| ... | ... | @@ -1294,7 +1294,6 @@ mkOc( ObjectType type, pathchar *path, char *image, int imageSize, |
| 1294 | 1294 | oc->bssEnd = NULL;
|
| 1295 | 1295 | oc->imageMapped = mapped;
|
| 1296 | 1296 | |
| 1297 | - oc->misalignment = misalignment;
|
|
| 1298 | 1297 | oc->cxa_finalize = NULL;
|
| 1299 | 1298 | oc->extraInfos = NULL;
|
| 1300 | 1299 | |
| ... | ... | @@ -1352,7 +1351,6 @@ preloadObjectFile (pathchar *path) |
| 1352 | 1351 | int r;
|
| 1353 | 1352 | void *image;
|
| 1354 | 1353 | ObjectCode *oc;
|
| 1355 | - int misalignment = 0;
|
|
| 1356 | 1354 | |
| 1357 | 1355 | r = pathstat(path, &st);
|
| 1358 | 1356 | if (r == -1) {
|
| ... | ... | @@ -1410,27 +1408,8 @@ preloadObjectFile (pathchar *path) |
| 1410 | 1408 | return NULL;
|
| 1411 | 1409 | }
|
| 1412 | 1410 | |
| 1413 | -# if defined(darwin_HOST_OS)
|
|
| 1414 | - |
|
| 1415 | - // In a Mach-O .o file, all sections can and will be misaligned
|
|
| 1416 | - // if the total size of the headers is not a multiple of the
|
|
| 1417 | - // desired alignment. This is fine for .o files that only serve
|
|
| 1418 | - // as input for the static linker, but it's not fine for us,
|
|
| 1419 | - // as SSE (used by gcc for floating point) and Altivec require
|
|
| 1420 | - // 16-byte alignment.
|
|
| 1421 | - // We calculate the correct alignment from the header before
|
|
| 1422 | - // reading the file, and then we misalign image on purpose so
|
|
| 1423 | - // that the actual sections end up aligned again.
|
|
| 1424 | - misalignment = machoGetMisalignment(f);
|
|
| 1425 | - image = stgMallocBytes(fileSize + misalignment, "loadObj(image)");
|
|
| 1426 | - image += misalignment;
|
|
| 1427 | - |
|
| 1428 | -# else /* !defined(darwin_HOST_OS) */
|
|
| 1429 | - |
|
| 1430 | 1411 | image = stgMallocBytes(fileSize, "loadObj(image)");
|
| 1431 | 1412 | |
| 1432 | -#endif /* !defined(darwin_HOST_OS) */
|
|
| 1433 | - |
|
| 1434 | 1413 | int n;
|
| 1435 | 1414 | n = fread ( image, 1, fileSize, f );
|
| 1436 | 1415 | fclose(f);
|
| ... | ... | @@ -1445,16 +1424,13 @@ preloadObjectFile (pathchar *path) |
| 1445 | 1424 | IF_DEBUG(linker, debugBelch("loadObj: preloaded image at %p\n", (void *) image));
|
| 1446 | 1425 | |
| 1447 | 1426 | /* FIXME (AP): =mapped= parameter unconditionally set to true */
|
| 1448 | - oc = mkOc(STATIC_OBJECT, path, image, fileSize, true, NULL, misalignment);
|
|
| 1427 | + oc = mkOc(STATIC_OBJECT, path, image, fileSize, true, NULL);
|
|
| 1449 | 1428 | |
| 1450 | -#if defined(OBJFORMAT_MACHO)
|
|
| 1451 | - if (ocVerifyImage_MachO( oc ))
|
|
| 1452 | - ocInit_MachO( oc );
|
|
| 1453 | -#endif
|
|
| 1454 | -#if defined(OBJFORMAT_ELF)
|
|
| 1455 | - if(ocVerifyImage_ELF( oc ))
|
|
| 1456 | - ocInit_ELF( oc );
|
|
| 1457 | -#endif
|
|
| 1429 | + if (!verifyAndInitOc(oc)) {
|
|
| 1430 | + ocDebugBelch(oc, "loadObj: Failed to verify oc.\n");
|
|
| 1431 | + freeObjectCode(oc);
|
|
| 1432 | + return NULL;
|
|
| 1433 | + }
|
|
| 1458 | 1434 | return oc;
|
| 1459 | 1435 | }
|
| 1460 | 1436 | |
| ... | ... | @@ -1511,27 +1487,42 @@ HsInt loadObj (pathchar *path) |
| 1511 | 1487 | return r;
|
| 1512 | 1488 | }
|
| 1513 | 1489 | |
| 1490 | +// Call the relevant VerifyImage_* and ocInit_* functions.
|
|
| 1491 | +// Return 1 on success.
|
|
| 1492 | +HsInt verifyAndInitOc (ObjectCode* oc)
|
|
| 1493 | +{
|
|
| 1494 | + int r;
|
|
| 1495 | + |
|
| 1496 | + /* verify the in-memory image */
|
|
| 1497 | +#if defined(OBJFORMAT_ELF)
|
|
| 1498 | + r = ocVerifyImage_ELF ( oc );
|
|
| 1499 | + if(r) {
|
|
| 1500 | + ocInit_ELF( oc );
|
|
| 1501 | + }
|
|
| 1502 | +#elif defined(OBJFORMAT_PEi386)
|
|
| 1503 | + r = ocVerifyImage_PEi386 ( oc );
|
|
| 1504 | +#elif defined(OBJFORMAT_MACHO)
|
|
| 1505 | + r = ocVerifyImage_MachO ( oc );
|
|
| 1506 | + if(r) {
|
|
| 1507 | + ocInit_MachO( oc );
|
|
| 1508 | + }
|
|
| 1509 | +#else
|
|
| 1510 | + barf("loadObj: no verify method");
|
|
| 1511 | +#endif
|
|
| 1512 | + if (!r) {
|
|
| 1513 | + IF_DEBUG(linker, ocDebugBelch(oc, "ocVerifyImage_* failed\n"));
|
|
| 1514 | + return r;
|
|
| 1515 | + }
|
|
| 1516 | + return 1;
|
|
| 1517 | +}
|
|
| 1518 | + |
|
| 1519 | +// Precondition: oc already verified.
|
|
| 1514 | 1520 | HsInt loadOc (ObjectCode* oc)
|
| 1515 | 1521 | {
|
| 1516 | 1522 | int r;
|
| 1517 | 1523 | |
| 1518 | 1524 | IF_DEBUG(linker, ocDebugBelch(oc, "start\n"));
|
| 1519 | 1525 | |
| 1520 | - /* verify the in-memory image */
|
|
| 1521 | -# if defined(OBJFORMAT_ELF)
|
|
| 1522 | - r = ocVerifyImage_ELF ( oc );
|
|
| 1523 | -# elif defined(OBJFORMAT_PEi386)
|
|
| 1524 | - r = ocVerifyImage_PEi386 ( oc );
|
|
| 1525 | -# elif defined(OBJFORMAT_MACHO)
|
|
| 1526 | - r = ocVerifyImage_MachO ( oc );
|
|
| 1527 | -# else
|
|
| 1528 | - barf("loadObj: no verify method");
|
|
| 1529 | -# endif
|
|
| 1530 | - if (!r) {
|
|
| 1531 | - IF_DEBUG(linker, ocDebugBelch(oc, "ocVerifyImage_* failed\n"));
|
|
| 1532 | - return r;
|
|
| 1533 | - }
|
|
| 1534 | - |
|
| 1535 | 1526 | /* Note [loadOc orderings]
|
| 1536 | 1527 | ~~~~~~~~~~~~~~~~~~~~~~~
|
| 1537 | 1528 | The order of `ocAllocateExtras` and `ocGetNames` matters. For MachO
|
| ... | ... | @@ -1593,7 +1584,7 @@ HsInt loadOc (ObjectCode* oc) |
| 1593 | 1584 | oc->status = OBJECT_LOADED;
|
| 1594 | 1585 | }
|
| 1595 | 1586 | }
|
| 1596 | - IF_DEBUG(linker, ocDebugBelch(oc, "done\n"));
|
|
| 1587 | + IF_DEBUG(linker, ocDebugBelch(oc, "loadOc:done\n"));
|
|
| 1597 | 1588 | |
| 1598 | 1589 | return 1;
|
| 1599 | 1590 | }
|
| ... | ... | @@ -264,10 +264,6 @@ struct _ObjectCode { |
| 264 | 264 | /* non-zero if the object file was mmap'd, otherwise malloc'd */
|
| 265 | 265 | int imageMapped;
|
| 266 | 266 | |
| 267 | - /* record by how much image has been deliberately misaligned
|
|
| 268 | - after allocation, so that we can use realloc */
|
|
| 269 | - int misalignment;
|
|
| 270 | - |
|
| 271 | 267 | /* The address of __cxa_finalize; set when at least one finalizer was
|
| 272 | 268 | * register and therefore we must call __cxa_finalize before unloading.
|
| 273 | 269 | * See Note [Resolving __dso_handle]. */
|
| ... | ... | @@ -390,6 +386,11 @@ extern Elf_Word shndx_table_uninit_label; |
| 390 | 386 | OC_INFORMATIVE_FILENAME(oc), \
|
| 391 | 387 | ##__VA_ARGS__)
|
| 392 | 388 | |
| 389 | +#define ocBelch(oc, s, ...) \
|
|
| 390 | + errorBelch("%s(%" PATH_FMT ": " s, \
|
|
| 391 | + __func__, \
|
|
| 392 | + OC_INFORMATIVE_FILENAME(oc), \
|
|
| 393 | + ##__VA_ARGS__)
|
|
| 393 | 394 | |
| 394 | 395 | #if defined(THREADED_RTS)
|
| 395 | 396 | extern Mutex linker_mutex;
|
| ... | ... | @@ -487,12 +488,17 @@ HsInt loadArchive_ (pathchar *path); |
| 487 | 488 | HsInt isAlreadyLoaded( pathchar *path );
|
| 488 | 489 | OStatus getObjectLoadStatus_ (pathchar *path);
|
| 489 | 490 | ObjectCode *lookupObjectByPath(pathchar *path);
|
| 491 | + |
|
| 492 | +/* Verify an objects is an a format that can be loaded and initialize the oc struct if required. */
|
|
| 493 | +HsInt verifyAndInitOc( ObjectCode *oc );
|
|
| 494 | + |
|
| 495 | +//Expects the oc to be verified already.
|
|
| 490 | 496 | HsInt loadOc( ObjectCode* oc );
|
| 491 | 497 | ObjectCode* mkOc( ObjectType type, pathchar *path, char *image, int imageSize,
|
| 492 | - bool mapped, pathchar *archiveMemberName,
|
|
| 493 | - int misalignment
|
|
| 498 | + bool mapped, pathchar *archiveMemberName
|
|
| 494 | 499 | );
|
| 495 | 500 | |
| 501 | + |
|
| 496 | 502 | void initSegment(Segment *s, void *start, size_t size, SegmentProt prot, int n_sections);
|
| 497 | 503 | void freeSegments(ObjectCode *oc);
|
| 498 | 504 |
| ... | ... | @@ -24,7 +24,9 @@ |
| 24 | 24 | #include <string.h>
|
| 25 | 25 | #include <stddef.h>
|
| 26 | 26 | #include <ctype.h>
|
| 27 | +#include <sys/types.h>
|
|
| 27 | 28 | #include <fs_rts.h>
|
| 29 | +#include <stdio.h>
|
|
| 28 | 30 | |
| 29 | 31 | #define FAIL(...) do {\
|
| 30 | 32 | errorBelch("loadArchive: "__VA_ARGS__); \
|
| ... | ... | @@ -33,7 +35,6 @@ |
| 33 | 35 | |
| 34 | 36 | #define DEBUG_LOG(...) IF_DEBUG(linker, debugBelch("loadArchive: " __VA_ARGS__))
|
| 35 | 37 | |
| 36 | - |
|
| 37 | 38 | #if defined(darwin_HOST_OS) || defined(ios_HOST_OS)
|
| 38 | 39 | /* Read 4 bytes and convert to host byte order */
|
| 39 | 40 | static uint32_t read4Bytes(const char buf[static 4])
|
| ... | ... | @@ -110,56 +111,8 @@ static bool loadFatArchive(char input[static 20], FILE* f, pathchar* path) |
| 110 | 111 | }
|
| 111 | 112 | #endif
|
| 112 | 113 | |
| 113 | -enum ObjectFileFormat {
|
|
| 114 | - NotObject,
|
|
| 115 | - COFFAmd64,
|
|
| 116 | - COFFI386,
|
|
| 117 | - COFFAArch64,
|
|
| 118 | - ELF,
|
|
| 119 | - MachO32,
|
|
| 120 | - MachO64,
|
|
| 121 | -};
|
|
| 122 | - |
|
| 123 | -static enum ObjectFileFormat identifyObjectFile_(char* buf, size_t sz)
|
|
| 124 | -{
|
|
| 125 | - if (sz > 2 && ((uint16_t*)buf)[0] == 0x8664) {
|
|
| 126 | - return COFFAmd64;
|
|
| 127 | - }
|
|
| 128 | - if (sz > 2 && ((uint16_t*)buf)[0] == 0x014c) {
|
|
| 129 | - return COFFI386;
|
|
| 130 | - }
|
|
| 131 | - if (sz > 2 && ((uint16_t*)buf)[0] == 0xaa64) {
|
|
| 132 | - return COFFAArch64;
|
|
| 133 | - }
|
|
| 134 | - if (sz > 4 && memcmp(buf, "\x7f" "ELF", 4) == 0) {
|
|
| 135 | - return ELF;
|
|
| 136 | - }
|
|
| 137 | - if (sz > 4 && ((uint32_t*)buf)[0] == 0xfeedface) {
|
|
| 138 | - return MachO32;
|
|
| 139 | - }
|
|
| 140 | - if (sz > 4 && ((uint32_t*)buf)[0] == 0xfeedfacf) {
|
|
| 141 | - return MachO64;
|
|
| 142 | - }
|
|
| 143 | - // BigObj COFF files ...
|
|
| 144 | - if (sz > 8 && ((uint64_t*)buf)[0] == 0x86640002ffff0000) {
|
|
| 145 | - return COFFAmd64;
|
|
| 146 | - }
|
|
| 147 | - return NotObject;
|
|
| 148 | -}
|
|
| 149 | - |
|
| 150 | -static enum ObjectFileFormat identifyObjectFile(FILE *f)
|
|
| 114 | +static pathchar* thinArchiveMemberPath(pathchar* path, char* fileName)
|
|
| 151 | 115 | {
|
| 152 | - char buf[32];
|
|
| 153 | - ssize_t sz = fread(buf, 1, 32, f);
|
|
| 154 | - CHECK(fseek(f, -sz, SEEK_CUR) == 0);
|
|
| 155 | - return identifyObjectFile_(buf, sz);
|
|
| 156 | -}
|
|
| 157 | - |
|
| 158 | -static bool readThinArchiveMember(int n, int memberSize, pathchar* path,
|
|
| 159 | - char* fileName, char* image)
|
|
| 160 | -{
|
|
| 161 | - bool has_succeeded = false;
|
|
| 162 | - FILE* member = NULL;
|
|
| 163 | 116 | pathchar *pathCopy, *dirName, *memberPath, *objFileName;
|
| 164 | 117 | memberPath = NULL;
|
| 165 | 118 | /* Allocate and setup the dirname of the archive. We'll need
|
| ... | ... | @@ -173,15 +126,29 @@ static bool readThinArchiveMember(int n, int memberSize, pathchar* path, |
| 173 | 126 | objFileName = mkPath(fileName);
|
| 174 | 127 | pathprintf(memberPath, memberLen, WSTR("%" PATH_FMT "%" PATH_FMT), dirName,
|
| 175 | 128 | objFileName);
|
| 176 | - stgFree(objFileName);
|
|
| 129 | + |
|
| 130 | + stgFree(pathCopy);
|
|
| 177 | 131 | stgFree(dirName);
|
| 132 | + stgFree(objFileName);
|
|
| 133 | + return memberPath;
|
|
| 134 | +}
|
|
| 135 | + |
|
| 136 | +static bool readThinArchiveMember(int memberSize, pathchar* path,
|
|
| 137 | + char* fileName, char* image)
|
|
| 138 | +{
|
|
| 139 | + bool has_succeeded = false;
|
|
| 140 | + FILE* member = NULL;
|
|
| 141 | + pathchar *memberPath;
|
|
| 142 | + //Fully resolved path.
|
|
| 143 | + memberPath = thinArchiveMemberPath(path, fileName);
|
|
| 144 | + |
|
| 178 | 145 | member = pathopen(memberPath, WSTR("rb"));
|
| 179 | 146 | if (!member) {
|
| 180 | 147 | errorBelch("loadObj: can't read thin archive `%" PATH_FMT "'",
|
| 181 | 148 | memberPath);
|
| 182 | 149 | goto inner_fail;
|
| 183 | 150 | }
|
| 184 | - n = fread(image, 1, memberSize, member);
|
|
| 151 | + int n = fread(image, 1, memberSize, member);
|
|
| 185 | 152 | if (n != memberSize) {
|
| 186 | 153 | errorBelch("loadArchive: error whilst reading `%s'",
|
| 187 | 154 | fileName);
|
| ... | ... | @@ -192,7 +159,6 @@ static bool readThinArchiveMember(int n, int memberSize, pathchar* path, |
| 192 | 159 | inner_fail:
|
| 193 | 160 | fclose(member);
|
| 194 | 161 | stgFree(memberPath);
|
| 195 | - stgFree(pathCopy);
|
|
| 196 | 162 | return has_succeeded;
|
| 197 | 163 | }
|
| 198 | 164 | |
| ... | ... | @@ -379,7 +345,6 @@ HsInt loadArchive_ (pathchar *path) |
| 379 | 345 | int memberIdx = 0;
|
| 380 | 346 | FILE *f = NULL;
|
| 381 | 347 | size_t thisFileNameSize = (size_t) -1; /* shut up bogus GCC warning */
|
| 382 | - int misalignment = 0;
|
|
| 383 | 348 | |
| 384 | 349 | DEBUG_LOG("start\n");
|
| 385 | 350 | DEBUG_LOG("Loading archive `%" PATH_FMT "'\n", path);
|
| ... | ... | @@ -387,8 +352,7 @@ HsInt loadArchive_ (pathchar *path) |
| 387 | 352 | /* Check that we haven't already loaded this archive.
|
| 388 | 353 | Ignore requests to load multiple times */
|
| 389 | 354 | if (isAlreadyLoaded(path)) {
|
| 390 | - IF_DEBUG(linker,
|
|
| 391 | - debugBelch("ignoring repeated load of %" PATH_FMT "\n", path));
|
|
| 355 | + DEBUG_LOG("ignoring repeated load of %" PATH_FMT "\n", path);
|
|
| 392 | 356 | return 1; /* success */
|
| 393 | 357 | }
|
| 394 | 358 | |
| ... | ... | @@ -407,6 +371,9 @@ HsInt loadArchive_ (pathchar *path) |
| 407 | 371 | FAIL("failed to identify archive format of %" PATH_FMT ".", path);
|
| 408 | 372 | }
|
| 409 | 373 | bool isThin = archive_fmt == ThinArchive;
|
| 374 | + if(isThin) {
|
|
| 375 | + DEBUG_LOG("Found thin archive.\n");
|
|
| 376 | + }
|
|
| 410 | 377 | |
| 411 | 378 | DEBUG_LOG("loading archive contents\n");
|
| 412 | 379 | |
| ... | ... | @@ -547,9 +514,25 @@ HsInt loadArchive_ (pathchar *path) |
| 547 | 514 | }
|
| 548 | 515 | |
| 549 | 516 | DEBUG_LOG("Found member file `%s'\n", fileName);
|
| 550 | - |
|
| 551 | 517 | bool is_symbol_table = strcmp("", fileName) == 0;
|
| 552 | - enum ObjectFileFormat object_fmt = is_symbol_table ? NotObject : identifyObjectFile(f);
|
|
| 518 | +#if defined(OBJFORMAT_MACHO)
|
|
| 519 | + if (!is_symbol_table) {
|
|
| 520 | + /* Darwin ranlib symbol tables are named __.SYMDEF*
|
|
| 521 | + * There is no good documentation for this. Your best bets are
|
|
| 522 | + * probably the LLVM and Apple cctools sources.
|
|
| 523 | + */
|
|
| 524 | + if (strncmp(fileName, "__.SYMDEF", sizeof("__.SYMDEF")) == 0 ||
|
|
| 525 | + strncmp(fileName, "__.SYMDEF SORTED", sizeof("__.SYMDEF SORTED")) == 0 ||
|
|
| 526 | + strncmp(fileName, "__.SYMDEF_64", sizeof("__.SYMDEF_64")) == 0 ||
|
|
| 527 | + strncmp(fileName, "__.SYMDEF_64 SORTED", sizeof("__.SYMDEF_64 SORTED")) == 0) {
|
|
| 528 | + is_symbol_table = true;
|
|
| 529 | + }
|
|
| 530 | + }
|
|
| 531 | +#endif
|
|
| 532 | + |
|
| 533 | +/////////////////////////////////////////////////
|
|
| 534 | +// We found the member file. Load it into memory.
|
|
| 535 | +/////////////////////////////////////////////////
|
|
| 553 | 536 | |
| 554 | 537 | #if defined(OBJFORMAT_PEi386)
|
| 555 | 538 | /*
|
| ... | ... | @@ -562,39 +545,70 @@ HsInt loadArchive_ (pathchar *path) |
| 562 | 545 | * for sections. So on windows, just try to load it all.
|
| 563 | 546 | *
|
| 564 | 547 | * Linker members (e.g. filename / are skipped since they are not needed)
|
| 548 | + *
|
|
| 549 | + * AK: The gist of it is really that we need to:
|
|
| 550 | + * + Load .dll members as objects if they are *not* an import lib.
|
|
| 551 | + * + Load .dll members as import libs if they are ... import libs.
|
|
| 552 | + *
|
|
| 553 | + * There seems to be no good place to make this decision so i've put the
|
|
| 554 | + * ugly import lib detection code here, keeping the rest of the verification/loading
|
|
| 555 | + * logic relatively tidy. We basically read parts of the member file to get
|
|
| 556 | + * the header and then reuse the PE linkers type detection logic.
|
|
| 557 | + *
|
|
| 558 | + * We read at least sizeof(ANON_OBJECT_HEADER) bytes, but at most
|
|
| 559 | + * sizeof(ANON_OBJECT_HEADER_BIGOBJ). Members might be megabytes in size
|
|
| 560 | + * and we really only need at most the size of the largest header to determine
|
|
| 561 | + * the type.
|
|
| 565 | 562 | */
|
| 566 | - bool isImportLib = thisFileNameSize >= 4 && strncmp(fileName + thisFileNameSize - 4, ".dll", 4) == 0;
|
|
| 567 | -#else
|
|
| 568 | - bool isImportLib = false;
|
|
| 569 | -#endif // windows
|
|
| 563 | + bool mb_peImportLib = thisFileNameSize >= 4 && strncmp(fileName + thisFileNameSize - 4, ".dll", 4) == 0;
|
|
| 564 | + bool importLib = false;
|
|
| 565 | + if (mb_peImportLib) {
|
|
| 566 | + |
|
| 567 | + char buf[sizeof(ANON_OBJECT_HEADER_BIGOBJ)];
|
|
| 568 | + // Too small to be a import lib
|
|
| 569 | + if(memberSize < sizeof(ANON_OBJECT_HEADER)) { importLib = false;}
|
|
| 570 | + // Read & Check the header
|
|
| 571 | + else {
|
|
| 572 | + if (isThin)
|
|
| 573 | + { if (!readThinArchiveMember(
|
|
| 574 | + stg_min(sizeof(ANON_OBJECT_HEADER_BIGOBJ), memberSize),
|
|
| 575 | + path, fileName, buf))
|
|
| 576 | + { goto fail; }
|
|
| 577 | + }
|
|
| 578 | + else {
|
|
| 579 | + ssize_t sz = fread(buf, 1, sizeof(ANON_OBJECT_HEADER_BIGOBJ), f);
|
|
| 580 | + CHECK(fseek(f, -sz, SEEK_CUR) == 0);
|
|
| 581 | + }
|
|
| 582 | + importLib = getObjectType(buf, path) == COFF_IMPORT_LIB;
|
|
| 583 | + }
|
|
| 584 | + IF_DEBUG(linker, if(importLib) { DEBUG_LOG("\tfound import lib.\n") })
|
|
| 585 | + }
|
|
| 570 | 586 | |
| 587 | +#endif // windows
|
|
| 571 | 588 | DEBUG_LOG("\tthisFileNameSize = %d\n", (int)thisFileNameSize);
|
| 572 | - DEBUG_LOG("\tisObject = %d\n", object_fmt);
|
|
| 573 | - |
|
| 574 | - if ((!is_symbol_table && isThin) || object_fmt != NotObject) {
|
|
| 575 | - DEBUG_LOG("Member is an object file...loading...\n");
|
|
| 576 | 589 | |
| 590 | + if (!is_symbol_table
|
|
| 591 | +#if defined(OBJFORMAT_PEi386)
|
|
| 592 | + && !importLib
|
|
| 593 | +#endif
|
|
| 594 | + )
|
|
| 595 | + {
|
|
| 596 | + ASSERT(!isGnuIndex);
|
|
| 597 | + DEBUG_LOG("Member might be an object file...loading...\n");
|
|
| 577 | 598 | #if defined(darwin_HOST_OS) || defined(ios_HOST_OS)
|
| 578 | - if (RTS_LINKER_USE_MMAP)
|
|
| 579 | - image = mmapAnonForLinker(memberSize);
|
|
| 580 | - else {
|
|
| 581 | - /* See loadObj() */
|
|
| 582 | - misalignment = machoGetMisalignment(f);
|
|
| 583 | - image = stgMallocBytes(memberSize + misalignment,
|
|
| 584 | - "loadArchive(image)");
|
|
| 585 | - image += misalignment;
|
|
| 586 | - }
|
|
| 599 | +#if defined(RTS_LINKER_USE_MMAP)
|
|
| 600 | + image = mmapAnonForLinker(memberSize);
|
|
| 601 | +#else
|
|
| 602 | +#error "Only MMAP based loading supported on Apple platforms"
|
|
| 603 | +#endif // defined(RTS_LINKER_USE_MMAP)
|
|
| 587 | 604 | |
| 588 | 605 | #else // not darwin
|
| 589 | 606 | image = stgMallocBytes(memberSize, "loadArchive(image)");
|
| 590 | 607 | #endif
|
| 591 | 608 | if (isThin) {
|
| 592 | - if (!readThinArchiveMember(n, memberSize, path, fileName, image)) {
|
|
| 593 | - goto fail;
|
|
| 609 | + if (!readThinArchiveMember(memberSize, path, fileName, image)) {
|
|
| 610 | + FAIL("Failed to read thin member %" PATH_FMT"\n", path);
|
|
| 594 | 611 | }
|
| 595 | - // Unlike for regular archives for thin archives we can only identify the object format
|
|
| 596 | - // after having read the file pointed to.
|
|
| 597 | - object_fmt = identifyObjectFile_(image, memberSize);
|
|
| 598 | 612 | }
|
| 599 | 613 | else
|
| 600 | 614 | {
|
| ... | ... | @@ -613,21 +627,26 @@ HsInt loadArchive_ (pathchar *path) |
| 613 | 627 | pathprintf(archiveMemberName, size+1, WSTR("%" PATH_FMT "(#%d:%.*s)"),
|
| 614 | 628 | path, memberIdx, (int)thisFileNameSize, fileName);
|
| 615 | 629 | |
| 616 | - ObjectCode *oc = mkOc(STATIC_OBJECT, path, image, memberSize, false, archiveMemberName,
|
|
| 617 | - misalignment);
|
|
| 618 | -#if defined(OBJFORMAT_MACHO)
|
|
| 619 | - ASSERT(object_fmt == MachO32 || object_fmt == MachO64);
|
|
| 620 | - ocInit_MachO( oc );
|
|
| 621 | -#endif
|
|
| 622 | -#if defined(OBJFORMAT_ELF)
|
|
| 623 | - ASSERT(object_fmt == ELF);
|
|
| 624 | - ocInit_ELF( oc );
|
|
| 625 | -#endif
|
|
| 630 | +///////////////////////////////////////////////////////////////
|
|
| 631 | +// Verfiy the object file is valid, and load it if appropriate.
|
|
| 632 | +///////////////////////////////////////////////////////////////
|
|
| 626 | 633 | |
| 634 | + // Prepare headers, doesn't load any data yet.
|
|
| 635 | + ObjectCode *oc = mkOc(STATIC_OBJECT, path, image, memberSize, false, archiveMemberName);
|
|
| 627 | 636 | stgFree(archiveMemberName);
|
| 628 | 637 | |
| 638 | + if(!verifyAndInitOc( oc ))
|
|
| 639 | + {
|
|
| 640 | + errorBelch("Failed to verify %" PATH_FMT " , aborting.\n", path);
|
|
| 641 | + freeObjectCode( oc );
|
|
| 642 | + continue;
|
|
| 643 | + }
|
|
| 644 | + |
|
| 645 | + |
|
| 629 | 646 | if (0 == loadOc(oc)) {
|
| 647 | + ocBelch(oc, "Failed to load OC %" PATH_FMT " , aborting.\n", path);
|
|
| 630 | 648 | stgFree(fileName);
|
| 649 | + freeObjectCode( oc );
|
|
| 631 | 650 | fclose(f);
|
| 632 | 651 | return 0;
|
| 633 | 652 | } else {
|
| ... | ... | @@ -654,8 +673,8 @@ while reading filename from `%" PATH_FMT "'", path); |
| 654 | 673 | gnuFileIndex[memberSize] = '/';
|
| 655 | 674 | gnuFileIndexSize = memberSize;
|
| 656 | 675 | }
|
| 657 | - else if (isImportLib) {
|
|
| 658 | 676 | #if defined(OBJFORMAT_PEi386)
|
| 677 | + else if (importLib) {
|
|
| 659 | 678 | if (checkAndLoadImportLibrary(path, fileName, f)) {
|
| 660 | 679 | DEBUG_LOG("Member is an import file section... "
|
| 661 | 680 | "Corresponding DLL has been loaded...\n");
|
| ... | ... | @@ -668,8 +687,8 @@ while reading filename from `%" PATH_FMT "'", path); |
| 668 | 687 | FAIL("error whilst seeking by %zd in `%" PATH_FMT "'",
|
| 669 | 688 | memberSize, path);
|
| 670 | 689 | }
|
| 671 | -#endif
|
|
| 672 | 690 | }
|
| 691 | +#endif
|
|
| 673 | 692 | else {
|
| 674 | 693 | DEBUG_LOG("`%s' does not appear to be an object file\n",
|
| 675 | 694 | fileName);
|
| ... | ... | @@ -698,7 +717,7 @@ while reading filename from `%" PATH_FMT "'", path); |
| 698 | 717 | }
|
| 699 | 718 | memberIdx ++;
|
| 700 | 719 | DEBUG_LOG("reached end of archive loading while loop\n");
|
| 701 | - }
|
|
| 720 | + } // while(1)
|
|
| 702 | 721 | retcode = 1;
|
| 703 | 722 | fail:
|
| 704 | 723 | if (f != NULL)
|
| ... | ... | @@ -742,4 +761,3 @@ bool isArchive (pathchar *path) |
| 742 | 761 | }
|
| 743 | 762 | return strncmp(ARCHIVE_HEADER, buffer, sizeof(ARCHIVE_HEADER)-1) == 0;
|
| 744 | 763 | } |
| 745 | - |
| ... | ... | @@ -134,7 +134,7 @@ void * loadNativeObj_POSIX (pathchar *path, char **errmsg) |
| 134 | 134 | goto dlopen_fail;
|
| 135 | 135 | }
|
| 136 | 136 | |
| 137 | - nc = mkOc(DYNAMIC_OBJECT, path, NULL, 0, false, NULL, 0);
|
|
| 137 | + nc = mkOc(DYNAMIC_OBJECT, path, NULL, 0, false, NULL);
|
|
| 138 | 138 | |
| 139 | 139 | // If we HAVE_DLINFO, we use RTLD_NOW rather than RTLD_LAZY because we want
|
| 140 | 140 | // to learn eagerly about all external functions. Otherwise, there is no
|
| 1 | 1 | #include "Rts.h"
|
| 2 | +#include "rts/Linker.h"
|
|
| 2 | 3 | |
| 3 | 4 | #if defined(darwin_HOST_OS) || defined(ios_HOST_OS)
|
| 4 | 5 | |
| ... | ... | @@ -199,11 +200,14 @@ ocAllocateExtras_MachO(ObjectCode* oc) |
| 199 | 200 | int
|
| 200 | 201 | ocVerifyImage_MachO(ObjectCode * oc)
|
| 201 | 202 | {
|
| 203 | + IF_DEBUG(linker, debugBelch("ocVerifyImage_MachO: start\n"));
|
|
| 202 | 204 | char *image = (char*) oc->image;
|
| 205 | + if (oc->fileSize < (int) sizeof(MachOHeader)) {
|
|
| 206 | + IF_DEBUG(linker, errorBelch("Tried loading machO smaller than header size.\n"));
|
|
| 207 | + return 0;
|
|
| 208 | + }
|
|
| 203 | 209 | MachOHeader *header = (MachOHeader*) image;
|
| 204 | 210 | |
| 205 | - IF_DEBUG(linker, debugBelch("ocVerifyImage_MachO: start\n"));
|
|
| 206 | - |
|
| 207 | 211 | if(header->magic != MH_MAGIC_64) {
|
| 208 | 212 | errorBelch("Could not load image %s: bad magic!\n"
|
| 209 | 213 | " Expected %08x (64bit), got %08x%s\n",
|
| ... | ... | @@ -1774,34 +1778,4 @@ ocRunFini_MachO ( ObjectCode *oc ) |
| 1774 | 1778 | return 1;
|
| 1775 | 1779 | }
|
| 1776 | 1780 | |
| 1777 | -/*
|
|
| 1778 | - * Figure out by how much to shift the entire Mach-O file in memory
|
|
| 1779 | - * when loading so that its single segment ends up 16-byte-aligned
|
|
| 1780 | - */
|
|
| 1781 | -int
|
|
| 1782 | -machoGetMisalignment( FILE * f )
|
|
| 1783 | -{
|
|
| 1784 | - MachOHeader header;
|
|
| 1785 | - int misalignment;
|
|
| 1786 | - |
|
| 1787 | - {
|
|
| 1788 | - size_t n = fread(&header, sizeof(header), 1, f);
|
|
| 1789 | - if (n != 1) {
|
|
| 1790 | - barf("machoGetMisalignment: can't read the Mach-O header");
|
|
| 1791 | - }
|
|
| 1792 | - }
|
|
| 1793 | - fseek(f, -sizeof(header), SEEK_CUR);
|
|
| 1794 | - |
|
| 1795 | - if(header.magic != MH_MAGIC_64) {
|
|
| 1796 | - barf("Bad magic. Expected: %08x, got: %08x.",
|
|
| 1797 | - MH_MAGIC_64, header.magic);
|
|
| 1798 | - }
|
|
| 1799 | - |
|
| 1800 | - misalignment = (header.sizeofcmds + sizeof(header))
|
|
| 1801 | - & 0xF;
|
|
| 1802 | - |
|
| 1803 | - IF_DEBUG(linker, debugBelch("mach-o misalignment %d\n", misalignment));
|
|
| 1804 | - return misalignment ? (16 - misalignment) : 0;
|
|
| 1805 | -}
|
|
| 1806 | - |
|
| 1807 | 1781 | #endif /* darwin_HOST_OS || ios_HOST_OS */ |
| ... | ... | @@ -13,7 +13,6 @@ int ocGetNames_MachO ( ObjectCode* oc ); |
| 13 | 13 | int ocResolve_MachO ( ObjectCode* oc );
|
| 14 | 14 | int ocRunInit_MachO ( ObjectCode* oc );
|
| 15 | 15 | int ocRunFini_MachO ( ObjectCode* oc );
|
| 16 | -int machoGetMisalignment ( FILE * );
|
|
| 17 | 16 | int ocAllocateExtras_MachO ( ObjectCode* oc );
|
| 18 | 17 | |
| 19 | 18 | SectionKind getSectionKind_MachO ( MachOSection *macho );
|
| ... | ... | @@ -780,6 +780,12 @@ COFF_OBJ_TYPE getObjectType ( char* image, pathchar* fileName ) |
| 780 | 780 | *************/
|
| 781 | 781 | COFF_HEADER_INFO* getHeaderInfo ( ObjectCode* oc )
|
| 782 | 782 | {
|
| 783 | + //No guarantee it's a valid file/oc at this point as we call
|
|
| 784 | + //getHeaderInfo during verify.
|
|
| 785 | + if((size_t) oc->fileSize < sizeof(IMAGE_FILE_HEADER)) {
|
|
| 786 | + IF_DEBUG(linker, ocErrorBelch ("Supposed COFF file smaller than minimum header size.\n"));
|
|
| 787 | + return NULL;
|
|
| 788 | + }
|
|
| 783 | 789 | COFF_OBJ_TYPE coff_type = getObjectType (oc->image, OC_INFORMATIVE_FILENAME(oc));
|
| 784 | 790 | |
| 785 | 791 | COFF_HEADER_INFO* info
|
| ... | ... | @@ -808,11 +814,23 @@ COFF_HEADER_INFO* getHeaderInfo ( ObjectCode* oc ) |
| 808 | 814 | info->numberOfSections = hdr->NumberOfSections;
|
| 809 | 815 | }
|
| 810 | 816 | break;
|
| 817 | + case COFF_IMPORT_LIB:
|
|
| 818 | + {
|
|
| 819 | + errorBelch ("Unexpected COFF_IMPORT_LIB in getHeaderInfo.\n");
|
|
| 820 | + stgFree(info);
|
|
| 821 | + info = NULL;
|
|
| 822 | + break;
|
|
| 823 | + }
|
|
| 811 | 824 | default:
|
| 812 | 825 | {
|
| 813 | 826 | stgFree (info);
|
| 814 | 827 | info = NULL;
|
| 815 | 828 | errorBelch ("Unknown COFF %d type in getHeaderInfo.", coff_type);
|
| 829 | + if(oc->archiveMemberName) {
|
|
| 830 | + errorBelch ("Archive %" PATH_FMT ".\n", oc->archiveMemberName);
|
|
| 831 | + }
|
|
| 832 | + errorBelch ("In %" PATH_FMT ".\n", oc->fileName);
|
|
| 833 | + |
|
| 816 | 834 | }
|
| 817 | 835 | break;
|
| 818 | 836 | }
|
| ... | ... | @@ -63,14 +63,10 @@ int ocAllocateExtras(ObjectCode* oc, int count, int first, int bssSize) |
| 63 | 63 | |
| 64 | 64 | // round up to the nearest 4
|
| 65 | 65 | int aligned = (oc->fileSize + 3) & ~3;
|
| 66 | - int misalignment = oc->misalignment;
|
|
| 67 | 66 | |
| 68 | - oc->image -= misalignment;
|
|
| 69 | 67 | oc->image = stgReallocBytes( oc->image,
|
| 70 | - misalignment +
|
|
| 71 | 68 | aligned + extras_size,
|
| 72 | 69 | "ocAllocateExtras" );
|
| 73 | - oc->image += misalignment;
|
|
| 74 | 70 | |
| 75 | 71 | oc->symbol_extras = (SymbolExtra *) (oc->image + aligned);
|
| 76 | 72 | } else if (USE_CONTIGUOUS_MMAP || RtsFlags.MiscFlags.linkerAlwaysPic) {
|