diff --git a/src/linker/lnk.c b/src/linker/lnk.c index f03204b3..b0d2a380 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1722,6 +1722,7 @@ lnk_build_guard_tables(TP_Context *tp, internal void lnk_emit_base_reloc_info(Arena *arena, LNK_Section **sect_id_map, + B32 is_large_addr_aware, U64 page_size, HashTable *page_ht, LNK_BaseRelocPageList *page_list, @@ -1751,41 +1752,45 @@ lnk_emit_base_reloc_info(Arena *arena, } } - u64_list_push(arena, &page->v.entries, reloc_voff); + if (reloc->type == LNK_Reloc_ADDR_32) { + if (is_large_addr_aware) { + lnk_error(LNK_Error_LargeAddrAwareRequired, "found out of range ADDR32 relocation for '%S', link with /LARGEADDRESSAWARE:NO", reloc->symbol->name); + } else { + u64_list_push(arena, &page->v.entries_addr32, reloc_voff); + } + } else if (reloc->type == LNK_Reloc_ADDR_64) { + u64_list_push(arena, &page->v.entries_addr64, reloc_voff); + } } } internal THREAD_POOL_TASK_FUNC(lnk_emit_base_relocs_from_reloc_array_task) { - LNK_BaseRelocTask *task = raw_task; - Rng1U64 range = task->range_arr[task_id]; - LNK_BaseRelocPageList *page_list = &task->list_arr[task_id]; - HashTable *page_ht = task->page_ht_arr[task_id]; - + ProfBeginFunction(); + LNK_BaseRelocTask task = *(LNK_BaseRelocTask*)raw_task; + Rng1U64 range = task.range_arr[task_id]; for (U64 reloc_idx = range.min; reloc_idx < range.max; reloc_idx += 1) { - LNK_Reloc *reloc = task->reloc_arr[reloc_idx]; - lnk_emit_base_reloc_info(arena, task->sect_id_map, task->page_size, page_ht, page_list, reloc); + LNK_Reloc *reloc = task.reloc_arr[reloc_idx]; + lnk_emit_base_reloc_info(arena, task.sect_id_map, task.is_large_addr_aware, task.page_size, task.page_ht_arr[task_id], &task.list_arr[task_id], reloc); } + ProfEnd(); } internal THREAD_POOL_TASK_FUNC(lnk_emit_base_relocs_from_objs_task) { ProfBeginFunction(); - LNK_ObjBaseRelocTask *task = raw_task; - LNK_BaseRelocPageList *page_list = &task->list_arr[task_id]; - HashTable *page_ht = task->page_ht_arr[task_id]; - Rng1U64 range = task->ranges[task_id]; - + LNK_ObjBaseRelocTask task = *(LNK_ObjBaseRelocTask *)raw_task; + Rng1U64 range = task.ranges[task_id]; for (U64 obj_idx = range.min; obj_idx < range.max; ++obj_idx) { - LNK_Obj *obj = task->obj_arr[obj_idx]; + LNK_Obj *obj = task.obj_arr[obj_idx]; for (U64 sect_idx = 0; sect_idx < obj->sect_count; sect_idx += 1) { B32 is_live = !lnk_chunk_is_discarded(obj->chunk_arr[sect_idx]); if (is_live) { LNK_RelocList reloc_list = obj->sect_reloc_list_arr[sect_idx]; for (LNK_Reloc *reloc = reloc_list.first; reloc != 0; reloc = reloc->next) { - lnk_emit_base_reloc_info(arena, task->sect_id_map, task->page_size, page_ht, page_list, reloc); + lnk_emit_base_reloc_info(arena, task.sect_id_map, task.is_large_addr_aware, task.page_size, task.page_ht_arr[task_id], &task.list_arr[task_id], reloc); } } } @@ -1823,13 +1828,14 @@ lnk_base_reloc_page_array_sort(LNK_BaseRelocPageArray arr) } internal void -lnk_build_base_relocs(TP_Context *tp, - TP_Arena *tp_arena, - LNK_SectionTable *st, - LNK_SymbolTable *symtab, - COFF_MachineType machine, - U64 page_size, - LNK_ObjList obj_list) +lnk_build_base_relocs(TP_Context *tp, + TP_Arena *tp_arena, + LNK_SectionTable *st, + LNK_SymbolTable *symtab, + COFF_MachineType machine, + U64 page_size, + PE_ImageFileCharacteristics file_chars, + LNK_ObjList obj_list) { ProfBeginFunction(); @@ -1849,13 +1855,14 @@ lnk_build_base_relocs(TP_Context *tp, // emit pages from relocs defined in section table ProfBegin("Emit Relocs From Section Table"); for (LNK_SectionNode *sect_node = st->list.first; sect_node != 0; sect_node = sect_node->next) { - LNK_BaseRelocTask task = {0}; - task.page_size = page_size; - task.sect_id_map = sect_id_map; - task.list_arr = page_list_arr; - task.page_ht_arr = page_ht_arr; - task.reloc_arr = lnk_reloc_array_from_list(tp_arena->v[0], sect_node->data.reloc_list); - task.range_arr = tp_divide_work(tp_arena->v[0], sect_node->data.reloc_list.count, tp->worker_count); + LNK_BaseRelocTask task = {0}; + task.page_size = page_size; + task.sect_id_map = sect_id_map; + task.list_arr = page_list_arr; + task.page_ht_arr = page_ht_arr; + task.reloc_arr = lnk_reloc_array_from_list(tp_arena->v[0], sect_node->data.reloc_list); + task.range_arr = tp_divide_work(tp_arena->v[0], sect_node->data.reloc_list.count, tp->worker_count); + task.is_large_addr_aware = !!(file_chars & PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE); tp_for_parallel(tp, tp_arena, tp->worker_count, lnk_emit_base_relocs_from_reloc_array_task, &task); } ProfEnd(); @@ -1870,6 +1877,7 @@ lnk_build_base_relocs(TP_Context *tp, task.page_ht_arr = page_ht_arr; task.list_arr = page_list_arr; task.obj_arr = lnk_obj_arr_from_list(tp_arena->v[0], obj_list); + task.is_large_addr_aware = !!(file_chars & PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE); tp_for_parallel(tp, tp_arena, tp->worker_count, lnk_emit_base_relocs_from_objs_task, &task); } ProfEnd(); @@ -1892,7 +1900,8 @@ lnk_build_base_relocs(TP_Context *tp, // page exists concat voffs LNK_BaseRelocPageNode *page = is_page_present->value_raw; Assert(page != src_page); - u64_list_concat_in_place(&page->v.entries, &src_page->v.entries); + u64_list_concat_in_place(&page->v.entries_addr32, &src_page->v.entries_addr32); + u64_list_concat_in_place(&page->v.entries_addr64, &src_page->v.entries_addr64); } else { // push page to main list SLLQueuePush(main_page_list->first, main_page_list->last, src_page); @@ -1923,10 +1932,14 @@ lnk_build_base_relocs(TP_Context *tp, ProfBegin("Serialize Pages"); for (U64 page_idx = 0; page_idx < page_arr.count; ++page_idx) { LNK_BaseRelocPage *page = &page_arr.v[page_idx]; + + U64 total_entry_count = 0; + total_entry_count += page->entries_addr32.count; + total_entry_count += page->entries_addr64.count; // push buffer U64 buf_align = sizeof(U32); - U64 buf_size = AlignPow2(sizeof(U32)*2 + sizeof(U16)*page->entries.count, buf_align); + U64 buf_size = AlignPow2(sizeof(U32)*2 + sizeof(U16)*total_entry_count, buf_align); U8 *buf = push_array_no_zero(base_reloc_sect->arena, U8, buf_size); // setup pointers into buffer @@ -1935,8 +1948,22 @@ lnk_build_base_relocs(TP_Context *tp, U16 *reloc_arr_base = (U16*)(block_size_ptr + 1); U16 *reloc_arr_ptr = reloc_arr_base; - // write reloc array - for (U64Node *i = page->entries.first; i != 0; i = i->next) { + // write 32-bit relocations + for (U64Node *i = page->entries_addr32.first; i != 0; i = i->next) { + // was base reloc_entry made? + if (hash_table_search_u64(voff_ht, i->data)) { + continue; + } + hash_table_push_u64_u64(tp_arena->v[0], voff_ht, i->data, 0); + + // write entry + U64 rel_off = i->data - page->voff; + Assert(rel_off <= page_size); + *reloc_arr_ptr++ = PE_BaseRelocMake(PE_BaseRelocKind_HIGHLOW, rel_off); + } + + // write 64-bit relocations + for (U64Node *i = page->entries_addr64.first; i != 0; i = i->next) { // was base reloc entry made? if (hash_table_search_u64(voff_ht, i->data)) { continue; @@ -1950,7 +1977,7 @@ lnk_build_base_relocs(TP_Context *tp, } // write pad - U64 pad_reloc_count = AlignPadPow2(page->entries.count, sizeof(reloc_arr_ptr[0])); + U64 pad_reloc_count = AlignPadPow2(total_entry_count, sizeof(reloc_arr_ptr[0])); MemoryZeroTyped(reloc_arr_ptr, pad_reloc_count); // fill pad with PE_BaseRelocKind_ABSOLUTE reloc_arr_ptr += pad_reloc_count; @@ -2620,7 +2647,7 @@ lnk_apply_reloc(U64 base_addr, reloc_size = 2; } break; case LNK_Reloc_ADDR_32: { - reloc_value = safe_cast_u32(base_addr + symbol_voff); + reloc_value = (U32)(base_addr + symbol_voff); reloc_size = 4; } break; case LNK_Reloc_ADDR_64: { @@ -3872,7 +3899,7 @@ lnk_run(int argc, char **argv) } break; case State_BuildBaseRelocs: { ProfBegin("Base Relocs"); - lnk_build_base_relocs(tp, tp_arena, st, symtab, config->machine, config->page_size, obj_list); + lnk_build_base_relocs(tp, tp_arena, st, symtab, config->machine, config->page_size, config->file_characteristics, obj_list); ProfEnd(); } break; case State_FinalizeImage: { diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 9742570d..a1999a32 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -130,7 +130,8 @@ typedef struct LNK_InputImportList typedef struct LNK_BaseRelocPage { U64 voff; - U64List entries; + U64List entries_addr32; + U64List entries_addr64; } LNK_BaseRelocPage; typedef struct LNK_BaseRelocPageNode @@ -160,6 +161,7 @@ typedef struct Rng1U64 *range_arr; LNK_BaseRelocPageList *list_arr; HashTable **page_ht_arr; + B32 is_large_addr_aware; } LNK_BaseRelocTask; typedef struct @@ -170,6 +172,7 @@ typedef struct LNK_BaseRelocPageList *list_arr; LNK_Obj **obj_arr; HashTable **page_ht_arr; + B32 is_large_addr_aware; } LNK_ObjBaseRelocTask; typedef struct @@ -274,7 +277,7 @@ internal String8 lnk_make_linker_coff_obj(TP_Context *tp, Arena *arena, COFF_Tim internal void lnk_build_debug_pdb(LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_Section *debug_sect, LNK_Chunk *debug_dir_array_chunk, COFF_TimeStamp time_stamp, Guid guid, U32 age, String8 pdb_path); internal void lnk_build_debug_rdi(LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_Section *debug_sect, LNK_Chunk *debug_dir_array_chunk, COFF_TimeStamp time_stamp, Guid guid, String8 rdi_path); internal void lnk_build_guard_tables(TP_Context *tp, LNK_SectionTable *st, LNK_SymbolTable *symtab, LNK_ExportTable *exptab, LNK_ObjList obj_list, COFF_MachineType machine, String8 entry_point_name, LNK_GuardFlags guard_flags, B32 emit_suppress_flag); -internal void lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_arena, LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine, U64 page_size, LNK_ObjList obj_list); +internal void lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_arena, LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine, U64 page_size, PE_ImageFileCharacteristics file_chars, LNK_ObjList obj_list); internal LNK_Chunk * lnk_build_dos_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent_chunk); internal LNK_Chunk * lnk_build_pe_magic(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent); internal LNK_Chunk * lnk_build_coff_file_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent, COFF_MachineType machine, COFF_TimeStamp time_stamp, PE_ImageFileCharacteristics file_characteristics); diff --git a/src/linker/lnk_error.h b/src/linker/lnk_error.h index 8e1f2fb4..555a23ce 100644 --- a/src/linker/lnk_error.h +++ b/src/linker/lnk_error.h @@ -30,6 +30,7 @@ typedef enum LNK_Error_UnableToSerializeMsf, LNK_Error_LoadRes, LNK_Error_IO, + LNK_Error_LargeAddrAwareRequired, LNK_Error_StopLast, LNK_Error_First, diff --git a/src/linker/lnk_reloc.h b/src/linker/lnk_reloc.h index c814123a..11e69e3f 100644 --- a/src/linker/lnk_reloc.h +++ b/src/linker/lnk_reloc.h @@ -30,16 +30,16 @@ typedef enum typedef struct LNK_Reloc { - struct LNK_Reloc *next; - LNK_Chunk *chunk; - LNK_RelocType type; - U64 apply_off; + struct LNK_Reloc *next; + LNK_Chunk *chunk; + LNK_RelocType type; + U64 apply_off; struct LNK_Symbol *symbol; } LNK_Reloc; typedef struct LNK_RelocList { - U64 count; + U64 count; LNK_Reloc *first; LNK_Reloc *last; } LNK_RelocList;