#include void sccf_builder_init(sccf_builder_t *builder) { builder->aligned = 64; sccf_init(&builder->sccf); scc_hashtable_init(&builder->str2offset, (scc_hashtable_hash_func_t)scc_strhash32, (scc_hashtable_equal_func_t)scc_strcmp); scc_hashtable_init(&builder->str2sym, (scc_hashtable_hash_func_t)scc_strhash32, (scc_hashtable_equal_func_t)scc_strcmp); scc_vec_init(builder->strtab); scc_vec_init(builder->relocs); scc_vec_init(builder->symtab); builder->entry_symbol_name = null; ///< Push null scc_vec_push(builder->strtab, (char)'\0'); ///< Push null scc_vec_push(builder->symtab, (sccf_sym_t){0}); } usize sccf_builder_add_symbol(sccf_builder_t *builder, const char *name, sccf_sym_t *sym) { usize offset = 0; offset = (usize)scc_hashtable_get(&builder->str2offset, name); const char *key = name; if (offset == 0) { offset = scc_vec_size(builder->strtab); while (*name) { scc_vec_push(builder->strtab, *name); name++; } scc_vec_push(builder->strtab, '\0'); scc_hashtable_set(&builder->str2offset, key, (void *)offset); } sym->name_offset = offset; usize sym_idx = scc_vec_size(builder->symtab); offset = (usize)scc_hashtable_get(&builder->str2sym, key); if (offset == 0) { scc_hashtable_set(&builder->str2sym, key, (void *)sym_idx); } else { LOG_ERROR("symbol %s already exists", key); } scc_vec_push(builder->symtab, *sym); return sym_idx; } usize sccf_builder_get_symbol_idx(sccf_builder_t *builder, const char *name) { usize offset = (usize)scc_hashtable_get(&builder->str2sym, name); return offset; } void sccf_builder_add_reloc(sccf_builder_t *builder, sccf_reloc_t reloc) { scc_vec_push(builder->relocs, reloc); } void sccf_builder_add_section(sccf_builder_t *builder, sccf_sect_header_t *sect_header, sccf_sect_data_t *sect_data) { Assert((usize)(sect_header->size) == scc_vec_size(*sect_data)); builder->sccf.header.sect_header_num += 1; scc_vec_push(builder->sccf.sect_headers, *sect_header); scc_vec_push(builder->sccf.sect_datas, *sect_data); } const sccf_t *sccf_builder_to_sccf(sccf_builder_t *builder) { if (builder->entry_symbol_name == null) { builder->sccf.header.entry_point = 0; } else { sccf_sym_t *sym = sccf_builder_get_symbol_unsafe(builder, builder->entry_symbol_name); if (sym == null || sym->sccf_sect_type != SCCF_SECT_CODE) { LOG_ERROR("entry symbol %s not found"); builder->sccf.header.entry_point = 0; } else { builder->sccf.header.entry_point = sym->sccf_sect_offset; } } sccf_sect_header_t sect_header; if (scc_vec_size(builder->strtab)) { sect_header = (sccf_sect_header_t){ .name = ".strtab", .info = 0, .data_size = scc_vec_size(builder->strtab), .addralign = 1, .size = scc_vec_size(builder->strtab), .sccf_sect_type = SCCF_SECT_STRTAB, }; sccf_builder_add_section(builder, §_header, (void *)&builder->strtab); } if (scc_vec_size(builder->symtab)) { sect_header = (sccf_sect_header_t){ .name = ".symtab", .info = 0, .data_size = scc_vec_size(builder->symtab), .addralign = 1, .size = scc_vec_size(builder->symtab), .sccf_sect_type = SCCF_SECT_SYMTAB, }; sccf_builder_add_section(builder, §_header, (void *)&builder->symtab); } if (scc_vec_size(builder->relocs)) { sect_header = (sccf_sect_header_t){ .name = ".relocs", .info = 0, .data_size = scc_vec_size(builder->relocs), .addralign = 1, .size = scc_vec_size(builder->relocs), .sccf_sect_type = SCCF_SECT_RELOCS, }; sccf_builder_add_section(builder, §_header, (void *)&builder->relocs); } return &builder->sccf; } void sccf_builder_to_buffer(sccf_builder_t *builder, sccf_buffer_t *buffer) { Assert(builder != null && buffer != null); sccf_write(sccf_builder_to_sccf(builder), buffer); } void sccf_builder_to_file(sccf_builder_t *builder, const char *file_path) { Assert(builder != null && file_path != null); scc_file_t fp = scc_fopen(file_path, SCC_FILE_WRITE); if (fp == null) { LOG_ERROR("file can't open %s", file_path); return; } sccf_buffer_t buffer; scc_vec_init(buffer); sccf_builder_to_buffer(builder, &buffer); usize write_size = scc_fwrite(fp, scc_vec_unsafe_get_data(buffer), scc_vec_size(buffer)); if (write_size != scc_vec_size(buffer)) { LOG_ERROR("file write failed expect write %zu but got %zu", scc_vec_size(buffer), write_size); } scc_vec_free(buffer); scc_fclose(fp); }