diff --git a/bootstrap/lib.h b/bootstrap/lib.h index 62a6e22..5a0dc0a 100644 --- a/bootstrap/lib.h +++ b/bootstrap/lib.h @@ -3029,6 +3029,180 @@ may_be_unused fn Hash32 hash64_fib_end(Hash64 hash) return result; } +STRUCT(MD5Context) +{ + u32 buffer[4]; + u8 input[64]; + u64 size; +}; + +// Took from: https://github.com/Zunawe/md5-c + +#define MD5_A 0x67452301 +#define MD5_B 0xefcdab89 +#define MD5_C 0x98badcfe +#define MD5_D 0x10325476 + +#define MD5_F(X, Y, Z) ((X & Y) | (~X & Z)) +#define MD5_G(X, Y, Z) ((X & Z) | (Y & ~Z)) +#define MD5_H(X, Y, Z) (X ^ Y ^ Z) +#define MD5_I(X, Y, Z) (Y ^ (X | ~Z)) + +global u32 md5_s[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}; + +global u32 md5_k[] = {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391}; + +/* + * Padding used to make the size (in bits) of the input congruent to 448 mod 512 + */ +global u8 md5_padding[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + +fn MD5Context md5_init() +{ + return (MD5Context) { + .buffer = { MD5_A, MD5_B, MD5_C, MD5_D }, + }; +} + +fn u32 rotate_left_u32(u32 x, u32 n) +{ + return (x << n) | (x >> (32 - n)); +} + +fn void md5_step(u32* buffer, u32* input) +{ + u32 aa = buffer[0]; + u32 bb = buffer[1]; + u32 cc = buffer[2]; + u32 dd = buffer[3]; + + for (u32 i = 0; i < 64; i += 1) + { + u32 j; + u32 e; + switch (i / 16) + { + case 0: + { + e = MD5_F(bb, cc, dd); + j = i; + } break; + case 1: + { + e = MD5_G(bb, cc, dd); + j = ((i * 5) + 1) % 16; + } break; + case 2: + { + e = MD5_H(bb, cc, dd); + j = ((i * 3) + 5) % 16; + } break; + default: + { + e = MD5_I(bb, cc, dd); + j = (i * 7) % 16; + } break; + } + + u32 old_dd = dd; + dd = cc; + cc = bb; + bb = bb + rotate_left_u32(aa + e + md5_k[i] + input[j], md5_s[i]); + aa = old_dd; + } + + buffer[0] += aa; + buffer[1] += bb; + buffer[2] += cc; + buffer[3] += dd; +} + +fn void md5_update(MD5Context* context, String input_argument) +{ + u32 input_local[16]; + auto offset = context->size % 64; + context->size += input_argument.length; + + for (u64 i = 0; i < input_argument.length; i += 1) + { + context->input[offset] = input_argument.pointer[i]; + offset += 1; + + if (offset % 64 == 0) + { + // TODO: convert to little-endian in case we are big-endian? + for (u16 i = 0; i < 16; i += 1) + { + auto existing = *(u32*)&input_argument.pointer[i * 4]; + input_local[i] = existing; + } + md5_step(context->buffer, input_local); + offset = 0; + } + } +} + +STRUCT(MD5Result) +{ + u8 hash[16]; +}; + +fn MD5Result md5_end(MD5Context* context) +{ + u32 input[16]; + auto offset = context->size % 64; + auto padding_length = offset < 56 ? 56 - offset : (56 + 64) - offset; + + md5_update(context, (String) { .pointer = md5_padding, .length = padding_length }); + context->size -= (u64)padding_length; + + for (u32 i = 0; i < 14; i += 1) + { + input[i] = *(u32*)&context->input[i * 4]; + } + input[14] = (u32)(context->size * 8); + input[15] = (u32)((context->size * 8) >> 32); + + md5_step(context->buffer, input); + + MD5Result result; + for (u32 i = 0; i < 4; i += 1) + { + result.hash[(i * 4) + 0] = (u8)((context->buffer[i] & 0x000000ff) >> 0); + result.hash[(i * 4) + 1] = (u8)((context->buffer[i] & 0x0000ff00) >> 8); + result.hash[(i * 4) + 2] = (u8)((context->buffer[i] & 0x00ff0000) >> 16); + result.hash[(i * 4) + 3] = (u8)((context->buffer[i] & 0xff000000) >> 24); + } + + return result; +} + fn void entry_point(int argc, char* argv[], char* envp[]); #if LINK_LIBC diff --git a/bootstrap/main.c b/bootstrap/main.c index 7738a5f..f431851 100644 --- a/bootstrap/main.c +++ b/bootstrap/main.c @@ -9722,21 +9722,94 @@ may_be_unused fn void write_elf(Thread* thread, const ObjectOptions* const restr uleb128_encode(&builder->file, opcode_length_lookup[i]); } - // TODO: figure out { - u8 data[] = { - 0x01, 0x01, 0x1F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x1F, 0x02, 0x0F, 0x05, 0x1E, 0x01, 0x14, 0x00, - 0x00, 0x00, 0x00, - }; - memcpy(vb_add(&builder->file, sizeof(data)), data, sizeof(data)); - } + typedef enum LineNumberHeaderEntryFormat : u8 + { + DW_LCNT_path = 0x01, + DW_LCNT_directory_index = 0x02, + DW_LCNT_timestamp = 0x03, + DW_LCNT_size = 0x04, + DW_LCNT_MD5 = 0x05, + } LineNumberHeaderEntryFormat; - // TODO: figure out - { - u8 checksum[] = { - 0x05, 0xAB, 0x89, 0xF5, 0x48, 0x1B, 0xC9, 0xF2, 0xD0, 0x37, 0xE7, 0x88, 0x66, 0x41, 0xE9, 0x19, + STRUCT(FormatDescriptor) + { + LineNumberHeaderEntryFormat format; + DwarfForm form; }; - memcpy(vb_add(&builder->file, sizeof(checksum)), checksum, sizeof(checksum)); + + FormatDescriptor directory_entry_formats[] = { + { DW_LCNT_path, DW_FORM_line_strp }, + }; + + auto directory_entry_format_count = cast(u8, u32, array_length(directory_entry_formats)); + *vb_add(&builder->file, 1) = directory_entry_format_count; + + for (u8 i = 0; i < array_length(directory_entry_formats); i += 1) + { + FormatDescriptor descriptor = directory_entry_formats[i]; + uleb128_encode(&builder->file, descriptor.format); + uleb128_encode(&builder->file, descriptor.form); + } + + u32 paths[] = { 0 }; + + auto directory_count = array_length(paths); + uleb128_encode(&builder->file, directory_count); + + for (u32 i = 0; i < directory_count; i += 1) + { + auto directory_offset = paths[i]; + *(u32*)(vb_add(&builder->file, sizeof(u32))) = directory_offset; + } + + FormatDescriptor filename_entry_formats[] = { + { DW_LCNT_path, DW_FORM_line_strp }, + { DW_LCNT_directory_index, DW_FORM_udata }, + { DW_LCNT_MD5, DW_FORM_data16 }, + }; + + auto filename_entry_format_count = cast(u8, u32, array_length(filename_entry_formats)); + *vb_add(&builder->file, 1) = filename_entry_format_count; + + for (u8 i = 0; i < filename_entry_format_count; i += 1) + { + FormatDescriptor descriptor = filename_entry_formats[i]; + uleb128_encode(&builder->file, descriptor.format); + uleb128_encode(&builder->file, descriptor.form); + } + + STRUCT(FilenameEntry) + { + u32 filename; + u8 directory_index; + MD5Result hash; + }; + MD5Result md5_hash = { { 0x05, 0xAB, 0x89, 0xF5, 0x48, 0x1B, 0xC9, 0xF2, 0xD0, 0x37, 0xE7, 0x88, 0x66, 0x41, 0xE9, 0x19 } }; +#if 0 + String dummy_file = file_read(thread->arena, strlit("/home/david/minimal/main.c")); + auto md5 = md5_init(); + md5_update(&md5, dummy_file); + md5_hash = md5_end(&md5); +#endif + + FilenameEntry filenames[] = { + { + 0x14, + 0, + md5_hash, + }, + }; + auto filename_count = array_length(filenames); + uleb128_encode(&builder->file, filename_count); + + for (auto i = 0; i < filename_count; i += 1) + { + auto filename = filenames[i]; + *(u32*)vb_add(&builder->file, sizeof(u32)) = filename.filename; + uleb128_encode(&builder->file, filename.directory_index); + memcpy(vb_add(&builder->file, sizeof(filename.hash)), &filename.hash, sizeof(filename.hash)); + } } auto line_program_start_offset = builder->file.length; @@ -9748,12 +9821,27 @@ may_be_unused fn void write_elf(Thread* thread, const ObjectOptions* const restr *vb_add(&builder->file, 1) = 5; *vb_add(&builder->file, 1) = DW_LNS_set_prologue_end; - } - // TODO: figure out - { - u8 data[] = { 0x00, 0x09, 0x02, 0x1C, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x02, 0x03, 0x00, 0x01, 0x01, }; - memcpy(vb_add(&builder->file, sizeof(data)), data, sizeof(data)); + { + // TODO: confirm this is the encoding of special opcodes? + *vb_add(&builder->file, 1) = 0; // Special opcode + *vb_add(&builder->file, 1) = 9; // Bytes ahead + *vb_add(&builder->file, 1) = DW_LNE_set_address; // Bytes ahead + *(u64*)vb_add(&builder->file, sizeof(u64)) = main_offset; + } + + *vb_add(&builder->file, 1) = 0x14; // 14, address += 0, line += 2, op-index += 0 + + // Advance PC by 3 + *vb_add(&builder->file, 1) = DW_LNS_advance_pc; + *vb_add(&builder->file, 1) = 0x03; + + { + // TODO: confirm this is the encoding of special opcodes? + *vb_add(&builder->file, 1) = 0; // Special opcode + *vb_add(&builder->file, 1) = 1; // Bytes ahead + *vb_add(&builder->file, 1) = DW_LNE_end_sequence; + } } auto size = builder->file.length - offset;