Module: wine Branch: master Commit: 0a3a1d2b034cbdc0f6d0931bd710e4e461f5149c URL: https://gitlab.winehq.org/wine/wine/-/commit/0a3a1d2b034cbdc0f6d0931bd710e4e...
Author: Alexandre Julliard julliard@winehq.org Date: Tue May 9 12:28:40 2023 +0200
ntdll: Apply dynamic relocations when mapping an ARM64X binary.
---
dlls/ntdll/unix/virtual.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 7769d2c31f5..b048d0f52d2 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -2177,6 +2177,113 @@ static NTSTATUS map_pe_header( void *ptr, size_t size, int fd, BOOL *removable ) return STATUS_SUCCESS; /* page protections will be updated later */ }
+#ifdef __aarch64__ + +/*********************************************************************** + * apply_arm64x_relocations + */ +static void apply_arm64x_relocations( char *base, const IMAGE_BASE_RELOCATION *reloc, size_t size ) +{ + const IMAGE_BASE_RELOCATION *reloc_end = (const IMAGE_BASE_RELOCATION *)((const char *)reloc + size); + + while (reloc < reloc_end - 1 && reloc->SizeOfBlock) + { + const USHORT *rel = (const USHORT *)(reloc + 1); + const USHORT *rel_end = (const USHORT *)reloc + reloc->SizeOfBlock / sizeof(USHORT); + char *page = base + reloc->VirtualAddress; + + while (rel < rel_end && *rel) + { + USHORT offset = *rel & 0xfff; + USHORT type = (*rel >> 12) & 3; + USHORT arg = *rel >> 14; + int val; + rel++; + switch (type) + { + case IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL: + memset( page + offset, 0, 1 << arg ); + break; + case IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE: + memcpy( page + offset, rel, 1 << arg ); + rel += (1 << arg) / sizeof(USHORT); + break; + case IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA: + val = (unsigned int)*rel++ * ((arg & 2) ? 8 : 4); + if (arg & 1) val = -val; + *(int *)(page + offset) += val; + break; + } + } + reloc = (const IMAGE_BASE_RELOCATION *)rel_end; + } +} + + +/*********************************************************************** + * update_arm64x_mapping + */ +static void update_arm64x_mapping( char *base, IMAGE_NT_HEADERS *nt, IMAGE_SECTION_HEADER *sections ) +{ + ULONG size, sec, offset; + const IMAGE_DATA_DIRECTORY *dir; + const IMAGE_LOAD_CONFIG_DIRECTORY *cfg; + const IMAGE_DYNAMIC_RELOCATION_TABLE *table; + const char *ptr, *end; + + /* retrieve config directory */ + + if (nt->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) return; + dir = nt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG; + if (!dir->VirtualAddress || !dir->Size) return; + cfg = (void *)(base + dir->VirtualAddress); + size = min( dir->Size, cfg->Size ); + + /* apply dynamic relocations */ + + if (size <= offsetof( IMAGE_LOAD_CONFIG_DIRECTORY, DynamicValueRelocTableSection )) return; + offset = cfg->DynamicValueRelocTableOffset; + sec = cfg->DynamicValueRelocTableSection; + if (!sec || sec > nt->FileHeader.NumberOfSections) return; + if (offset >= sections[sec - 1].Misc.VirtualSize) return; + table = (const IMAGE_DYNAMIC_RELOCATION_TABLE *)(base + sections[sec - 1].VirtualAddress + offset); + ptr = (const char *)(table + 1); + end = ptr + table->Size; + switch (table->Version) + { + case 1: + while (ptr < end) + { + const IMAGE_DYNAMIC_RELOCATION64 *dyn = (const IMAGE_DYNAMIC_RELOCATION64 *)ptr; + if (dyn->Symbol == IMAGE_DYNAMIC_RELOCATION_ARM64X) + { + apply_arm64x_relocations( base, (const IMAGE_BASE_RELOCATION *)(dyn + 1), + dyn->BaseRelocSize ); + break; + } + ptr += sizeof(*dyn) + dyn->BaseRelocSize; + } + break; + case 2: + while (ptr < end) + { + const IMAGE_DYNAMIC_RELOCATION64_V2 *dyn = (const IMAGE_DYNAMIC_RELOCATION64_V2 *)ptr; + if (dyn->Symbol == IMAGE_DYNAMIC_RELOCATION_ARM64X) + { + apply_arm64x_relocations( base, (const IMAGE_BASE_RELOCATION *)(dyn + 1), + dyn->FixupInfoSize ); + break; + } + ptr += dyn->HeaderSize + dyn->FixupInfoSize; + } + break; + default: + FIXME( "unsupported version %u\n", table->Version ); + break; + } +} + +#endif /* __aarch64__ */
/*********************************************************************** * map_image_into_view @@ -2342,6 +2449,12 @@ static NTSTATUS map_image_into_view( struct file_view *view, const WCHAR *filena } }
+#ifdef __aarch64__ + if (main_image_info.Machine == IMAGE_FILE_MACHINE_AMD64 && + nt->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64) + update_arm64x_mapping( ptr, nt, sections ); +#endif + /* set the image protections */
set_vprot( view, ptr, ROUND_SIZE( 0, header_size ), VPROT_COMMITTED | VPROT_READ );