diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2024-08-01 08:24:18 +0200 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2024-08-01 08:24:18 +0200 |
commit | b33fbbc22c895e6553331c29cc6856208ff16dc4 (patch) | |
tree | baa0d0dae45894e87f0667e83dcf6a41d6ea5b0b | |
parent | 4bc7fe83b94e400ac190a6140ce9792a1c1ba106 (diff) | |
download | bxgen-b33fbbc22c895e6553331c29cc6856208ff16dc4.zip |
TLS segments
-rwxr-xr-x | bxgen.c | 188 |
1 files changed, 142 insertions, 46 deletions
@@ -30,6 +30,7 @@ #/ - Simplify #/ - Use 0 for UNDEFINED. Make the zero value useful #/ - Factor out checks +#/ - Allow to format the message in CHECK and FAIL macros #/ - Library #/ - Terminal color option #/ - String table for names and arrays @@ -1498,7 +1499,8 @@ void write_f64(u32 ordering, f64 x, void *v, void *v_end) { // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/ // https://docs.oracle.com/cd/E19120-01/open.solaris/819-0690/chapter7-2/index.html // -// https://web.archive.org/web/20150324024617/http://mylinuxbook.com/readelf-command/ +// Thread-local storage +// https://maskray.me/blog/2021-02-14-all-about-thread-local-storage // // tinycc impl // https://repo.or.cz/tinycc.git/blob/HEAD:/x86_64-link.c @@ -1769,6 +1771,7 @@ typedef struct { b8 alloc; b8 write; b8 exec; + b8 tls; i64 alignment; i64 entry_size; i64 num_entries; @@ -2338,16 +2341,17 @@ Elf_Section_Header elf_section( u64 flags = read_u64(LE, begin + 8, end); if (type > SEC_SYMTAB_SHNDX || type == 12 || type == 13) { - LOG(WARNING, "Unknown section type: %d", type); - type = SEC_NONE; + LOG(ERROR, "Section type: %d", type); + FAIL("Unknown section type", (Elf_Section_Header) {0}); } return (Elf_Section_Header) { .name = elf_name_in_string_table(b, names, name_index), .type = type, - .alloc = (flags & 2) == 2, - .write = (flags & 1) == 1, - .exec = (flags & 4) == 4, + .alloc = (flags & 2) == 2, + .write = (flags & 1) == 1, + .exec = (flags & 4) == 4, + .tls = (flags & 0x400) == 0x400, .alignment = read_i64(LE, begin + 48, end), .entry_size = entry_size, .num_entries = num_entries, @@ -2561,18 +2565,20 @@ i64 unit_write_in_memory( emit_unit(pool, codegen, unit, arch); - u16 num_program_headers = 7; + u16 num_program_headers = 9; i64 program_offset = align(ELF_HEADER_SIZE + ELF_PROGRAM_HEADER_SIZE * num_program_headers, X86_64_PAGE_SIZE); i64 base_address = X86_64_BASE_ADDRESS; i64 rx_code_address = base_address + program_offset; - i64 rx_code_size = codegen->offset_code; - i64 rw_zval_size = 0; - i64 rw_data_size = 0; - i64 ro_data_size = codegen->offset_ro_data; - i64 rw_got_size = ELF_GOT_ENTRY_SIZE; - i64 rw_dynamic_size = ELF_DYNAMIC_ENTRY_SIZE; + i64 rx_code_size = codegen->offset_code; + i64 rw_zval_size = 0; + i64 rw_data_size = 0; + i64 ro_data_size = codegen->offset_ro_data; + i64 rw_tls_zval_size = 0; + i64 rw_tls_data_size = 0; + i64 rw_got_size = ELF_GOT_ENTRY_SIZE; + i64 rw_dynamic_size = ELF_DYNAMIC_ENTRY_SIZE; i64 num_sections_total = 0; i64 num_symbols = 0; @@ -2593,8 +2599,7 @@ i64 unit_write_in_memory( CHECK(num_sections_total < linker->max_num_sections, "Too many sections",); Elf_Section_Header section = elf_section(buf, sec_index); - - c8 *name = elf_name_from_offset(buf, section.name); + c8 * name = elf_name_from_offset(buf, section.name); if (section.type == SEC_PROGBITS && STR_EQ(section.name.size, name, SECTION_GOT)) { @@ -2609,6 +2614,23 @@ i64 unit_write_in_memory( if (!section.alloc || section.data.size == 0) continue; + if (section.tls) { + if (section.type == SEC_PROGBITS) { + linker->sections[num_sections_total].offset = rw_tls_data_size; + linker->sections[num_sections_total].address = rw_tls_data_size; + rw_tls_data_size += align(section.data.size, X86_64_ALIGNMENT); + continue; + } + + if (section.type == SEC_NOBITS) { + linker->sections[num_sections_total].address = rw_tls_zval_size; + rw_tls_zval_size += align(section.data.size, X86_64_ALIGNMENT); + continue; + } + + FAIL("Not implemented", 0); + } + if (section.type == SEC_DYNAMIC) { FAIL("Not implemented", 0); } @@ -2651,38 +2673,90 @@ i64 unit_write_in_memory( } } - i64 rw_zval_address = align(rx_code_address + rx_code_size, X86_64_PAGE_SIZE); - i64 rw_data_address = align(rw_zval_address + rw_zval_size, X86_64_PAGE_SIZE); - i64 ro_data_address = align(rw_data_address + rw_data_size, X86_64_PAGE_SIZE); + i64 rw_zval_address = align(rx_code_address + rx_code_size, X86_64_PAGE_SIZE); + i64 rw_data_address = align(rw_zval_address + rw_zval_size, X86_64_PAGE_SIZE); + i64 ro_data_address = align(rw_data_address + rw_data_size, X86_64_PAGE_SIZE); + i64 rw_tls_zval_address = align(ro_data_address + ro_data_size, X86_64_PAGE_SIZE); + i64 rw_tls_data_address = align(rw_tls_zval_address + rw_tls_zval_size, X86_64_PAGE_SIZE); - i64 rx_code_offset = program_offset; - i64 rw_data_offset = align(rx_code_offset + rx_code_size, X86_64_PAGE_SIZE); - i64 ro_data_offset = align(rw_data_offset + rw_data_size, X86_64_PAGE_SIZE); + i64 rx_code_offset = program_offset; + i64 rw_data_offset = align(rx_code_offset + rx_code_size, X86_64_PAGE_SIZE); + i64 ro_data_offset = align(rw_data_offset + rw_data_size, X86_64_PAGE_SIZE); + i64 rw_tls_data_offset = align(ro_data_offset + ro_data_size, X86_64_PAGE_SIZE); for (i64 elf_index = 0, sec_index_global = 0; elf_index < linker->num_obj_files; ++elf_index) { - Buffer_Context buf = elf_buffer_context(pool, linker, linker->num_obj_files, elf_index); - Offset_Num headers = elf_section_headers(buf); + Buffer_Context buf = elf_buffer_context(pool, linker, linker->num_obj_files, elf_index); + Offset_Num headers = elf_section_headers(buf); for (i64 sec_index = 1; sec_index < headers.num; ++sec_index, ++sec_index_global) { CHECK(sec_index_global < num_sections_total, "Buffer overflow",); Elf_Section_Header section = elf_section(buf, sec_index); + c8 * name = elf_name_from_offset(buf, section.name); + + if (section.type == SEC_PROGBITS && + STR_EQ(section.name.size, name, SECTION_GOT)) { + FAIL("Not implemented", 0); + } + + if (section.type == SEC_PROGBITS && + STR_EQ(section.name.size, name, SECTION_PLT)) { + FAIL("Not implemented", 0); + } if (!section.alloc || section.data.size == 0) continue; + if (section.tls) { + if (section.type == SEC_PROGBITS) { + linker->sections[sec_index_global].offset += rw_tls_data_offset; + linker->sections[sec_index_global].address += rw_tls_data_address; + continue; + } + + if (section.type == SEC_NOBITS) { + linker->sections[sec_index_global].address += rw_tls_zval_address; + continue; + } + + FAIL("Not implemented", 0); + } + + if (section.type == SEC_DYNAMIC) { + FAIL("Not implemented", 0); + } + + if (section.type == SEC_PROGBITS && section.exec && + STR_EQ(section.name.size, name, SECTION_INIT)) { + FAIL("Not implemented", 0); + } + + if (section.type == SEC_PROGBITS && section.exec && + STR_EQ(section.name.size, name, SECTION_FINI)) { + FAIL("Not implemented", 0); + } + if (section.exec) { + CHECK(!section.write, "Not implemented", 0); + linker->sections[sec_index_global].offset += rx_code_offset + codegen->offset_code; linker->sections[sec_index_global].address += rx_code_address + codegen->offset_code; - } else if (section.write && section.type == SEC_NOBITS) { + continue; + } + + if (section.write && section.type == SEC_NOBITS) { linker->sections[sec_index_global].address += rw_zval_address; - } else if (section.write) { + continue; + } + + if (section.write) { linker->sections[sec_index_global].offset += rw_data_offset; linker->sections[sec_index_global].address += rw_data_address; - } else if (section.data.size > 0) { - linker->sections[sec_index_global].offset += ro_data_offset + codegen->offset_ro_data; - linker->sections[sec_index_global].address += ro_data_address + codegen->offset_ro_data; + continue; } + + linker->sections[sec_index_global].offset += ro_data_offset + codegen->offset_ro_data; + linker->sections[sec_index_global].address += ro_data_address + codegen->offset_ro_data; } } @@ -2705,10 +2779,15 @@ i64 unit_write_in_memory( Elf_Symbol_Entry sym = elf_symbol(buf, tab.data, strtab, sym_index); c8 * sym_name = elf_name_from_offset(buf, sym.name); + if (sym.type == SYM_TLS && sym.section != 0) + CHECK(elf_section(buf, sym.section).tls, "Sanity",); + if (sym.section == 0) // undefined symbol continue; - if (sym.section == 65522) // common + if (sym.section == 65522) { // common + LOG(INFO, "Common symbol: %s", sym_name); continue; + } i64 sym_address = sym.value.offset; @@ -2792,6 +2871,9 @@ i64 unit_write_in_memory( c8 * sym_name = elf_name_from_offset(buf, relx.symbol.name); i64 sym_index_global = num_symbols; + CHECK(relx.symbol.section != 65521, "Sanity",); + CHECK(relx.symbol.section != 65522, "Sanity",); + CHECK(num_symbols < linker->max_num_symbols, "Out of memory",); if (relx.symbol.section == 0) { @@ -3130,17 +3212,7 @@ i64 unit_write_in_memory( // Writing the ELF executable // - i64 output_size = - align( - program_offset - + rx_code_size - + rw_zval_size - + rw_data_size - + ro_data_size - + rw_got_size - + rw_dynamic_size, - X86_64_ALIGNMENT); - + i64 output_size = align(rw_dynamic_offset + rw_dynamic_size, X86_64_ALIGNMENT); CHECK(output_size <= linker->max_output_size, "Out of memory",); i64 entry = rx_code_address + codegen->entry_point; @@ -3166,12 +3238,14 @@ i64 unit_write_in_memory( LOG(VERBOSE, "Total %lld symbols", num_symbols); LOG(VERBOSE, "Total size"); - LOG(VERBOSE, "r/x code - %7lld bytes", rx_code_size); - LOG(VERBOSE, "r/w zval - %7lld bytes", rw_zval_size); - LOG(VERBOSE, "r/w data - %7lld bytes", rw_data_size); - LOG(VERBOSE, "r/o data - %7lld bytes", ro_data_size); - LOG(VERBOSE, "r/w GOT - %7lld bytes", rw_got_size); - LOG(VERBOSE, "r/w dynamic - %7lld bytes", rw_dynamic_size); + LOG(VERBOSE, "r/x code - %7lld bytes", rx_code_size); + LOG(VERBOSE, "r/w zval - %7lld bytes", rw_zval_size); + LOG(VERBOSE, "r/w data - %7lld bytes", rw_data_size); + LOG(VERBOSE, "r/o data - %7lld bytes", ro_data_size); + LOG(VERBOSE, "r/w TLS zval - %7lld bytes", rw_tls_zval_size); + LOG(VERBOSE, "r/w TLS data - %7lld bytes", rw_tls_data_size); + LOG(VERBOSE, "r/w GOT - %7lld bytes", rw_got_size); + LOG(VERBOSE, "r/w dynamic - %7lld bytes", rw_dynamic_size); LOG(VERBOSE, "Writing ELF x86_64 executable"); @@ -3269,6 +3343,28 @@ i64 unit_write_in_memory( write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); h += ELF_PROGRAM_HEADER_SIZE; + // r/w TLS zero values + write_u32(LE, 7, h, o_end); // type (PT_TLS) + write_u32(LE, 6, h + 4, o_end); // flags (PF_R | PF_W) + write_i64(LE, rw_tls_data_offset, h + 8, o_end); + write_i64(LE, rw_tls_zval_address, h + 16, o_end); // virtual address + write_i64(LE, rw_tls_zval_address, h + 24, o_end); // phisical address + write_i64(LE, 0, h + 32, o_end); // size in file + write_i64(LE, rw_tls_zval_size, h + 40, o_end); // size in memory + write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); + h += ELF_PROGRAM_HEADER_SIZE; + + // r/w TLS data + write_u32(LE, 7, h, o_end); // type (PT_TLS) + write_u32(LE, 6, h + 4, o_end); // flags (PF_R | PF_W) + write_i64(LE, rw_tls_data_offset, h + 8, o_end); + write_i64(LE, rw_tls_data_address, h + 16, o_end); // virtual address + write_i64(LE, rw_tls_data_address, h + 24, o_end); // phisical address + write_i64(LE, rw_tls_data_size, h + 32, o_end); // size in file + write_i64(LE, rw_tls_data_size, h + 40, o_end); // size in memory + write_i64(LE, X86_64_ALIGNMENT, h + 48, o_end); + h += ELF_PROGRAM_HEADER_SIZE; + // r/w GOT write_u32(LE, 1, h, o_end); // type (PT_LOAD) write_u32(LE, 6, h + 4, o_end); // flags (PF_R | PF_W) |