Andreas Klebinger pushed to branch wip/andreask/linker_fix at Glasgow Haskell Compiler / GHC
Commits:
-
1a10f18c
by Andreas Klebinger at 2025-08-11T22:34:04+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,9 @@ 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 | + //machoGetMisalignment might fail to parse the header, but in that
|
|
1420 | + //case so will verifyAndInitOc so we leave cleanup to after verifyAndInitOc.
|
|
1419 | 1421 | image = stgMallocBytes(fileSize + misalignment, "loadObj(image)");
|
1420 | 1422 | image += misalignment;
|
1421 | 1423 | |
... | ... | @@ -1441,14 +1443,11 @@ preloadObjectFile (pathchar *path) |
1441 | 1443 | /* FIXME (AP): =mapped= parameter unconditionally set to true */
|
1442 | 1444 | oc = mkOc(STATIC_OBJECT, path, image, fileSize, true, NULL, misalignment);
|
1443 | 1445 | |
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
|
|
1446 | + if (!verifyAndInitOc(oc)) {
|
|
1447 | + freeObjectCode(oc);
|
|
1448 | + debugBelch("loadObj: Failed to verify oc.\n");
|
|
1449 | + return NULL;
|
|
1450 | + };
|
|
1452 | 1451 | return oc;
|
1453 | 1452 | }
|
1454 | 1453 | |
... | ... | @@ -1505,27 +1504,44 @@ HsInt loadObj (pathchar *path) |
1505 | 1504 | return r;
|
1506 | 1505 | }
|
1507 | 1506 | |
1507 | +// Call the relevant VeriffyImage_* and ocInit_* functions.
|
|
1508 | +// Return 1 on success.
|
|
1509 | +HsInt verifyAndInitOc (ObjectCode* oc)
|
|
1510 | +{
|
|
1511 | + int r;
|
|
1512 | + |
|
1513 | + IF_DEBUG(linker, ocDebugBelch(oc, "start\n"));
|
|
1514 | + |
|
1515 | + /* verify the in-memory image */
|
|
1516 | +#if defined(OBJFORMAT_ELF)
|
|
1517 | + r = ocVerifyImage_ELF ( oc );
|
|
1518 | + if(r) {
|
|
1519 | + ocInit_ELF( oc );
|
|
1520 | + }
|
|
1521 | +#elif defined(OBJFORMAT_PEi386)
|
|
1522 | + r = ocVerifyImage_PEi386 ( oc );
|
|
1523 | +#elif defined(OBJFORMAT_MACHO)
|
|
1524 | + r = ocVerifyImage_MachO ( oc );
|
|
1525 | + if(r) {
|
|
1526 | + ocInit_MachO( oc );
|
|
1527 | + }
|
|
1528 | +#else
|
|
1529 | + barf("loadObj: no verify method");
|
|
1530 | +#endif
|
|
1531 | + if (!r) {
|
|
1532 | + IF_DEBUG(linker, ocDebugBelch(oc, "ocVerifyImage_* failed\n"));
|
|
1533 | + return r;
|
|
1534 | + }
|
|
1535 | + return 1;
|
|
1536 | +}
|
|
1537 | + |
|
1538 | +// Precondition: oc already verified.
|
|
1508 | 1539 | HsInt loadOc (ObjectCode* oc)
|
1509 | 1540 | {
|
1510 | 1541 | int r;
|
1511 | 1542 | |
1512 | 1543 | IF_DEBUG(linker, ocDebugBelch(oc, "start\n"));
|
1513 | 1544 | |
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 | 1545 | /* Note [loadOc orderings]
|
1530 | 1546 | ~~~~~~~~~~~~~~~~~~~~~~~
|
1531 | 1547 | The order of `ocAllocateExtras` and `ocGetNames` matters. For MachO
|
... | ... | @@ -485,12 +485,18 @@ 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 | + |
|
494 | 500 | void initSegment(Segment *s, void *start, size_t size, SegmentProt prot, int n_sections);
|
495 | 501 | void freeSegments(ObjectCode *oc);
|
496 | 502 |
... | ... | @@ -110,51 +110,6 @@ 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 | - 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 | -}
|
|
157 | - |
|
158 | 113 | static bool readThinArchiveMember(int n, int memberSize, pathchar* path,
|
159 | 114 | char* fileName, char* image)
|
160 | 115 | {
|
... | ... | @@ -547,9 +502,11 @@ HsInt loadArchive_ (pathchar *path) |
547 | 502 | }
|
548 | 503 | |
549 | 504 | DEBUG_LOG("Found member file `%s'\n", fileName);
|
550 | - |
|
551 | 505 | bool is_symbol_table = strcmp("", fileName) == 0;
|
552 | - enum ObjectFileFormat object_fmt = is_symbol_table ? NotObject : identifyObjectFile(f);
|
|
506 | + |
|
507 | +/////////////////////////////////////////////////
|
|
508 | +// We found the member file. Load it into memory.
|
|
509 | +/////////////////////////////////////////////////
|
|
553 | 510 | |
554 | 511 | #if defined(OBJFORMAT_PEi386)
|
555 | 512 | /*
|
... | ... | @@ -569,17 +526,20 @@ HsInt loadArchive_ (pathchar *path) |
569 | 526 | #endif // windows
|
570 | 527 | |
571 | 528 | DEBUG_LOG("\tthisFileNameSize = %d\n", (int)thisFileNameSize);
|
572 | - DEBUG_LOG("\tisObject = %d\n", object_fmt);
|
|
573 | 529 | |
574 | - if ((!is_symbol_table && isThin) || object_fmt != NotObject) {
|
|
575 | - DEBUG_LOG("Member is an object file...loading...\n");
|
|
530 | + if (!is_symbol_table && !isImportLib)
|
|
531 | + {
|
|
532 | + DEBUG_LOG("Member might be an object file...loading...\n");
|
|
576 | 533 | |
577 | 534 | #if defined(darwin_HOST_OS) || defined(ios_HOST_OS)
|
578 | 535 | if (RTS_LINKER_USE_MMAP)
|
579 | 536 | image = mmapAnonForLinker(memberSize);
|
580 | 537 | else {
|
581 | 538 | /* See loadObj() */
|
582 | - misalignment = machoGetMisalignment(f);
|
|
539 | + if(!machoGetMisalignment(f, &misalignment))
|
|
540 | + DEBUG_LOG("Failed to load member as mach-o file. Skipping.\n");
|
|
541 | + continue;
|
|
542 | + }
|
|
583 | 543 | image = stgMallocBytes(memberSize + misalignment,
|
584 | 544 | "loadArchive(image)");
|
585 | 545 | image += misalignment;
|
... | ... | @@ -610,19 +570,23 @@ HsInt loadArchive_ (pathchar *path) |
610 | 570 | pathprintf(archiveMemberName, size+1, WSTR("%" PATH_FMT "(#%d:%.*s)"),
|
611 | 571 | path, memberIdx, (int)thisFileNameSize, fileName);
|
612 | 572 | |
573 | +///////////////////////////////////////////////////////////////
|
|
574 | +// Verfiy the object file is valid, and load it if appropriate.
|
|
575 | +///////////////////////////////////////////////////////////////
|
|
576 | + |
|
577 | + // Prepare headers, doesn't load any data yet.
|
|
613 | 578 | ObjectCode *oc = mkOc(STATIC_OBJECT, path, image, memberSize, false, archiveMemberName,
|
614 | 579 | misalignment);
|
615 | -#if defined(OBJFORMAT_MACHO)
|
|
616 | - ASSERT(object_fmt == MachO32 || object_fmt == MachO64);
|
|
617 | - ocInit_MachO( oc );
|
|
618 | -#endif
|
|
619 | -#if defined(OBJFORMAT_ELF)
|
|
620 | - ASSERT(object_fmt == ELF);
|
|
621 | - ocInit_ELF( oc );
|
|
622 | -#endif
|
|
623 | - |
|
624 | 580 | stgFree(archiveMemberName);
|
625 | 581 | |
582 | + if(!verifyAndInitOc( oc ))
|
|
583 | + {
|
|
584 | + freeObjectCode( oc );
|
|
585 | + IF_DEBUG(linker, ocDebugBelch(oc, "Faild to verify ... skipping."));
|
|
586 | + continue;
|
|
587 | + };
|
|
588 | + |
|
589 | + |
|
626 | 590 | if (0 == loadOc(oc)) {
|
627 | 591 | stgFree(fileName);
|
628 | 592 | 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 if
|
|
1730 | + * 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 = 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 | }
|