Andreas Klebinger pushed to branch wip/andreask/linker_fix at Glasgow Haskell Compiler / GHC
Commits:
-
ae4264e7
by Andreas Klebinger at 2025-08-08T16:39:09+02:00
6 changed files:
- rts/Linker.c
- rts/LinkerInternals.h
- rts/linker/LoadArchive.c
- rts/linker/MachO.c
- rts/linker/MachO.h
- rts/linker/PEi386.c
Changes:
| ... | ... | @@ -1415,7 +1415,7 @@ preloadObjectFile (pathchar *path) |
| 1415 | 1415 | // We calculate the correct alignment from the header before
|
| 1416 | 1416 | // reading the file, and then we misalign image on purpose so
|
| 1417 | 1417 | // that the actual sections end up aligned again.
|
| 1418 | - misalignment = machoGetMisalignment(f);
|
|
| 1418 | + machoGetMisalignment(f, &misalignment);
|
|
| 1419 | 1419 | image = stgMallocBytes(fileSize + misalignment, "loadObj(image)");
|
| 1420 | 1420 | image += misalignment;
|
| 1421 | 1421 | |
| ... | ... | @@ -1441,14 +1441,7 @@ preloadObjectFile (pathchar *path) |
| 1441 | 1441 | /* FIXME (AP): =mapped= parameter unconditionally set to true */
|
| 1442 | 1442 | oc = mkOc(STATIC_OBJECT, path, image, fileSize, true, NULL, misalignment);
|
| 1443 | 1443 | |
| 1444 | -#if defined(OBJFORMAT_MACHO)
|
|
| 1445 | - if (ocVerifyImage_MachO( oc ))
|
|
| 1446 | - ocInit_MachO( oc );
|
|
| 1447 | -#endif
|
|
| 1448 | -#if defined(OBJFORMAT_ELF)
|
|
| 1449 | - if(ocVerifyImage_ELF( oc ))
|
|
| 1450 | - ocInit_ELF( oc );
|
|
| 1451 | -#endif
|
|
| 1444 | + verifyAndInitOc(oc);
|
|
| 1452 | 1445 | return oc;
|
| 1453 | 1446 | }
|
| 1454 | 1447 | |
| ... | ... | @@ -1505,27 +1498,44 @@ HsInt loadObj (pathchar *path) |
| 1505 | 1498 | return r;
|
| 1506 | 1499 | }
|
| 1507 | 1500 | |
| 1501 | +// Call the relevant VeriffyImage_* and ocInit_* functions.
|
|
| 1502 | +// Return 1 on success.
|
|
| 1503 | +HsInt verifyAndInitOc (ObjectCode* oc)
|
|
| 1504 | +{
|
|
| 1505 | + int r;
|
|
| 1506 | + |
|
| 1507 | + IF_DEBUG(linker, ocDebugBelch(oc, "start\n"));
|
|
| 1508 | + |
|
| 1509 | + /* verify the in-memory image */
|
|
| 1510 | +#if defined(OBJFORMAT_ELF)
|
|
| 1511 | + r = ocVerifyImage_ELF ( oc );
|
|
| 1512 | + if(r) {
|
|
| 1513 | + ocInit_ELF( oc );
|
|
| 1514 | + }
|
|
| 1515 | +#elif defined(OBJFORMAT_PEi386)
|
|
| 1516 | + r = ocVerifyImage_PEi386 ( oc );
|
|
| 1517 | +#elif defined(OBJFORMAT_MACHO)
|
|
| 1518 | + r = ocVerifyImage_MachO ( oc );
|
|
| 1519 | + if(r) {
|
|
| 1520 | + ocInit_MachO( oc );
|
|
| 1521 | + }
|
|
| 1522 | +#else
|
|
| 1523 | + barf("loadObj: no verify method");
|
|
| 1524 | +#endif
|
|
| 1525 | + if (!r) {
|
|
| 1526 | + IF_DEBUG(linker, ocDebugBelch(oc, "ocVerifyImage_* failed\n"));
|
|
| 1527 | + return r;
|
|
| 1528 | + }
|
|
| 1529 | + return 1;
|
|
| 1530 | +}
|
|
| 1531 | + |
|
| 1532 | +// Precondition: oc already verified.
|
|
| 1508 | 1533 | HsInt loadOc (ObjectCode* oc)
|
| 1509 | 1534 | {
|
| 1510 | 1535 | int r;
|
| 1511 | 1536 | |
| 1512 | 1537 | IF_DEBUG(linker, ocDebugBelch(oc, "start\n"));
|
| 1513 | 1538 | |
| 1514 | - /* verify the in-memory image */
|
|
| 1515 | -# if defined(OBJFORMAT_ELF)
|
|
| 1516 | - r = ocVerifyImage_ELF ( oc );
|
|
| 1517 | -# elif defined(OBJFORMAT_PEi386)
|
|
| 1518 | - r = ocVerifyImage_PEi386 ( oc );
|
|
| 1519 | -# elif defined(OBJFORMAT_MACHO)
|
|
| 1520 | - r = ocVerifyImage_MachO ( oc );
|
|
| 1521 | -# else
|
|
| 1522 | - barf("loadObj: no verify method");
|
|
| 1523 | -# endif
|
|
| 1524 | - if (!r) {
|
|
| 1525 | - IF_DEBUG(linker, ocDebugBelch(oc, "ocVerifyImage_* failed\n"));
|
|
| 1526 | - return r;
|
|
| 1527 | - }
|
|
| 1528 | - |
|
| 1529 | 1539 | /* Note [loadOc orderings]
|
| 1530 | 1540 | ~~~~~~~~~~~~~~~~~~~~~~~
|
| 1531 | 1541 | The order of `ocAllocateExtras` and `ocGetNames` matters. For MachO
|
| ... | ... | @@ -485,12 +485,19 @@ HsInt loadArchive_ (pathchar *path); |
| 485 | 485 | HsInt isAlreadyLoaded( pathchar *path );
|
| 486 | 486 | OStatus getObjectLoadStatus_ (pathchar *path);
|
| 487 | 487 | ObjectCode *lookupObjectByPath(pathchar *path);
|
| 488 | + |
|
| 489 | +/* Verify an objects is an a format that can be loaded and initialize the oc struct if required. */
|
|
| 490 | +HsInt verifyAndInitOc( ObjectCode *oc );
|
|
| 491 | + |
|
| 492 | +//Expects the oc to be verified already.
|
|
| 488 | 493 | HsInt loadOc( ObjectCode* oc );
|
| 489 | 494 | ObjectCode* mkOc( ObjectType type, pathchar *path, char *image, int imageSize,
|
| 490 | 495 | bool mapped, pathchar *archiveMemberName,
|
| 491 | 496 | int misalignment
|
| 492 | 497 | );
|
| 493 | 498 | |
| 499 | + |
|
| 500 | + |
|
| 494 | 501 | void initSegment(Segment *s, void *start, size_t size, SegmentProt prot, int n_sections);
|
| 495 | 502 | void freeSegments(ObjectCode *oc);
|
| 496 | 503 |
| ... | ... | @@ -110,56 +110,50 @@ static bool loadFatArchive(char input[static 20], FILE* f, pathchar* path) |
| 110 | 110 | }
|
| 111 | 111 | #endif
|
| 112 | 112 | |
| 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 | - if (sz > 8 && ((uint64_t*)buf)[0] == 0x014c0002ffff0000) {
|
|
| 148 | - return COFFI386;
|
|
| 149 | - }
|
|
| 150 | - if (sz > 8 && ((uint64_t*)buf)[0] == 0xaa640002ffff0000) {
|
|
| 151 | - return COFFAArch64;
|
|
| 152 | - }
|
|
| 153 | - return NotObject;
|
|
| 154 | -}
|
|
| 155 | - |
|
| 156 | -static enum ObjectFileFormat identifyObjectFile(FILE *f)
|
|
| 157 | -{
|
|
| 158 | - char buf[32];
|
|
| 159 | - ssize_t sz = fread(buf, 1, 32, f);
|
|
| 160 | - CHECK(fseek(f, -sz, SEEK_CUR) == 0);
|
|
| 161 | - return identifyObjectFile_(buf, sz);
|
|
| 162 | -}
|
|
| 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)
|
|
| 151 | +// {
|
|
| 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 | +// }
|
|
| 163 | 157 | |
| 164 | 158 | static bool readThinArchiveMember(int n, int memberSize, pathchar* path,
|
| 165 | 159 | char* fileName, char* image)
|
| ... | ... | @@ -553,9 +547,11 @@ HsInt loadArchive_ (pathchar *path) |
| 553 | 547 | }
|
| 554 | 548 | |
| 555 | 549 | DEBUG_LOG("Found member file `%s'\n", fileName);
|
| 556 | - |
|
| 557 | 550 | bool is_symbol_table = strcmp("", fileName) == 0;
|
| 558 | - enum ObjectFileFormat object_fmt = is_symbol_table ? NotObject : identifyObjectFile(f);
|
|
| 551 | + |
|
| 552 | +/////////////////////////////////////////////////
|
|
| 553 | +// We found the member file. Load it into memory.
|
|
| 554 | +/////////////////////////////////////////////////
|
|
| 559 | 555 | |
| 560 | 556 | #if defined(OBJFORMAT_PEi386)
|
| 561 | 557 | /*
|
| ... | ... | @@ -575,17 +571,22 @@ HsInt loadArchive_ (pathchar *path) |
| 575 | 571 | #endif // windows
|
| 576 | 572 | |
| 577 | 573 | DEBUG_LOG("\tthisFileNameSize = %d\n", (int)thisFileNameSize);
|
| 578 | - DEBUG_LOG("\tisObject = %d\n", object_fmt);
|
|
| 574 | + // DEBUG_LOG("\tisObject = %d\n", object_fmt);
|
|
| 579 | 575 | |
| 580 | - if ((!is_symbol_table && isThin) || object_fmt != NotObject) {
|
|
| 581 | - DEBUG_LOG("Member is an object file...loading...\n");
|
|
| 576 | + //if ((!is_symbol_table && isThin) || object_fmt != NotObject)
|
|
| 577 | + if (!is_symbol_table && !isImportLib)
|
|
| 578 | + {
|
|
| 579 | + DEBUG_LOG("Member might be an object file...loading...\n");
|
|
| 582 | 580 | |
| 583 | 581 | #if defined(darwin_HOST_OS) || defined(ios_HOST_OS)
|
| 584 | 582 | if (RTS_LINKER_USE_MMAP)
|
| 585 | 583 | image = mmapAnonForLinker(memberSize);
|
| 586 | 584 | else {
|
| 587 | 585 | /* See loadObj() */
|
| 588 | - misalignment = machoGetMisalignment(f);
|
|
| 586 | + if(!machoGetMisalignment(f, &misalignment))
|
|
| 587 | + DEBUG_LOG("Failed to load member as mach-o file. Skipping.\n");
|
|
| 588 | + continue;
|
|
| 589 | + }
|
|
| 589 | 590 | image = stgMallocBytes(memberSize + misalignment,
|
| 590 | 591 | "loadArchive(image)");
|
| 591 | 592 | image += misalignment;
|
| ... | ... | @@ -616,19 +617,23 @@ HsInt loadArchive_ (pathchar *path) |
| 616 | 617 | pathprintf(archiveMemberName, size+1, WSTR("%" PATH_FMT "(#%d:%.*s)"),
|
| 617 | 618 | path, memberIdx, (int)thisFileNameSize, fileName);
|
| 618 | 619 | |
| 620 | +///////////////////////////////////////////////////////////////
|
|
| 621 | +// Verfiy the object file is valid, and load it if appropriate.
|
|
| 622 | +///////////////////////////////////////////////////////////////
|
|
| 623 | + |
|
| 624 | + // Prepare headers, doesn't load any data yet.
|
|
| 619 | 625 | ObjectCode *oc = mkOc(STATIC_OBJECT, path, image, memberSize, false, archiveMemberName,
|
| 620 | 626 | misalignment);
|
| 621 | -#if defined(OBJFORMAT_MACHO)
|
|
| 622 | - ASSERT(object_fmt == MachO32 || object_fmt == MachO64);
|
|
| 623 | - ocInit_MachO( oc );
|
|
| 624 | -#endif
|
|
| 625 | -#if defined(OBJFORMAT_ELF)
|
|
| 626 | - ASSERT(object_fmt == ELF);
|
|
| 627 | - ocInit_ELF( oc );
|
|
| 628 | -#endif
|
|
| 629 | - |
|
| 630 | 627 | stgFree(archiveMemberName);
|
| 631 | 628 | |
| 629 | + if(!verifyAndInitOc( oc ))
|
|
| 630 | + {
|
|
| 631 | + freeObjectCode( oc );
|
|
| 632 | + IF_DEBUG(linker, ocDebugBelch(oc, "Faild to verify ... skipping."));
|
|
| 633 | + continue;
|
|
| 634 | + };
|
|
| 635 | + |
|
| 636 | + |
|
| 632 | 637 | if (0 == loadOc(oc)) {
|
| 633 | 638 | stgFree(fileName);
|
| 634 | 639 | fclose(f);
|
| ... | ... | @@ -1725,31 +1725,41 @@ ocRunFini_MachO ( ObjectCode *oc ) |
| 1725 | 1725 | /*
|
| 1726 | 1726 | * Figure out by how much to shift the entire Mach-O file in memory
|
| 1727 | 1727 | * when loading so that its single segment ends up 16-byte-aligned
|
| 1728 | + *
|
|
| 1729 | + * Returns 1 and sets misalignment_out to the detected misalignment i
|
|
| 1730 | + * f we successfully parsed the file.
|
|
| 1731 | + *
|
|
| 1732 | + * If we can't parse the file we set misalignment_out to 0 and return 0
|
|
| 1728 | 1733 | */
|
| 1729 | 1734 | int
|
| 1730 | -machoGetMisalignment( FILE * f )
|
|
| 1735 | +machoGetMisalignment( FILE * f, int* misalignment_out )
|
|
| 1731 | 1736 | {
|
| 1732 | 1737 | MachOHeader header;
|
| 1733 | 1738 | int misalignment;
|
| 1739 | + *misalignment_out = 0;
|
|
| 1734 | 1740 | |
| 1735 | 1741 | {
|
| 1736 | 1742 | size_t n = fread(&header, sizeof(header), 1, f);
|
| 1737 | 1743 | if (n != 1) {
|
| 1738 | - barf("machoGetMisalignment: can't read the Mach-O header");
|
|
| 1744 | + debugBelch("machoGetMisalignment: can't read the Mach-O header");
|
|
| 1745 | + return 0;
|
|
| 1739 | 1746 | }
|
| 1740 | 1747 | }
|
| 1741 | 1748 | fseek(f, -sizeof(header), SEEK_CUR);
|
| 1742 | 1749 | |
| 1743 | 1750 | if(header.magic != MH_MAGIC_64) {
|
| 1744 | - barf("Bad magic. Expected: %08x, got: %08x.",
|
|
| 1751 | + debugBelch("Bad magic. Expected: %08x, got: %08x.",
|
|
| 1745 | 1752 | MH_MAGIC_64, header.magic);
|
| 1753 | + return 0;
|
|
| 1746 | 1754 | }
|
| 1747 | 1755 | |
| 1748 | 1756 | misalignment = (header.sizeofcmds + sizeof(header))
|
| 1749 | 1757 | & 0xF;
|
| 1750 | 1758 | |
| 1751 | 1759 | IF_DEBUG(linker, debugBelch("mach-o misalignment %d\n", misalignment));
|
| 1752 | - return misalignment ? (16 - misalignment) : 0;
|
|
| 1760 | + misalignment ? (16 - misalignment) : 0;
|
|
| 1761 | + *misalignment_out = misalignment
|
|
| 1762 | + return 1;
|
|
| 1753 | 1763 | }
|
| 1754 | 1764 | |
| 1755 | 1765 | #endif /* darwin_HOST_OS || ios_HOST_OS */ |
| ... | ... | @@ -13,7 +13,7 @@ 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 * );
|
|
| 16 | +int machoGetMisalignment ( FILE *, int* );
|
|
| 17 | 17 | int ocAllocateExtras_MachO ( ObjectCode* oc );
|
| 18 | 18 | |
| 19 | 19 | SectionKind getSectionKind_MachO ( MachOSection *macho );
|
| ... | ... | @@ -775,6 +775,10 @@ COFF_OBJ_TYPE getObjectType ( char* image, pathchar* fileName ) |
| 775 | 775 | *************/
|
| 776 | 776 | COFF_HEADER_INFO* getHeaderInfo ( ObjectCode* oc )
|
| 777 | 777 | {
|
| 778 | + if((size_t) oc->fileSize < sizeof(IMAGE_FILE_HEADER)) {
|
|
| 779 | + errorBelch ("Supposed COFF file smaller than minimum header size.\n");
|
|
| 780 | + return NULL;
|
|
| 781 | + }
|
|
| 778 | 782 | COFF_OBJ_TYPE coff_type = getObjectType (oc->image, OC_INFORMATIVE_FILENAME(oc));
|
| 779 | 783 | |
| 780 | 784 | COFF_HEADER_INFO* info
|
| ... | ... | @@ -808,6 +812,11 @@ COFF_HEADER_INFO* getHeaderInfo ( ObjectCode* oc ) |
| 808 | 812 | stgFree (info);
|
| 809 | 813 | info = NULL;
|
| 810 | 814 | errorBelch ("Unknown COFF %d type in getHeaderInfo.", coff_type);
|
| 815 | + if(oc->archiveMemberName) {
|
|
| 816 | + errorBelch ("Archive %" PATH_FMT ".\n", oc->archiveMemberName);
|
|
| 817 | + }
|
|
| 818 | + errorBelch ("In %" PATH_FMT ".\n", oc->fileName);
|
|
| 819 | + |
|
| 811 | 820 | }
|
| 812 | 821 | break;
|
| 813 | 822 | }
|