/* ** Symbol Set Link Script Generator for ld */ #include "mr4th_base.h" #include "mr4th_cmdln.h" #include "exefmt/elf/mr4th_elf.h" #include "exefmt/elf/mr4th_elf.parse.h" #include "mr4th_stdio.h" #include "mr4th_base.c" #include "mr4th_cmdln.c" #include "exefmt/elf/mr4th_elf.c" #include "exefmt/elf/mr4th_elf.parse.c" #include "mr4th_stdio.c" //////////////////////////////// // Entry Point int main(int argc, char **argv){ os_main_init(argc, argv); Arena *arena = arena_alloc(); // arguments String8List command_line_args = os_command_line_arguments(); CMDLN *cmdln = cmdln_from_args(arena, &command_line_args); String8 output_file_name = cmdln_get_str8(cmdln, str8_lit("out"), 'o'); if (output_file_name.size == 0){ output_file_name = str8_lit("sy.ld"); } // symbol set names String8List symbol_set_names_list = {0}; BUFFER buckets; buffer_alloc(&buckets, GB(64)); hash_buckets_init(&buckets, 512); for (U32 input_idx = 0;; input_idx += 1){ // load input file String8 input_file_name = cmdln_input_from_idx(cmdln, input_idx); if (input_file_name.size == 0){ break; } String8 input_data = os_file_read(arena, input_file_name); // parse ELF_Parse *parse = elfp_begin(arena, input_data); if (parse != 0){ // process sections U32 section_count = elfp_section_count(parse); for (U32 i = 0; i < section_count; i += 1){ String8 secname = elfp_section_name(parse, i); if (secname.size >= 4 && str8_match(secname, str8_lit(".sy."), StringMatchFlag_PrefixMatch)){ String8 syname = str8_skip(secname, 4); U64 hash = str8_hash(syname); B32 match = 0; for (HASH_Node *hash_node = hash_buckets_first(&buckets, hash); hash_node != 0; hash_node = hash_node->next){ if (hash_node->hash == hash){ String8Node *node = (String8Node*)PtrFromInt(hash_node->val); if (str8_match(node->string, syname, 0)){ match = 1; break; } } } if (!match){ str8_list_push(arena, &symbol_set_names_list, syname); hash_buckets_expand(&buckets, symbol_set_names_list.node_count); hash_buckets_insert(arena, &buckets, hash, IntFromPtr(symbol_set_names_list.last)); } } } // process symbols U32 symbol_count = elfp_symbol_count(parse, ELFP_SYMBOL_TABLE_symtab); for (U32 i = 0; i < symbol_count; i += 1){ String8 name = elfp_symbol_name(parse, ELFP_SYMBOL_TABLE_symtab, i); String8 syname = {0}; if (str8_match(name, str8_lit("syfirst__"), StringMatchFlag_PrefixMatch)){ syname = str8_skip(name, 9); } else if (str8_match(name, str8_lit("syopl__"), StringMatchFlag_PrefixMatch)){ syname = str8_skip(name, 7); } if (syname.size != 0){ U64 hash = str8_hash(syname); B32 match = 0; for (HASH_Node *hash_node = hash_buckets_first(&buckets, hash); hash_node != 0; hash_node = hash_node->next){ if (hash_node->hash == hash){ String8Node *node = (String8Node*)PtrFromInt(hash_node->val); if (str8_match(node->string, syname, 0)){ match = 1; break; } } } if (!match){ str8_list_push(arena, &symbol_set_names_list, syname); hash_buckets_expand(&buckets, symbol_set_names_list.node_count); hash_buckets_insert(arena, &buckets, hash, IntFromPtr(symbol_set_names_list.last)); } } } } } // print output linker script STREAM *stream = stream_new(); stream_printf(stream, "SECTIONS {\n" " .sy : {\n"); for (String8Node *node = symbol_set_names_list.first; node != 0; node = node->next){ stream_printf(stream, " syfirst__%S = .; *(.sy.%S); syopl__%S = .;\n", &node->string, &node->string, &node->string); } stream_printf(stream, " }\n" "}\n" "INSERT AFTER .data;\n"); os_file_write_stream(output_file_name, stream); return(0); }