pass over COFF archive parser

This commit is contained in:
Nikita Smith
2024-12-06 11:40:36 -08:00
parent 29de0c5a9e
commit 80fa226432
8 changed files with 455 additions and 335 deletions
+371 -277
View File
@@ -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;
}
+51 -34
View File
@@ -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);
-8
View File
@@ -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;
+13
View File
@@ -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)
{
+1
View File
@@ -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);
+2 -2
View File
@@ -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
+16 -13
View File
@@ -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;
}
+1 -1
View File
@@ -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;