diff --git a/src/coff/coff.c b/src/coff/coff.c index bc2ead98..12108b38 100644 --- a/src/coff/coff.c +++ b/src/coff/coff.c @@ -224,7 +224,7 @@ coff_section_header_from_num(String8 data, U64 section_headers_off, U64 n) } internal String8 -coff_section_header_get_name(COFF_SectionHeader *header, String8 coff_data, U64 string_table_base) +coff_name_from_section_header(COFF_SectionHeader *header, String8 coff_data, U64 string_table_base) { U64 size = 0; for (; size < sizeof(header->name); size += 1) { @@ -904,129 +904,171 @@ coff_is_thin_archive(String8 data) return is_archive; } -internal U64 -coff_read_archive_member_header(String8 data, U64 offset, COFF_ArchiveMemberHeader *header_out) +internal COFF_ArchiveType +coff_archive_type_from_data(String8 data) { -#define NAME_SIZE 16 -#define DATE_SIZE 12 -#define USER_ID_SIZE 6 -#define GROUP_ID_SIZE 6 -#define MODE_SIZE 8 -#define SIZE_SIZE 10 -#define TOTAL_SIZE (NAME_SIZE + DATE_SIZE + USER_ID_SIZE + GROUP_ID_SIZE + MODE_SIZE + SIZE_SIZE) - - if (str8_deserial_get_raw_ptr(data, offset, TOTAL_SIZE) == NULL) { - return 0; + if (coff_is_archive(data)) { + return COFF_Archive_Regular; + } else if (coff_is_thin_archive(data)) { + return COFF_Archive_Thin; } - - U64 read_offset = offset; - - U8 *name = (U8 *)str8_deserial_get_raw_ptr(data, read_offset, NAME_SIZE); - read_offset += NAME_SIZE; - - U8 *date = (U8 *)str8_deserial_get_raw_ptr(data, read_offset, DATE_SIZE); - read_offset += DATE_SIZE; - - U8 *user_id = (U8 *)str8_deserial_get_raw_ptr(data, read_offset, USER_ID_SIZE); - read_offset += USER_ID_SIZE; - - U8 *group_id = (U8 *)str8_deserial_get_raw_ptr(data, read_offset, GROUP_ID_SIZE); - read_offset += GROUP_ID_SIZE; - - U8 *mode = (U8 *)str8_deserial_get_raw_ptr(data, read_offset, MODE_SIZE); - read_offset += MODE_SIZE; - - U8 *size = (U8 *)str8_deserial_get_raw_ptr(data, read_offset, SIZE_SIZE); - read_offset += SIZE_SIZE; - - U8 end[] = { 0, 0 }; - read_offset += str8_deserial_read_array(data, read_offset, &end[0], ArrayCount(end)); - - U64 i; - for (i = 0; i < NAME_SIZE; ++i) { - if (name[i] == ' ') { - break; - } - } - header_out->name = str8(name, i); - header_out->date = (U32)s64_from_str8(str8(date, DATE_SIZE), 10); - header_out->user_id = (U32)s64_from_str8(str8(user_id, USER_ID_SIZE), 10); - header_out->group_id = (U32)s64_from_str8(str8(group_id, GROUP_ID_SIZE), 10); - header_out->mode = str8(mode, MODE_SIZE); - for (i = 0; i < SIZE_SIZE; ++i) { - if (size[i] == ' ') { - break; - } - } - header_out->size = (U32)s64_from_str8(str8(size, i), 10); - header_out->is_end_correct = (end[0] == '`' && end[1] == '\n'); - - U64 result = (read_offset - offset); - return result; - -#undef NAME_SIZE -#undef DATE_SIZE -#undef USER_ID_SIZE -#undef GROUP_ID_SIZE -#undef MODE_SIZE -#undef SIZE_SIZE -#undef TOTAL_SIZE -} - -internal COFF_ArchiveMember -coff_read_archive_member(String8 data, U64 offset) -{ - COFF_ArchiveMember member; MemoryZeroStruct(&member); - coff_archive_member_iter_next(data, &offset, &member); - return member; -} - -internal COFF_ArchiveMember -coff_archive_member_from_data(String8 data) -{ - return coff_read_archive_member(data, 0); + return COFF_Archive_Null; } internal U64 -coff_read_archive_import(String8 data, U64 offset, COFF_ImportHeader *header_out) +coff_parse_archive_member_header(String8 data, U64 offset, B32 is_regular_archive, COFF_ArchiveMemberHeader *header_out) { + static const U64 name_size = 16; + static const U64 date_size = 12; + static const U64 user_id_size = 6; + static const U64 group_id_size = 6; + static const U64 mode_size = 8; + static const U64 size_size = 10; + static const String8 end_magic = str8_lit_comp("`\n"); + U64 total_header_size = name_size + date_size + user_id_size + group_id_size + mode_size + size_size + end_magic.size; + U64 cursor = offset; - - cursor += str8_deserial_read_struct(data, cursor, &header_out->sig1); - cursor += str8_deserial_read_struct(data, cursor, &header_out->sig2); - cursor += str8_deserial_read_struct(data, cursor, &header_out->version); - cursor += str8_deserial_read_struct(data, cursor, &header_out->machine); - cursor += str8_deserial_read_struct(data, cursor, &header_out->time_stamp); - cursor += str8_deserial_read_struct(data, cursor, &header_out->data_size); - cursor += str8_deserial_read_struct(data, cursor, &header_out->hint); - - U16 flags = 0; - cursor += str8_deserial_read_struct(data, cursor, &flags); - header_out->type = COFF_IMPORT_HEADER_GET_TYPE(flags); - header_out->name_type = COFF_IMPORT_HEADER_GET_NAME_TYPE(flags); - - header_out->func_name = str8(0,0); - cursor += str8_deserial_read_cstr(data, cursor, &header_out->func_name); - - header_out->dll_name = str8(0,0); - cursor += str8_deserial_read_cstr(data, cursor, &header_out->dll_name); - - Assert(header_out->func_name.size + header_out->dll_name.size + /* nulls */ 2 == header_out->data_size); - - U64 read_size = cursor - offset; - return read_size; + if (cursor + total_header_size <= data.size) { + String8 name = str8_zero(); + String8 date = str8_zero(); + String8 user_id = str8_zero(); + String8 group_id = str8_zero(); + String8 mode = str8_zero(); + String8 size = str8_zero(); + String8 end = str8_zero(); + + cursor += str8_deserial_read_block(data, cursor, name_size, &name ); + cursor += str8_deserial_read_block(data, cursor, date_size, &date ); + cursor += str8_deserial_read_block(data, cursor, user_id_size, &user_id ); + cursor += str8_deserial_read_block(data, cursor, group_id_size, &group_id); + cursor += str8_deserial_read_block(data, cursor, mode_size, &mode ); + cursor += str8_deserial_read_block(data, cursor, size_size, &size ); + cursor += str8_deserial_read_block(data, cursor, 2, &end ); + + name = str8_skip_chop_whitespace(name); + date = str8_skip_chop_whitespace(date); + user_id = str8_skip_chop_whitespace(user_id); + group_id = str8_skip_chop_whitespace(group_id); + mode = str8_skip_chop_whitespace(mode); + size = str8_skip_chop_whitespace(size); + + header_out->name = name; + header_out->time_stamp = s32_from_str8(date, 10); + header_out->user_id = s32_from_str8(user_id, 10); + header_out->group_id = s32_from_str8(group_id, 10); + header_out->mode = mode; + header_out->is_end_correct = str8_match(end, end_magic, 0); + header_out->data_range = rng_1u64(cursor, cursor + u32_from_str8(size, 10)); + + if (is_regular_archive) { + cursor = header_out->data_range.max; + } + } + + U64 result = AlignPow2((cursor - offset), COFF_ARCHIVE_ALIGN); + return result; } -internal COFF_ImportHeader -coff_archive_import_from_data(String8 data) +internal B32 +coff_parse_archive_member_data(String8 data, U64 cursor, COFF_ArchiveMember *member_out) { - COFF_ImportHeader header; MemoryZeroStruct(&header); - coff_read_archive_import(data, 0, &header); - return header; + B32 is_parsed = 0; + + COFF_ArchiveMemberHeader header; header.is_end_correct = 0; + coff_parse_archive_member_header(data, cursor, 1, &header); + + if (header.is_end_correct) { + member_out->header = header; + member_out->offset = cursor; + member_out->data = str8_substr(data, header.data_range); + + cursor = AlignPow2(header.data_range.max, COFF_ARCHIVE_ALIGN); + + is_parsed = 1; + } else { + MemoryZeroStruct(&member_out->header); + member_out->offset = max_U64; + member_out->data = str8_zero(); + } + + return is_parsed; +} + +internal COFF_ArchiveFirstMember +coff_parse_first_archive_member(COFF_ArchiveMember *member) +{ + Assert(str8_match(member->header.name, str8_lit("/"), 0)); + + U64 cursor = 0; + + U32 symbol_count = 0; + cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count); + + symbol_count = from_be_u32(symbol_count); + + Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U32)); + cursor += dim_1u64(member_offsets_range); + + Rng1U64 string_table_range = rng_1u64(cursor, member->data.size); + cursor += dim_1u64(string_table_range); + + String8 raw_member_offsets = str8_substr(member->data, member_offsets_range); + U32 *member_offsets = (U32 *)raw_member_offsets.str; + U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]); + + COFF_ArchiveFirstMember result = {0}; + result.symbol_count = symbol_count; + result.member_offset_count = member_offset_count; + result.member_offsets = member_offsets; + result.string_table = str8_substr(member->data, string_table_range); + + return result; +} + +internal COFF_ArchiveSecondMember +coff_parse_second_archive_member(COFF_ArchiveMember *member) +{ + Assert(str8_match(member->header.name, str8_lit("/"), 0)); + + U64 cursor = 0; + + U32 member_count = 0; + cursor += str8_deserial_read_struct(member->data, cursor, &member_count); + + Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + member_count * sizeof(U32)); + cursor += dim_1u64(member_offsets_range); + + U32 symbol_count = 0; + cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count); + + Rng1U64 symbol_indices_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U16)); + cursor += dim_1u64(symbol_indices_range); + + Rng1U64 string_table_range = rng_1u64(cursor, member->data.size); + + String8 raw_member_offsets = str8_substr(member->data, member_offsets_range); + String8 raw_indices = str8_substr(member->data, symbol_indices_range); + + U32 *member_offsets = (U32 *)raw_member_offsets.str; + U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]); + + U16 *symbol_indices = (U16 *)raw_indices.str; + U64 symbol_index_count = raw_indices.size / sizeof(symbol_indices[0]); + + COFF_ArchiveSecondMember result = {0}; + result.member_count = member_count; + result.symbol_count = symbol_count; + result.member_offsets = member_offsets; + result.member_offset_count = member_offset_count; + result.symbol_indices = symbol_indices; + result.symbol_index_count = symbol_index_count; + result.string_table = str8_substr(member->data, string_table_range); + + return result; } internal String8 -coff_read_archive_long_name(String8 long_names, String8 name) +coff_parse_long_name(String8 long_names, String8 name) { String8 result = name; if (name.size > 0 && name.str[0] == '/') { @@ -1046,6 +1088,58 @@ coff_read_archive_long_name(String8 long_names, String8 name) return result; } +internal U64 +coff_parse_archive_import(String8 data, U64 offset, COFF_ImportHeader *header_out) +{ + U64 cursor = offset; + + cursor += str8_deserial_read_struct(data, cursor, &header_out->sig1); + cursor += str8_deserial_read_struct(data, cursor, &header_out->sig2); + cursor += str8_deserial_read_struct(data, cursor, &header_out->version); + cursor += str8_deserial_read_struct(data, cursor, &header_out->machine); + cursor += str8_deserial_read_struct(data, cursor, &header_out->time_stamp); + cursor += str8_deserial_read_struct(data, cursor, &header_out->data_size); + cursor += str8_deserial_read_struct(data, cursor, &header_out->hint); + + U16 flags = 0; + cursor += str8_deserial_read_struct(data, cursor, &flags); + header_out->type = COFF_IMPORT_HEADER_GET_TYPE(flags); + header_out->name_type = COFF_IMPORT_HEADER_GET_NAME_TYPE(flags); + + header_out->func_name = str8_zero(); + cursor += str8_deserial_read_cstr(data, cursor, &header_out->func_name); + + header_out->dll_name = str8_zero(); + cursor += str8_deserial_read_cstr(data, cursor, &header_out->dll_name); + + Assert(header_out->func_name.size + header_out->dll_name.size + /* nulls */ 2 == header_out->data_size); + + U64 read_size = cursor - offset; + return read_size; +} + +internal COFF_ArchiveMember +coff_archive_member_from_offset(String8 data, U64 offset) +{ + COFF_ArchiveMember member = {0}; + coff_archive_member_iter_next(data, &offset, &member); + return member; +} + +internal COFF_ArchiveMember +coff_archive_member_from_data(String8 data) +{ + return coff_archive_member_from_offset(data, 0); +} + +internal COFF_ImportHeader +coff_archive_import_from_data(String8 data) +{ + COFF_ImportHeader header = {0}; + coff_parse_archive_import(data, 0, &header); + return header; +} + internal U64 coff_archive_member_iter_init(String8 data) { @@ -1061,153 +1155,28 @@ coff_archive_member_iter_next(String8 data, U64 *offset, COFF_ArchiveMember *mem { B32 is_parsed; - COFF_ArchiveMemberHeader header; - U64 header_read_size = coff_read_archive_member_header(data, *offset, &header); + COFF_ArchiveMemberHeader header; header.is_end_correct = 0; + U64 read_size = coff_parse_archive_member_header(data, *offset, 1, &header); - if (header_read_size && header.is_end_correct) { - Rng1U64 data_range = rng_1u64(*offset + header_read_size, *offset + header_read_size + header.size); - + if (header.is_end_correct) { member_out->header = header; member_out->offset = *offset; - member_out->data = str8_substr(data, data_range); - - *offset += header_read_size; - *offset += member_out->header.size; - *offset = AlignPow2(*offset, COFF_ARCHIVE_ALIGN); + member_out->data = str8_substr(data, header.data_range); + + *offset += read_size; is_parsed = 1; } else { MemoryZeroStruct(&member_out->header); - member_out->offset = max_U64; - member_out->data = str8(0,0); - + member_out->offset = max_U64; + member_out->data = str8(0,0); + is_parsed = 0; } return is_parsed; } -internal B32 -coff_get_first_archive_member(COFF_ArchiveMember *member, COFF_ArchiveFirstMember *first_out) -{ - B32 is_header = str8_match(member->header.name, str8_lit("/"), 0); - if (is_header) { - U64 cursor = 0; - - U32 symbol_count = 0; - cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count); - -#if ARCH_LITTLE_ENDIAN - symbol_count = bswap_u32(symbol_count); -#endif - - Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U32)); - cursor += dim_1u64(member_offsets_range); - - Rng1U64 string_table_range = rng_1u64(cursor, member->data.size); - cursor += dim_1u64(string_table_range); - - first_out->symbol_count = symbol_count; - first_out->member_offsets = str8_substr(member->data, member_offsets_range); - first_out->string_table = str8_substr(member->data, string_table_range); - } - return is_header; -} - -internal B32 -coff_get_second_archive_member(COFF_ArchiveMember *member, COFF_ArchiveSecondMember *second_out) -{ - B32 is_header = str8_match(member->header.name, str8_lit("/"), 0); - if (is_header) { - U64 cursor = 0; - - U32 member_count = 0; - cursor += str8_deserial_read_struct(member->data, cursor, &member_count); - - Rng1U64 member_offsets_range = rng_1u64(cursor, cursor + member_count * sizeof(U32)); - cursor += dim_1u64(member_offsets_range); - - U32 symbol_count = 0; - cursor += str8_deserial_read_struct(member->data, cursor, &symbol_count); - - Rng1U64 symbol_indices_range = rng_1u64(cursor, cursor + symbol_count * sizeof(U16)); - cursor += dim_1u64(symbol_indices_range); - - Rng1U64 string_table_range = rng_1u64(cursor, member->data.size); - - second_out->member_count = member_count; - second_out->symbol_count = symbol_count; - second_out->member_offsets = str8_substr(member->data, member_offsets_range); - second_out->symbol_indices = str8_substr(member->data, symbol_indices_range); - second_out->string_table = str8_substr(member->data, string_table_range); - } - return is_header; -} - -internal void -coff_archive_member_list_push_node(COFF_ArchiveMemberList *list, COFF_ArchiveMemberNode *node) -{ - SLLQueuePush(list->first, list->last, node); - list->count += 1; -} - -internal COFF_ArchiveParse -coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list) -{ - COFF_ArchiveMember first_header; MemoryZeroStruct(&first_header); - COFF_ArchiveMember second_header; MemoryZeroStruct(&second_header); - COFF_ArchiveMember long_names_member; MemoryZeroStruct(&long_names_member); - - if (member_list.count) { - if (str8_match(member_list.first->data.header.name, str8_lit("/"), 0)) { - first_header = member_list.first->data; - SLLQueuePop(member_list.first, member_list.last); - member_list.count -= 1; - - if (member_list.count && str8_match(member_list.first->data.header.name, str8_lit("/"), 0)) { - second_header = member_list.first->data; - SLLQueuePop(member_list.first, member_list.last); - member_list.count -= 1; - } - - if (member_list.count && str8_match(member_list.first->data.header.name, str8_lit("//"), 0)) { - long_names_member = member_list.first->data; - SLLQueuePop(member_list.first, member_list.last); - member_list.count -= 1; - } - } - } - - COFF_ArchiveFirstMember first_member; MemoryZeroStruct(&first_member); - coff_get_first_archive_member(&first_header, &first_member); - - COFF_ArchiveSecondMember second_member; MemoryZeroStruct(&second_member); - coff_get_second_archive_member(&second_header, &second_member); - - COFF_ArchiveParse parse; MemoryZeroStruct(&parse); - parse.first_member = first_member; - parse.second_member = second_member; - parse.long_names = long_names_member.data; - - return parse; -} - -internal COFF_ArchiveParse -coff_archive_from_data(Arena *arena, String8 data) -{ - COFF_ArchiveMemberList list; MemoryZeroStruct(&list); - COFF_ArchiveMemberNode node_arr[3]; MemoryZeroStruct(&node_arr[0]); - U64 cursor = coff_archive_member_iter_init(data); - for (U64 i = 0; i < ArrayCount(node_arr); i += 1) { - COFF_ArchiveMemberNode *node = &node_arr[i]; - if (!coff_archive_member_iter_next(data, &cursor, &node->data)) { - break; - } - coff_archive_member_list_push_node(&list, node); - } - return coff_archive_parse_from_member_list(list); -} - internal U64 coff_thin_archive_member_iter_init(String8 data) { @@ -1223,30 +1192,112 @@ coff_thin_archive_member_iter_next(String8 data, U64 *offset, COFF_ArchiveMember { B32 is_parsed = 0; - U64 header_size = coff_read_archive_member_header(data, *offset, &member_out->header); - if (header_size) { + member_out->header.is_end_correct = 0; + U64 header_size = coff_parse_archive_member_header(data, *offset, 0, &member_out->header); + + if (member_out->header.is_end_correct) { member_out->offset = *offset; - *offset += header_size; if (str8_match(member_out->header.name, str8_lit("/"), 0) || str8_match(member_out->header.name, str8_lit("//"), 0)) { - Rng1U64 data_range = rng_1u64(*offset, *offset + member_out->header.size); - member_out->data = str8_substr(data, data_range); - *offset += member_out->header.size; + member_out->data = str8_substr(data, member_out->header.data_range); } else { // size field in non-header members means size of stand-alone obj - member_out->data = str8(0,0); + member_out->data = str8_zero(); } - *offset = AlignPow2(*offset, COFF_ARCHIVE_ALIGN); + *offset += header_size; is_parsed = 1; } return is_parsed; } -internal COFF_ArchiveParse -coff_thin_archive_from_data(Arena *arena, String8 data) +internal void +coff_archive_member_list_push_node(COFF_ArchiveMemberList *list, COFF_ArchiveMemberNode *node) { - COFF_ArchiveMemberList list; MemoryZeroStruct(&list); - COFF_ArchiveMemberNode node_arr[3]; MemoryZeroStruct(&node_arr[0]); + SLLQueuePush(list->first, list->last, node); + list->count += 1; +} + +internal COFF_ArchiveParse +coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list) +{ + String8 error = str8_zero(); + B32 has_second_header = 0; + B32 has_long_names = 0; + COFF_ArchiveMember first_header = {0}; + COFF_ArchiveMember second_header = {0}; + COFF_ArchiveMember long_names_member = {0}; + + COFF_ArchiveMemberNode *ptr = member_list.first; + + if (ptr) { + if (str8_match(ptr->data.header.name, str8_lit("/"), 0)) { + if (ptr->data.header.is_end_correct) { + first_header = ptr->data; + ptr = ptr->next; + } else { + error = str8_lit("first header doesn't have correct end"); + } + } + } else { + error = str8_lit("missing first header"); + } + + if (!error.size && ptr) { + if (str8_match(ptr->data.header.name, str8_lit("/"), 0)) { + if (ptr->data.header.is_end_correct) { + second_header = ptr->data; + ptr = ptr->next; + has_second_header = 1; + } else { + error = str8_lit("second header doesn't have correct end"); + } + } + } + + if (!error.size && ptr) { + if (str8_match(ptr->data.header.name, str8_lit("//"), 0)) { + if (ptr->data.header.is_end_correct) { + long_names_member = ptr->data; + ptr = ptr->next; + has_long_names; + } else { + error = str8_lit("long names header doesn't have correct end"); + } + } + } + + COFF_ArchiveParse parse = {0}; + parse.has_second_header = has_second_header; + parse.has_long_names = has_long_names; + parse.first_member = coff_parse_first_archive_member(&first_header); + parse.second_member = coff_parse_second_archive_member(&second_header); + parse.long_names = long_names_member.data; + parse.error = error; + + return parse; +} + +internal COFF_ArchiveParse +coff_archive_from_data(String8 data) +{ + COFF_ArchiveMemberList list = {0}; + COFF_ArchiveMemberNode node_arr[3] = {0}; + U64 cursor = coff_archive_member_iter_init(data); + for (U64 i = 0; i < ArrayCount(node_arr); ++i) { + COFF_ArchiveMemberNode *node = &node_arr[i]; + if (!coff_archive_member_iter_next(data, &cursor, &node->data)) { + break; + } + coff_archive_member_list_push_node(&list, node); + } + return coff_archive_parse_from_member_list(list); +} + +internal COFF_ArchiveParse +coff_thin_archive_from_data(String8 data) +{ + COFF_ArchiveMemberList list = {0}; + COFF_ArchiveMemberNode node_arr[3] = {0}; U64 cursor = coff_thin_archive_member_iter_init(data); for (U64 i = 0; i < ArrayCount(node_arr); i += 1) { COFF_ArchiveMemberNode *node = &node_arr[i]; @@ -1258,27 +1309,16 @@ coff_thin_archive_from_data(Arena *arena, String8 data) return coff_archive_parse_from_member_list(list); } -internal COFF_ArchiveType -coff_archive_type_from_data(String8 data) -{ - if (coff_is_archive(data)) { - return COFF_Archive_Regular; - } else if (coff_is_thin_archive(data)) { - return COFF_Archive_Thin; - } - return COFF_Archive_Null; -} - internal COFF_ArchiveParse -coff_archive_parse_from_data(Arena *arena, String8 data) +coff_archive_parse_from_data(String8 data) { COFF_ArchiveType type = coff_archive_type_from_data(data); switch (type) { - case COFF_Archive_Null: break; - case COFF_Archive_Regular: return coff_archive_from_data(arena, data); - case COFF_Archive_Thin: return coff_thin_archive_from_data(arena, data); + case COFF_Archive_Null: break; + case COFF_Archive_Regular: return coff_archive_from_data(data); + case COFF_Archive_Thin: return coff_thin_archive_from_data(data); } - COFF_ArchiveParse null_parse; MemoryZeroStruct(&null_parse); + COFF_ArchiveParse null_parse = {0}; return null_parse; } @@ -1352,6 +1392,55 @@ coff_string_from_machine_type(COFF_MachineType machine) return str8_zero(); } +internal String8 +coff_string_from_flags(Arena *arena, COFF_Flags flags) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + + if (flags & COFF_Flag_RELOC_STRIPPED) { + str8_list_pushf(scratch.arena, &list, "Relocs Stripped"); + } + if (flags & COFF_Flag_EXECUTABLE_IMAGE) { + str8_list_pushf(scratch.arena, &list, "Executable"); + } + if (flags & COFF_Flag_LINE_NUMS_STRIPPED) { + str8_list_pushf(scratch.arena, &list, "Line Numbers Stripped"); + } + if (flags & COFF_Flag_SYM_STRIPPED) { + str8_list_pushf(scratch.arena, &list, "Symbols Stripped"); + } + if (flags & COFF_Flag_LARGE_ADDRESS_AWARE) { + str8_list_pushf(scratch.arena, &list, "Large Address Aware"); + } + if (flags & COFF_Flag_32BIT_MACHINE) { + str8_list_pushf(scratch.arena, &list, "32-Bit Machine"); + } + if (flags & COFF_Flag_DEBUG_STRIPPED) { + str8_list_pushf(scratch.arena, &list, "Debug Stripped"); + } + if (flags & COFF_Flag_REMOVABLE_RUN_FROM_SWAP) { + str8_list_pushf(scratch.arena, &list, "Removeable Run From Swap"); + } + if (flags & COFF_Flag_NET_RUN_FROM_SWAP) { + str8_list_pushf(scratch.arena, &list, "Net Run From Swap"); + } + if (flags & COFF_Flag_SYSTEM) { + str8_list_pushf(scratch.arena, &list, "System"); + } + if (flags & COFF_Flag_DLL) { + str8_list_pushf(scratch.arena, &list, "DLL"); + } + if (flags & COFF_Flag_UP_SYSTEM_ONLY) { + str8_list_pushf(scratch.arena, &list, "Up System Only"); + } + + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + + scratch_end(scratch); + return result; +} + internal String8 coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags) { @@ -1416,9 +1505,13 @@ coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags) str8_list_pushf(scratch.arena, &list, "MEM_WRITE"); } - U64 align = COFF_SectionFlags_Extract_ALIGN(flags); + U64 align = coff_align_size_from_section_flags(flags); if (align) { - str8_list_pushf(scratch.arena, &list, "ALIGN=%u", align); + str8_list_pushf(scratch.arena, &list, "Align=%u", align); + } + + if (!list.node_count) { + str8_list_pushf(scratch.arena, &list, "None"); } StringJoin join = {0}; @@ -1444,7 +1537,7 @@ internal String8 coff_string_from_sym_dtype(COFF_SymDType x) { switch (x) { - case COFF_SymDType_NULL: break; + case COFF_SymDType_NULL: return str8_lit("NULL"); case COFF_SymDType_PTR : return str8_lit("PTR"); case COFF_SymDType_FUNC: return str8_lit("FUNC"); case COFF_SymDType_ARRAY: return str8_lit("ARRAY"); @@ -1456,7 +1549,7 @@ internal String8 coff_string_from_sym_type(COFF_SymType x) { switch (x) { - case COFF_SymType_NULL: break; + case COFF_SymType_NULL: return str8_lit("NULL"); case COFF_SymType_VOID: return str8_lit("VOID"); case COFF_SymType_CHAR: return str8_lit("CHAR"); case COFF_SymType_SHORT: return str8_lit("SHORT"); @@ -1677,3 +1770,4 @@ coff_import_header_type_from_string(String8 name) return COFF_ImportHeaderType_COUNT; } + diff --git a/src/coff/coff.h b/src/coff/coff.h index ee306747..80e34c87 100644 --- a/src/coff/coff.h +++ b/src/coff/coff.h @@ -506,7 +506,7 @@ typedef struct COFF_SymbolSecDef U16 number_of_relocations; U16 number_of_ln; U32 check_sum; - U16 number_lo; // one-based section index + U16 number_lo; // low 16 bits of one-based section index COFF_ComdatSelectType selection; U8 unused; U16 number_hi; @@ -635,13 +635,13 @@ typedef struct COFF_ResourceDirEntry typedef struct COFF_ArchiveMemberHeader { - String8 name; // padded to 16 bytes with spaces - U32 date; // unix time - U32 user_id; // unix artifact that does not have meaning on windows - U32 group_id; // unix artifact that does not have meaning on windows - String8 mode; // octal representation the members file mode - U32 size; // size of the member data, not including header - B32 is_end_correct; // set to true if found correct signature after header + String8 name; // padded to 16 bytes with spaces + COFF_TimeStamp time_stamp; + U32 user_id; // unix artifact that does not have meaning on windows + U32 group_id; // unix artifact that does not have meaning on windows + String8 mode; // octal representation the members file mode + B32 is_end_correct; // set to true if found correct signature after header + Rng1U64 data_range; } COFF_ArchiveMemberHeader; //////////////////////////////// @@ -747,18 +747,21 @@ typedef struct COFF_ArchiveMember typedef struct COFF_ArchiveFirstMember { - U32 symbol_count; - String8 member_offsets; - String8 string_table; + U32 symbol_count; + U64 member_offset_count; + U32 *member_offsets; + String8 string_table; } COFF_ArchiveFirstMember; typedef struct COFF_ArchiveSecondMember { - U32 member_count; - U32 symbol_count; - String8 member_offsets; - String8 symbol_indices; - String8 string_table; + U32 member_count; + U32 symbol_count; + U64 member_offset_count; + U32 *member_offsets; + U64 symbol_index_count; + U16 *symbol_indices; + String8 string_table; } COFF_ArchiveSecondMember; typedef struct COFF_ArchiveMemberNode @@ -783,9 +786,12 @@ typedef enum typedef struct COFF_ArchiveParse { + B32 has_second_header; + B32 has_long_names; COFF_ArchiveFirstMember first_member; COFF_ArchiveSecondMember second_member; String8 long_names; + String8 error; } COFF_ArchiveParse; //////////////////////////////// @@ -828,7 +834,7 @@ internal COFF_SymbolValueInterpType coff_interp_symbol(U32 section_number, U32 v internal U64 coff_foff_from_voff(COFF_SectionHeader *sections, U64 section_count, U64 voff); internal COFF_SectionHeader *coff_section_header_from_num(String8 data, U64 section_headers_off, U64 n); -internal String8 coff_section_header_get_name(COFF_SectionHeader *header, String8 coff_data, U64 string_table_base); +internal String8 coff_name_from_section_header(COFF_SectionHeader *header, String8 coff_data, U64 string_table_base); internal void coff_parse_section_name(String8 full_name, String8 *name_out, String8 *postfix_out); internal String8 coff_read_symbol_name(String8 data, U64 string_table_base_offset, COFF_SymbolName *name); @@ -883,31 +889,42 @@ internal String8 coff_write_resource_id(Arena *arena, COFF_ResourceID id); internal String8 coff_write_resource(Arena *arena, COFF_ResourceID type, COFF_ResourceID name, U32 data_version, COFF_ResourceMemoryFlags memory_flags, U16 language_id, U32 version, U32 characteristics, String8 data); //////////////////////////////// +//~ Archive -internal COFF_DataType coff_data_type_from_data(String8 data); -internal B32 coff_is_import(String8 data); -internal B32 coff_is_archive(String8 data); -internal B32 coff_is_thin_archive(String8 data); -internal U64 coff_read_archive_member_header(String8 data, U64 offset, COFF_ArchiveMemberHeader *header_out); -internal COFF_ArchiveMember coff_read_archive_member(String8 data, U64 offset); -internal U64 coff_read_archive_import(String8 data, U64 offset, COFF_ImportHeader *header_out); -internal String8 coff_read_archive_long_name(String8 long_names, String8 name); +internal COFF_DataType coff_data_type_from_data(String8 data); +internal B32 coff_is_import(String8 data); +internal B32 coff_is_archive(String8 data); +internal B32 coff_is_thin_archive(String8 data); +internal COFF_ArchiveType coff_archive_type_from_data(String8 data); + +internal U64 coff_parse_archive_member_header(String8 data, U64 offset, B32 is_regular_archive, COFF_ArchiveMemberHeader *header_out); +internal B32 coff_parse_archive_member_data(String8 data, U64 cursor, COFF_ArchiveMember *member_out); +internal COFF_ArchiveFirstMember coff_parse_first_archive_member(COFF_ArchiveMember *member); +internal COFF_ArchiveSecondMember coff_parse_second_archive_member(COFF_ArchiveMember *member); +internal String8 coff_parse_long_name(String8 long_names, String8 name); +internal U64 coff_parse_archive_import(String8 data, U64 offset, COFF_ImportHeader *header_out); + +internal COFF_ArchiveMember coff_archive_member_from_offset(String8 data, U64 offset); internal COFF_ArchiveMember coff_archive_member_from_data(String8 data); -internal U64 coff_archive_member_iter_init(String8 data); -internal B32 coff_archive_member_iter_next(String8 data, U64 *offset, COFF_ArchiveMember *member_out); -internal COFF_ArchiveParse coff_archive_parse_from_member_list(COFF_ArchiveMemberList list); -internal COFF_ArchiveParse coff_archive_from_data(Arena *arena, String8 data); -internal U64 coff_thin_archive_member_iter_init(String8 data); -internal B32 coff_thin_archive_member_iter_next(String8 data, U64 *offset, COFF_ArchiveMember *member_out); -internal COFF_ArchiveParse coff_thin_archive_from_data(Arena *arena, String8 data); -internal COFF_ArchiveType coff_archive_type_from_data(String8 data); -internal COFF_ArchiveParse coff_archive_parse_from_data(Arena *arena, String8 data); +internal COFF_ImportHeader coff_archive_import_from_data(String8 data); + +internal U64 coff_archive_member_iter_init(String8 data); +internal B32 coff_archive_member_iter_next(String8 data, U64 *offset, COFF_ArchiveMember *member_out); + +internal U64 coff_thin_archive_member_iter_init(String8 data); +internal B32 coff_thin_archive_member_iter_next(String8 data, U64 *offset, COFF_ArchiveMember *member_out); + +internal COFF_ArchiveParse coff_archive_parse_from_member_list(COFF_ArchiveMemberList list); +internal COFF_ArchiveParse coff_archive_from_data(String8 data); +internal COFF_ArchiveParse coff_thin_archive_from_data(String8 data); +internal COFF_ArchiveParse coff_archive_parse_from_data(String8 data); //////////////////////////////// // String <-> Enum internal String8 coff_string_from_comdat_select_type(COFF_ComdatSelectType select); internal String8 coff_string_from_machine_type(COFF_MachineType machine); +internal String8 coff_string_from_flags(Arena *arena, COFF_Flags flags); internal String8 coff_string_from_section_flags(Arena *arena, COFF_SectionFlags flags); internal String8 coff_string_from_import_header_type(COFF_ImportHeaderType type); internal String8 coff_string_from_sym_dtype(COFF_SymDType x); diff --git a/src/linker/base_ext/base_core.h b/src/linker/base_ext/base_core.h index a5c736eb..2f850d3b 100644 --- a/src/linker/base_ext/base_core.h +++ b/src/linker/base_ext/base_core.h @@ -114,14 +114,6 @@ //////////////////////////////// -#if ARCH_LITTLE_ENDIAN -# define BE_U32(x) bswap_u32(x) -#else -# define BE_U32(x) (x) -#endif - -//////////////////////////////// - typedef struct { U64 major; diff --git a/src/linker/hash_table.c b/src/linker/hash_table.c index b48c9a10..50ec76a2 100644 --- a/src/linker/hash_table.c +++ b/src/linker/hash_table.c @@ -243,6 +243,19 @@ key_value_pair_is_before_u64(void *raw_a, void *raw_b) return a->key_u64 < b->key_u64; } +internal U32 * +keys_from_hash_table_u32(Arena *arena, HashTable *ht) +{ + U32 *result = push_array_no_zero(arena, U32, ht->count); + for (U64 bucket_idx = 0, cursor = 0; bucket_idx < ht->cap; ++bucket_idx) { + for (BucketNode *n = ht->buckets[bucket_idx].first; n != 0; n = n->next) { + Assert(cursor < ht->count); + result[cursor++] = n->v.key_u32; + } + } + return result; +} + internal KeyValuePair * key_value_pairs_from_hash_table(Arena *arena, HashTable *ht) { diff --git a/src/linker/hash_table.h b/src/linker/hash_table.h index 70786d5b..ad048600 100644 --- a/src/linker/hash_table.h +++ b/src/linker/hash_table.h @@ -75,6 +75,7 @@ internal B32 hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_o //- key-value helpers +internal U32 * keys_from_hash_table_u32(Arena *arena, HashTable *ht); internal KeyValuePair * key_value_pairs_from_hash_table(Arena *arena, HashTable *ht); internal void sort_key_value_pairs_as_u32(KeyValuePair *pairs, U64 count); internal void sort_key_value_pairs_as_u64(KeyValuePair *pairs, U64 count); diff --git a/src/linker/lnk.c b/src/linker/lnk.c index f5f74c52..8e7b6d4c 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1221,7 +1221,7 @@ internal void lnk_push_input_from_lazy(Arena *arena, PathStyle path_style, LNK_LazySymbol *lazy, LNK_InputImportList *input_import_list, LNK_InputObjList *input_obj_list) { // parse member - COFF_ArchiveMember member_info = coff_read_archive_member(lazy->lib->data, lazy->member_offset); + COFF_ArchiveMember member_info = coff_archive_member_from_offset(lazy->lib->data, lazy->member_offset); COFF_DataType member_type = coff_data_type_from_data(member_info.data); switch (member_type) { @@ -1231,7 +1231,7 @@ lnk_push_input_from_lazy(Arena *arena, PathStyle path_style, LNK_LazySymbol *laz } break; case COFF_DataType_BIG_OBJ: case COFF_DataType_OBJ: { - String8 obj_path = coff_read_archive_long_name(lazy->lib->long_names, member_info.header.name); + String8 obj_path = coff_parse_long_name(lazy->lib->long_names, member_info.header.name); // obj path in thin archive has slash appended which screws up // file lookup on disk; it couble be there to enable paths to symbols diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index e8d486a3..0d018704 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -109,25 +109,28 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path) lnk_not_implemented("TODO: data is not archive"); } - COFF_ArchiveParse parse = coff_archive_parse_from_data(arena, data); + COFF_ArchiveParse parse = coff_archive_parse_from_data(data); + + // report archive parser errors + if (parse.error.size) { + lnk_error(LNK_Error_IllData, "%S: %S", path, parse.error); + } // try to init library from optional second member if (parse.second_member.member_count) { COFF_ArchiveSecondMember second_member = parse.second_member; - Assert(second_member.symbol_count == second_member.symbol_indices.size / sizeof(U16)); - Assert(second_member.member_count == second_member.member_offsets.size / sizeof(U32)); + Assert(second_member.symbol_count == second_member.symbol_index_count); + Assert(second_member.member_count == second_member.member_offset_count); symbol_count = second_member.symbol_count; string_table = second_member.string_table; member_off_arr = push_array_no_zero(arena, U32, symbol_count); // decompress member offsets - U32 *comp_off_arr = (U32*)second_member.member_offsets.str; - U16 *off_number_arr = (U16*)second_member.symbol_indices.str; for (U64 symbol_idx = 0; symbol_idx < symbol_count; symbol_idx += 1) { - U16 off_number = off_number_arr[symbol_idx]; + U16 off_number = second_member.symbol_indices[symbol_idx]; if (0 < off_number && off_number <= second_member.member_count) { - member_off_arr[symbol_idx] = comp_off_arr[off_number - 1]; + member_off_arr[symbol_idx] = second_member.member_offsets[off_number - 1]; } else { // TODO: log bad offset member_off_arr[symbol_idx] = max_U32; @@ -138,19 +141,19 @@ lnk_lib_from_data(Arena *arena, String8 data, String8 path) // and lld-link with /DLL emits only first member else if (parse.first_member.symbol_count) { COFF_ArchiveFirstMember first_member = parse.first_member; - Assert(first_member.symbol_count == first_member.member_offsets.size / sizeof(U32)); + Assert(first_member.symbol_count == first_member.member_offset_count); symbol_count = first_member.symbol_count; string_table = first_member.string_table; - member_off_arr = (U32*)first_member.member_offsets.str; + member_off_arr = first_member.member_offsets; // convert big endian offsets for (U32 offset_idx = 0; offset_idx < symbol_count; offset_idx += 1) { - member_off_arr[offset_idx] = BE_U32(member_off_arr[offset_idx]); + member_off_arr[offset_idx] = from_be_u32(member_off_arr[offset_idx]); } } else { symbol_count = 0; - string_table = str8(0,0); + string_table = str8_zero(); member_off_arr = 0; } @@ -472,7 +475,7 @@ lnk_coff_archive_from_lib_build(Arena *arena, LNK_LibBuild *lib, B32 emit_second // first linker member (obsolete, but kept for compatability reasons) { - U32 symbol_count_be = BE_U32(symbol_count); + U32 symbol_count_be = from_be_u32(symbol_count); U32 *member_off32_arr = push_array_no_zero(scratch.arena, U32, symbol_count); for (U64 symbol_idx = 0; symbol_idx < symbol_count; symbol_idx += 1) { @@ -480,7 +483,7 @@ lnk_coff_archive_from_lib_build(Arena *arena, LNK_LibBuild *lib, B32 emit_second // write big endian member offset U64 member_off = member_base_off + member_off_arr[symbol->member_idx]; - U32 member_off32 = BE_U32(safe_cast_u32(member_off)); + U32 member_off32 = from_be_u32(safe_cast_u32(member_off)); member_off32_arr[symbol_idx] = member_off32; } diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index a6024234..311dde28 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -359,7 +359,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) COFF_SectionHeader *coff_sect = &coff_sect_arr[sect_idx]; // read name - String8 sect_name = coff_section_header_get_name(coff_sect, input->data, coff_info.string_table_off); + String8 sect_name = coff_name_from_section_header(coff_sect, input->data, coff_info.string_table_off); // parse section name String8 name, postfix;