diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp index 115e3457db697..ff3c89884c24d 100644 --- a/lld/COFF/Chunks.cpp +++ b/lld/COFF/Chunks.cpp @@ -1183,7 +1183,7 @@ size_t Arm64XDynamicRelocEntry::getSize() const { void Arm64XDynamicRelocEntry::writeTo(uint8_t *buf) const { auto out = reinterpret_cast(buf); - *out = (offset & 0xfff) | (type << 12); + *out = (offset.get() & 0xfff) | (type << 12); switch (type) { case IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE: @@ -1211,14 +1211,19 @@ void Arm64XDynamicRelocEntry::writeTo(uint8_t *buf) const { void DynamicRelocsChunk::finalize() { llvm::stable_sort(arm64xRelocs, [=](const Arm64XDynamicRelocEntry &a, const Arm64XDynamicRelocEntry &b) { - return a.offset < b.offset; + return a.offset.get() < b.offset.get(); }); - size = sizeof(coff_dynamic_reloc_table) + sizeof(coff_dynamic_relocation64) + - sizeof(coff_base_reloc_block_header); + size = sizeof(coff_dynamic_reloc_table) + sizeof(coff_dynamic_relocation64); + uint32_t prevPage = 0xfff; for (const Arm64XDynamicRelocEntry &entry : arm64xRelocs) { - assert(!(entry.offset & ~0xfff)); // Not yet supported. + uint32_t page = entry.offset.get() & ~0xfff; + if (page != prevPage) { + size = alignTo(size, sizeof(uint32_t)) + + sizeof(coff_base_reloc_block_header); + prevPage = page; + } size += entry.getSize(); } @@ -1235,17 +1240,31 @@ void DynamicRelocsChunk::writeTo(uint8_t *buf) const { header->Symbol = IMAGE_DYNAMIC_RELOCATION_ARM64X; buf += sizeof(*header); - auto pageHeader = reinterpret_cast(buf); - pageHeader->BlockSize = sizeof(*pageHeader); + coff_base_reloc_block_header *pageHeader = nullptr; + size_t relocSize = 0; for (const Arm64XDynamicRelocEntry &entry : arm64xRelocs) { - entry.writeTo(buf + pageHeader->BlockSize); - pageHeader->BlockSize += entry.getSize(); + uint32_t page = entry.offset.get() & ~0xfff; + if (!pageHeader || page != pageHeader->PageRVA) { + relocSize = alignTo(relocSize, sizeof(uint32_t)); + if (pageHeader) + pageHeader->BlockSize = + buf + relocSize - reinterpret_cast(pageHeader); + pageHeader = + reinterpret_cast(buf + relocSize); + pageHeader->PageRVA = page; + relocSize += sizeof(*pageHeader); + } + + entry.writeTo(buf + relocSize); + relocSize += entry.getSize(); } - pageHeader->BlockSize = alignTo(pageHeader->BlockSize, sizeof(uint32_t)); + relocSize = alignTo(relocSize, sizeof(uint32_t)); + pageHeader->BlockSize = + buf + relocSize - reinterpret_cast(pageHeader); - header->BaseRelocSize = pageHeader->BlockSize; - table->Size += header->BaseRelocSize; - assert(size == sizeof(*table) + sizeof(*header) + header->BaseRelocSize); + header->BaseRelocSize = relocSize; + table->Size += relocSize; + assert(size == sizeof(*table) + sizeof(*header) + relocSize); } } // namespace lld::coff diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h index 46fd8e21dce65..7ba58e336451f 100644 --- a/lld/COFF/Chunks.h +++ b/lld/COFF/Chunks.h @@ -851,13 +851,13 @@ class Arm64XRelocVal { class Arm64XDynamicRelocEntry { public: Arm64XDynamicRelocEntry(llvm::COFF::Arm64XFixupType type, uint8_t size, - uint32_t offset, Arm64XRelocVal value) + Arm64XRelocVal offset, Arm64XRelocVal value) : offset(offset), value(value), type(type), size(size) {} size_t getSize() const; void writeTo(uint8_t *buf) const; - uint32_t offset; + Arm64XRelocVal offset; Arm64XRelocVal value; private: @@ -873,8 +873,8 @@ class DynamicRelocsChunk : public NonSectionChunk { void writeTo(uint8_t *buf) const override; void finalize(); - void add(llvm::COFF::Arm64XFixupType type, uint8_t size, uint32_t offset, - Arm64XRelocVal value) { + void add(llvm::COFF::Arm64XFixupType type, uint8_t size, + Arm64XRelocVal offset, Arm64XRelocVal value) { arm64xRelocs.emplace_back(type, size, offset, value); } diff --git a/lld/COFF/Symbols.cpp b/lld/COFF/Symbols.cpp index 148822fdb68ff..fce50d41a663b 100644 --- a/lld/COFF/Symbols.cpp +++ b/lld/COFF/Symbols.cpp @@ -100,7 +100,6 @@ bool Symbol::isLive() const { return true; } -// MinGW specific. void Symbol::replaceKeepingName(Symbol *other, size_t size) { StringRef origName = getName(); memcpy(this, other, size); diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 8247f131dcf07..536c1eef5e49c 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -2352,6 +2352,20 @@ void Writer::setECSymbols() { delayIatCopySym, "__hybrid_auxiliary_delayload_iat_copy", delayIdata.getAuxIatCopy().empty() ? nullptr : delayIdata.getAuxIatCopy().front()); + + if (ctx.hybridSymtab) { + // For the hybrid image, set the alternate entry point to the EC entry + // point. In the hybrid view, it is swapped to the native entry point + // using ARM64X relocations. + if (auto altEntrySym = cast_or_null(ctx.hybridSymtab->entry)) { + // If the entry is an EC export thunk, use its target instead. + if (auto thunkChunk = + dyn_cast(altEntrySym->getChunk())) + altEntrySym = thunkChunk->target; + symtab->findUnderscore("__arm64x_native_entrypoint") + ->replaceKeepingName(altEntrySym, sizeof(SymbolUnion)); + } + } } // Write section contents to a mmap'ed file. @@ -2586,12 +2600,23 @@ void Writer::createDynamicRelocs() { coffHeaderOffset + offsetof(coff_file_header, Machine), AMD64); - if (ctx.symtab.entry != ctx.hybridSymtab->entry) + if (ctx.symtab.entry != ctx.hybridSymtab->entry) { ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t), peHeaderOffset + offsetof(pe32plus_header, AddressOfEntryPoint), cast_or_null(ctx.hybridSymtab->entry)); + // Swap the alternate entry point in the CHPE metadata. + Symbol *s = ctx.hybridSymtab->findUnderscore("__chpe_metadata"); + if (auto chpeSym = cast_or_null(s)) + ctx.dynamicRelocs->add( + IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t), + Arm64XRelocVal(chpeSym, offsetof(chpe_metadata, AlternateEntryPoint)), + cast_or_null(ctx.symtab.entry)); + else + Warn(ctx) << "'__chpe_metadata' is missing for ARM64X target"; + } + // Set the hybrid load config to the EC load config. ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t), dataDirOffset64 + diff --git a/lld/test/COFF/arm64x-entry.test b/lld/test/COFF/arm64x-entry.test index d5363c66544a5..1c2e7e7a0c93a 100644 --- a/lld/test/COFF/arm64x-entry.test +++ b/lld/test/COFF/arm64x-entry.test @@ -3,12 +3,14 @@ RUN: split-file %s %t.dir && cd %t.dir RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-dllmain.s -o arm64ec-dllmain.obj RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-dllmain.s -o arm64-dllmain.obj +RUN: llvm-mc -filetype=obj -triple=x86_64-windows amd64-dllmain.s -o amd64-dllmain.obj RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-func.s -o arm64ec-func.obj RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-func.s -o arm64-func.obj RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64-drectve.s -o arm64ec-drectve.obj RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-drectve.s -o arm64-drectve.obj RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj +RUN: llvm-mc -filetype=obj -triple=arm64ec-windows loadconfig-min.s -o loadconfig-min.obj RUN: lld-link -machine:arm64x -dll -out:out.dll arm64ec-dllmain.obj arm64-dllmain.obj \ RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj @@ -34,10 +36,12 @@ DISASM-NEXT: 180003009: e9 f2 ef ff ff jmp 0x180002000 <.text+ DISASM-NEXT: 18000300e: cc int3 DISASM-NEXT: 18000300f: cc int3 -RUN: llvm-readobj --headers out.dll | FileCheck --check-prefix=READOBJ %s +RUN: llvm-readobj --headers --coff-load-config out.dll | FileCheck --check-prefix=READOBJ %s READOBJ: AddressOfEntryPoint: 0x1000 +READOBJ: AlternateEntryPoint: 0x2000 READOBJ: HybridObject { READOBJ: AddressOfEntryPoint: 0x3000 +READOBJ: AlternateEntryPoint: 0x1000 READOBJ: } RUN: lld-link -machine:arm64x -dll -out:out2.dll arm64ec-func.obj arm64-func.obj \ @@ -55,6 +59,20 @@ RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj -entry:func RUN: llvm-objdump -d out4.dll | FileCheck --check-prefix=DISASM %s RUN: llvm-readobj --headers --coff-load-config out4.dll | FileCheck --check-prefix=READOBJ %s +RUN: lld-link -machine:arm64x -dll -out:out-x86.dll amd64-dllmain.obj arm64-dllmain.obj \ +RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj +RUN: llvm-readobj --headers --coff-load-config out-x86.dll | FileCheck --check-prefix=READOBJ-X86 %s +READOBJ-X86: AddressOfEntryPoint: 0x1000 +READOBJ-X86: AlternateEntryPoint: 0x2000 +READOBJ-X86: HybridObject { +READOBJ-X86: AddressOfEntryPoint: 0x2000 +READOBJ-X86: AlternateEntryPoint: 0x1000 +READOBJ-X86: } + +RUN: lld-link -machine:arm64x -dll -out:out-warn.dll arm64ec-dllmain.obj arm64-dllmain.obj \ +RUN: loadconfig-arm64.obj loadconfig-min.obj 2>&1 | FileCheck --check-prefix=WARN %s +WARN: lld-link: warning: '__chpe_metadata' is missing for ARM64X target + #--- arm64-dllmain.s .section .text,"xr",discard,_DllMainCRTStartup .globl _DllMainCRTStartup @@ -87,6 +105,56 @@ func: mov w0, #2 ret +#--- amd64-dllmain.s + .section .text,"xr",discard,_DllMainCRTStartup + .globl _DllMainCRTStartup + .p2align 2 +_DllMainCRTStartup: + movl $3, %eax + retq + #--- arm64-drectve.s .section .drectve .ascii "-entry:func" + +#--- loadconfig-min.s + .section .rdata,"dr" + .globl _load_config_used + .p2align 3, 0 +_load_config_used: + .word 0x140 + .fill 0xc4,1,0 + .xword chpe_metadata + .fill 0x70,1,0 + + .p2align 3, 0 +chpe_metadata: + .word 2 + .rva __hybrid_code_map + .word __hybrid_code_map_count + .rva __x64_code_ranges_to_entry_points + .rva __arm64x_redirection_metadata + .word 0 // __os_arm64x_dispatch_call_no_redirect + .word 0 // __os_arm64x_dispatch_ret + .word 0 // __os_arm64x_check_call + .word 0 // __os_arm64x_check_icall + .word 0 // __os_arm64x_check_icall_cfg + .rva __arm64x_native_entrypoint + .rva __hybrid_auxiliary_iat + .word __x64_code_ranges_to_entry_points_count + .word __arm64x_redirection_metadata_count + .word 0 // __os_arm64x_get_x64_information + .word 0 // __os_arm64x_set_x64_information + .rva __arm64x_extra_rfe_table + .word __arm64x_extra_rfe_table_size + .word 0 // __os_arm64x_dispatch_fptr + .rva __hybrid_auxiliary_iat_copy + .rva __hybrid_auxiliary_delayload_iat + .rva __hybrid_auxiliary_delayload_iat_copy + .word __hybrid_image_info_bitfield + .word 0 // __os_arm64x_helper3 + .word 0 // __os_arm64x_helper4 + .word 0 // __os_arm64x_helper5 + .word 0 // __os_arm64x_helper6 + .word 0 // __os_arm64x_helper7 + .word 0 // __os_arm64x_helper8