@@ -716,32 +716,49 @@ class ExportOrdinalChunk : public NonSectionChunk {
716
716
void IdataContents::create (COFFLinkerContext &ctx) {
717
717
std::vector<std::vector<DefinedImportData *>> v = binImports (ctx, imports);
718
718
719
- // Merge compatible EC and native import files in hybrid images.
719
+ // In hybrid images, EC and native code are usually very similar,
720
+ // resulting in a highly similar set of imported symbols. Consequently,
721
+ // their import tables can be shared, with ARM64X relocations handling any
722
+ // differences. Identify matching import files used by EC and native code, and
723
+ // merge them into a single hybrid import entry.
720
724
if (ctx.hybridSymtab ) {
721
725
for (std::vector<DefinedImportData *> &syms : v) {
722
- // At this point, symbols are sorted by base name, ensuring that
723
- // compatible import files, if present, are adjacent.
724
726
std::vector<DefinedImportData *> hybridSyms;
725
727
ImportFile *prev = nullptr ;
726
728
for (DefinedImportData *sym : syms) {
727
729
ImportFile *file = sym->file ;
730
+ // At this stage, symbols are sorted by base name, ensuring that
731
+ // compatible import files, if present, are adjacent. Check if the
732
+ // current symbol's file imports the same symbol as the previously added
733
+ // one (if any and if it was not already merged). Additionally, verify
734
+ // that one of them is native while the other is EC. In rare cases,
735
+ // separate matching import entries may exist within the same namespace,
736
+ // which cannot be merged.
728
737
if (!prev || file->isEC () == prev->isEC () ||
729
738
!file->isSameImport (prev)) {
739
+ // We can't merge the import file, just add it to hybridSyms
740
+ // and set prev to its file so that we can try to match the next
741
+ // symbol.
730
742
hybridSyms.push_back (sym);
731
743
prev = file;
732
744
continue ;
733
745
}
734
746
735
- // The native variant exposes a subset of EC symbols and chunks. Use the
736
- // EC variant to represent both.
747
+ // A matching symbol may appear in syms in any order. The native variant
748
+ // exposes a subset of EC symbols and chunks, so always use the EC
749
+ // variant as the hybrid import file. If the native file was already
750
+ // added, replace it with the EC symbol in hybridSyms. Otherwise, the EC
751
+ // variant is already pushed, so we can simply merge it.
737
752
if (file->isEC ()) {
738
753
hybridSyms.pop_back ();
739
754
hybridSyms.push_back (sym);
740
755
}
741
756
757
+ // Merge import files by storing their hybrid form in the corresponding
758
+ // file class.
742
759
prev->hybridFile = file;
743
760
file->hybridFile = prev;
744
- prev = nullptr ;
761
+ prev = nullptr ; // A hybrid import file cannot be merged again.
745
762
}
746
763
747
764
// Sort symbols by type: native-only files first, followed by merged
@@ -780,11 +797,15 @@ void IdataContents::create(COFFLinkerContext &ctx) {
780
797
}
781
798
782
799
// Detect the first EC-only import in the hybrid IAT. Emit null chunks
783
- // and add an ARM64X relocation to replace it with the import for the EC
784
- // view. Additionally, use the original chunks as import terminators
785
- // and zero them with ARM64X relocations. Since these chunks appear
786
- // after the null terminator in the native view, they are always ignored
787
- // by the loader. However, MSVC emits them for some reason.
800
+ // as a terminator for the native view, and add an ARM64X relocation to
801
+ // replace it with the correct import for the EC view.
802
+ //
803
+ // Additionally, for MSVC compatibility, store the lookup and address
804
+ // chunks and append them at the end of EC-only imports, where a null
805
+ // terminator chunk would typically be placed. Since they appear after
806
+ // the native terminator, they will be ignored in the native view.
807
+ // In the EC view, they should act as terminators, so emit ZEROFILL
808
+ // relocations overriding them.
788
809
if (ctx.hybridSymtab && !lookupsTerminator && s->file ->isEC () &&
789
810
!s->file ->hybridFile ) {
790
811
lookupsTerminator = lookupsChunk;
@@ -846,8 +867,8 @@ void IdataContents::create(COFFLinkerContext &ctx) {
846
867
dirs.push_back (dir);
847
868
848
869
if (ctx.hybridSymtab ) {
849
- // If native-only imports exist, emit ARM64X relocations, skipping them in
850
- // the EC view.
870
+ // If native-only imports exist, they will appear as a prefix to all
871
+ // imports. Emit ARM64X relocations to skip them in the EC view.
851
872
uint32_t nativeOnly =
852
873
llvm::find_if (syms,
853
874
[](DefinedImportData *s) { return s->file ->isEC (); }) -
0 commit comments