summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2024-08-01 08:24:18 +0200
committerMitya Selivanov <automainint@guattari.tech>2024-08-01 08:24:18 +0200
commitb33fbbc22c895e6553331c29cc6856208ff16dc4 (patch)
treebaa0d0dae45894e87f0667e83dcf6a41d6ea5b0b
parent4bc7fe83b94e400ac190a6140ce9792a1c1ba106 (diff)
downloadbxgen-b33fbbc22c895e6553331c29cc6856208ff16dc4.zip
TLS segments
-rwxr-xr-xbxgen.c188
1 files changed, 142 insertions, 46 deletions
diff --git a/bxgen.c b/bxgen.c
index b26ded0..d666f87 100755
--- a/bxgen.c
+++ b/bxgen.c
@@ -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)