Skip to content

Commit acab989

Browse files
committed
Merge inmemlink-2, removes use of .dyo files
The compile process (can be) now fully fileless. Typical command line operation reads from .c/.h, but the code is generated (and linked) directly in memory, rather than going through the intermediate step of dyo files being written and re-read. This is slightly simpler in that it avoids the de/serialization code, but the memory management is a bit more complex. A subsequent change will probably need to reintroduce some sort of textual dump to inspect compile/fixups/link for debugging, but it wasn't necessary yet. Additionally, symbols are maintained as regular strings in the fixup array and some hashtables. It would be nice to intern these to speed up and simplify linking.
1 parent 3346218 commit acab989

15 files changed

Lines changed: 260 additions & 1084 deletions

.gitignore

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,11 @@
22
**/\#*
33
**/*.o
44
**/a.out
5-
**/*.dyo
65
/tmp*
76
x.bat
87
/third_party
98
/test/*.exe
10-
/test_codebase/
119
.vs/
12-
dyocache/
1310
tags
1411
test/x.c
1512
minilua

Makefile

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ OBJS=$(SRCS:.c=.o)
1111
dyibicc: $(OBJS)
1212
$(CC) $(CFLAGS) -o $@ $^ -ldl $(LDFLAGS)
1313

14-
dumpdyo: dumpdyo.o dyo.o hashmap.o alloc.o
15-
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
16-
1714
$(OBJS): dyibicc.h libdyibicc.h
1815

1916
minilua: dynasm/minilua.c
@@ -28,7 +25,7 @@ test: testrun.lua minilua dyibicc
2825
# Misc.
2926

3027
clean:
31-
rm -rf dyibicc dumpdyo codegen.linux.c test/*.s test/*.exe minilua minilua.exe *.dyo
28+
rm -rf dyibicc codegen.linux.c test/*.s test/*.exe minilua minilua.exe
3229
find * -type f '(' -name '*~' -o -name '*.o' ')' -exec rm {} ';'
3330
clang-format -i *.c *.h
3431

codegen.in.c

Lines changed: 126 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,7 @@ static void gen_addr(Node* node) {
216216
///| lea rax, [=>node->var->dasm_entry_label]
217217
} else {
218218
int fixup_location = codegen_pclabel();
219-
strintarray_push(&C(import_fixups), (StringInt){node->var->name, fixup_location},
220-
AL_Compile);
219+
strintarray_push(&C(fixups), (StringInt){node->var->name, fixup_location}, AL_Compile);
221220
#ifdef _MSC_VER
222221
#pragma warning(push)
223222
#pragma warning(disable : 4310) // dynasm casts the top and bottom of the 64bit arg
@@ -233,7 +232,7 @@ static void gen_addr(Node* node) {
233232

234233
// Global variable
235234
int fixup_location = codegen_pclabel();
236-
strintarray_push(&C(data_fixups), (StringInt){node->var->name, fixup_location}, AL_Compile);
235+
strintarray_push(&C(fixups), (StringInt){node->var->name, fixup_location}, AL_Compile);
237236
#ifdef _MSC_VER
238237
#pragma warning(push)
239238
#pragma warning(disable : 4310) // dynasm casts the top and bottom of the 64bit arg
@@ -2180,6 +2179,20 @@ static void assign_lvar_offsets(Obj* prog) {
21802179

21812180
#endif // SysV
21822181

2182+
void linkfixup_push(FileLinkData* fld, char* target, char* fixup, int addend) {
2183+
if (!fld->fixups) {
2184+
fld->fixups = calloc(8, sizeof(LinkFixup));
2185+
fld->fcap = 8;
2186+
}
2187+
2188+
if (fld->fcap == fld->flen) {
2189+
fld->fixups = realloc(fld->fixups, sizeof(LinkFixup) * fld->fcap * 2);
2190+
fld->fcap *= 2;
2191+
}
2192+
2193+
fld->fixups[fld->flen++] = (LinkFixup){fixup, strdup(target), addend};
2194+
}
2195+
21832196
static void emit_data(Obj* prog) {
21842197
for (Obj* var = prog; var; var = var->next) {
21852198
// outaf("var->name %s %d %d %d %d\n", var->name, var->is_function, var->is_definition,
@@ -2194,53 +2207,101 @@ static void emit_data(Obj* prog) {
21942207
int align =
21952208
(var->ty->kind == TY_ARRAY && var->ty->size >= 16) ? MAX(16, var->align) : var->align;
21962209

2197-
write_dyo_initialized_data(C(dyo_file), var->ty->size, align, var->is_static, var->is_rodata,
2198-
var->name);
2210+
// - rodata, always free existing entry in either static/extern
2211+
// global_data, and then recreate and reinitialize
2212+
//
2213+
// - if writeable data has an entry, it shouldn't be recreated. the
2214+
// dyo version doesn't reprocess kTypeInitializerDataRelocation or
2215+
// kTypeInitializerCodeRelocation; that's possibly a bug, but it'll
2216+
// need some testing to get a case where it comes up.
2217+
//
2218+
// TODO: if it changes from static to extern, is it the same
2219+
// variable? currently they're separate, so a switch causes a
2220+
// reinit, a leak, and some confusion.
2221+
//
2222+
// can't easily make a large single data segment allocation for all
2223+
// data because 1) the rodata change size link-over-link (put in
2224+
// codeseg?); 2) wdata don't move or reinit, but new ones get added
2225+
// as code evolves and we can't blow away or move the old ones.
2226+
//
2227+
// for now, just continue with individual regular aligned_allocate
2228+
// for all data objects and maintain their addresses here.
2229+
//
2230+
// LinkFixup won't work as is
2231+
// - offset is codeseg relative. it can be made a pointer for the
2232+
// codeseg imports instead because it's recreated for each compile
2233+
// anyway
2234+
// - need to remap initializer_code_relocation to name, but...
2235+
// actually we have the real address at this point now, so if the
2236+
// data was allocated it can just be written directly i think rather
2237+
// than deferred to a relocation
2238+
2239+
UserContext* uc = user_context;
2240+
bool was_freed = false;
2241+
size_t idx = var->is_static ? C(file_index) : uc->num_files;
2242+
void* prev = hashmap_get(&user_context->global_data[idx], var->name);
2243+
if (prev) {
2244+
if (var->is_rodata) {
2245+
aligned_free(prev);
2246+
was_freed = true;
2247+
} else {
2248+
// data already created and initialized, don't reinit.
2249+
continue;
2250+
}
2251+
}
2252+
2253+
void* global_data = aligned_allocate(var->ty->size, align);
2254+
memset(global_data, 0, var->ty->size);
2255+
2256+
// TODO: Is this wrong (or above)? If writable |x| in one file
2257+
// already existed and |x| in another is added, then it'll be
2258+
// silently ignored. If it's rodata it'll be silently replaced here
2259+
// by getting thrown away above and then recreated.
2260+
// Need to figure out where/how to have a duplicate symbol check.
2261+
#if 0
2262+
if (!was_freed) {
2263+
void* prev = hashmap_get(&uc->global_data[idx], strings.data[name_index]);
2264+
if (prev) {
2265+
outaf("duplicated symbol: %s\n", strings.data[name_index]);
2266+
goto fail;
2267+
}
2268+
}
2269+
#endif
2270+
// TODO: intern
2271+
hashmap_put(&uc->global_data[idx], strdup(var->name), global_data);
2272+
2273+
char* fillp = global_data;
2274+
FileLinkData* fld = &uc->files[C(file_index)];
21992275

22002276
// .data or .tdata
22012277
if (var->init_data) {
22022278
Relocation* rel = var->rel;
22032279
int pos = 0;
2204-
ByteArray bytes = {NULL, 0, 0};
22052280
while (pos < var->ty->size) {
22062281
if (rel && rel->offset == pos) {
2207-
if (bytes.len > 0) {
2208-
write_dyo_initializer_bytes(C(dyo_file), bytes.data, bytes.len);
2209-
bytes = (ByteArray){NULL, 0, 0};
2210-
}
2211-
22122282
assert(!(rel->string_label && rel->internal_code_label)); // Shouldn't be both.
22132283
assert(rel->string_label ||
22142284
rel->internal_code_label); // But should be at least one if we're here.
22152285

22162286
if (rel->string_label) {
2217-
write_dyo_initializer_data_relocation(C(dyo_file), *rel->string_label, rel->addend);
2287+
linkfixup_push(fld, *rel->string_label, fillp, rel->addend);
22182288
} else {
2219-
int file_loc;
2220-
write_dyo_initializer_code_relocation(C(dyo_file), -1, rel->addend, &file_loc);
2221-
intintarray_push(&C(pending_code_pclabels),
2222-
(IntInt){file_loc, *rel->internal_code_label}, AL_Compile);
2289+
int offset = dasm_getpclabel(&C(dynasm), *rel->internal_code_label);
2290+
*((uintptr_t*)fillp) = (uintptr_t)(fld->codeseg_base_address + offset + rel->addend);
22232291
}
22242292

22252293
rel = rel->next;
22262294
pos += 8;
2295+
fillp += 8;
22272296
} else {
2228-
bytearray_push(&bytes, var->init_data[pos], AL_Compile);
2229-
++pos;
2297+
*fillp++ = var->init_data[pos++];
22302298
}
22312299
}
22322300

2233-
if (bytes.len > 0) {
2234-
write_dyo_initializer_bytes(C(dyo_file), bytes.data, bytes.len);
2235-
bytes = (ByteArray){NULL, 0, 0};
2236-
}
2237-
2238-
write_dyo_initializer_end(C(dyo_file));
22392301
continue;
22402302
}
22412303

2242-
// .bss or .tbss
2243-
write_dyo_initializer_end(C(dyo_file));
2304+
// If no init_data, then already allocated and cleared (.bss).
22442305
}
22452306
}
22462307

@@ -2314,7 +2375,7 @@ static void emit_text(Obj* prog) {
23142375
if (fn->stack_size >= 4096) {
23152376
///| mov rax, fn->stack_size
23162377
int fixup_location = codegen_pclabel();
2317-
strintarray_push(&C(import_fixups), (StringInt){"__chkstk", fixup_location}, AL_Compile);
2378+
strintarray_push(&C(fixups), (StringInt){"__chkstk", fixup_location}, AL_Compile);
23182379
#ifdef _MSC_VER
23192380
#pragma warning(push)
23202381
#pragma warning(disable : 4310) // dynasm casts the top and bottom of the 64bit arg
@@ -2452,11 +2513,6 @@ static void emit_text(Obj* prog) {
24522513
// behavior is undefined for the other functions.
24532514
if (strcmp(fn->name, "main") == 0) {
24542515
///| mov rax, 0
2455-
C(dasm_label_main_entry) = fn->dasm_entry_label;
2456-
}
2457-
2458-
if (user_context->entry_point_name && strcmp(fn->name, user_context->entry_point_name) == 0) {
2459-
C(dasm_label_main_entry) = fn->dasm_entry_label;
24602516
}
24612517

24622518
// Epilogue
@@ -2467,51 +2523,42 @@ static void emit_text(Obj* prog) {
24672523
}
24682524
}
24692525

2470-
static void write_text_exports(Obj* prog) {
2526+
static void fill_out_text_exports(Obj* prog, char* codeseg_base_address) {
2527+
// per-file from any previous need to be cleared out for this round.
2528+
hashmap_clear_manual_key_owned_value_unowned(&user_context->exports[C(file_index)]);
2529+
24712530
for (Obj* fn = prog; fn; fn = fn->next) {
24722531
if (!fn->is_function || !fn->is_definition || !fn->is_live)
24732532
continue;
24742533

2475-
write_dyo_function_export(C(dyo_file), fn->name, fn->is_static,
2476-
dasm_getpclabel(&C(dynasm), fn->dasm_entry_label));
2534+
int offset = dasm_getpclabel(&C(dynasm), fn->dasm_entry_label);
2535+
size_t idx = fn->is_static ? C(file_index) : user_context->num_files;
2536+
hashmap_put(&user_context->exports[idx], strdup(fn->name), codeseg_base_address + offset);
24772537
}
24782538
}
24792539

2480-
static void write_imports(void) {
2481-
for (int i = 0; i < C(import_fixups).len; ++i) {
2482-
int offset = dasm_getpclabel(&C(dynasm), C(import_fixups).data[i].i);
2483-
// +2 is a hack taking advantage of the fact that import fixups are always
2484-
// of the form `mov64 rax, <ADDR>` which is encoded as:
2485-
// 48 B8 <8 byte address>
2486-
// so skip over the mov64 prefix and point directly at the address to be
2487-
// slapped into place.
2488-
offset += 2;
2489-
2490-
write_dyo_import(C(dyo_file), C(import_fixups).data[i].str, offset);
2540+
void free_link_fixups(FileLinkData* fld) {
2541+
for (int i = 0; i < fld->flen; ++i) {
2542+
free(fld->fixups[i].name);
24912543
}
2544+
free(fld->fixups);
2545+
fld->fixups = NULL;
2546+
fld->flen = 0;
2547+
fld->fcap = 0;
24922548
}
24932549

2494-
static void write_data_fixups(void) {
2495-
for (int i = 0; i < C(data_fixups).len; ++i) {
2496-
int offset = dasm_getpclabel(&C(dynasm), C(data_fixups).data[i].i);
2550+
static void fill_out_fixups(FileLinkData* fld) {
2551+
for (int i = 0; i < C(fixups).len; ++i) {
2552+
int offset = dasm_getpclabel(&C(dynasm), C(fixups).data[i].i);
24972553
// +2 is a hack taking advantage of the fact that import fixups are always
24982554
// of the form `mov64 rax, <ADDR>` which is encoded as:
24992555
// 48 B8 <8 byte address>
25002556
// so skip over the mov64 prefix and point directly at the address to be
25012557
// slapped into place.
25022558
offset += 2;
25032559

2504-
write_dyo_code_reference_to_global(C(dyo_file), C(data_fixups).data[i].str, offset);
2505-
}
2506-
}
2507-
2508-
static void update_pending_code_relocations(void) {
2509-
for (int i = 0; i < C(pending_code_pclabels).len; ++i) {
2510-
int file_loc = C(pending_code_pclabels).data[i].a;
2511-
int pclabel = C(pending_code_pclabels).data[i].b;
2512-
int offset = dasm_getpclabel(&C(dynasm), pclabel);
2513-
// outaf("update at %d, label %d, offset %d\n", file_loc, pclabel, offset);
2514-
patch_dyo_initializer_code_relocation(C(dyo_file), file_loc, offset);
2560+
char* fixup = fld->codeseg_base_address + offset;
2561+
linkfixup_push(fld, C(fixups).data[i].str, fixup, /*addend=*/0);
25152562
}
25162563
}
25172564

@@ -2520,55 +2567,53 @@ void codegen_init(void) {
25202567
dasm_growpc(&C(dynasm), 1 << 16); // Arbitrary number to avoid lots of reallocs of that array.
25212568

25222569
C(numlabels) = 1;
2523-
C(dasm_label_main_entry) = -1;
25242570
}
25252571

2526-
void codegen(Obj* prog, FILE* dyo_out) {
2527-
C(dyo_file) = dyo_out;
2528-
write_dyo_begin(C(dyo_file));
2572+
void codegen(Obj* prog, size_t file_index) {
2573+
C(file_index) = file_index;
25292574

25302575
void* globals[dynasm_globals_MAX + 1];
25312576
dasm_setupglobal(&C(dynasm), globals, dynasm_globals_MAX + 1);
25322577

25332578
dasm_setup(&C(dynasm), dynasm_actions);
25342579

25352580
assign_lvar_offsets(prog);
2536-
emit_data(prog);
25372581
emit_text(prog);
25382582

25392583
size_t code_size;
25402584
dasm_link(&C(dynasm), &code_size);
25412585

2542-
write_text_exports(prog);
2543-
write_imports();
2544-
write_data_fixups();
2545-
update_pending_code_relocations();
2586+
FileLinkData* fld = &user_context->files[C(file_index)];
2587+
if (fld->codeseg_base_address) {
2588+
free_executable_memory(fld->codeseg_base_address, fld->codeseg_size);
2589+
}
2590+
// VirtualAlloc and mmap don't accept 0.
2591+
if (code_size == 0)
2592+
code_size = 1;
2593+
unsigned int page_sized = (unsigned int)align_to_u(code_size, get_page_size());
2594+
fld->codeseg_size = page_sized;
2595+
fld->codeseg_base_address = allocate_writable_memory(page_sized);
2596+
// outaf("code_size: %zu, page_sized: %zu\n", code_size, page_sized);
2597+
2598+
fill_out_text_exports(prog, fld->codeseg_base_address);
25462599

2547-
C(code_buf) = malloc(code_size);
2600+
free_link_fixups(fld);
2601+
emit_data(prog); // This needs to point into code for fixups, so has to go late-ish.
2602+
fill_out_fixups(fld);
25482603

2549-
dasm_encode(&C(dynasm), C(code_buf));
2604+
dasm_encode(&C(dynasm), fld->codeseg_base_address);
25502605

25512606
int check_result = dasm_checkstep(&C(dynasm), DASM_SECTION_MAIN);
25522607
if (check_result != DASM_S_OK) {
25532608
outaf("check_result: 0x%08x\n", check_result);
25542609
ABORT("dasm_checkstep failed");
25552610
}
25562611

2557-
if (C(dasm_label_main_entry) >= 0) {
2558-
int offset = dasm_getpclabel(&C(dynasm), C(dasm_label_main_entry));
2559-
write_dyo_entrypoint(C(dyo_file), offset);
2560-
}
2561-
2562-
write_dyo_code(C(dyo_file), C(code_buf), code_size);
2563-
25642612
codegen_free();
25652613
}
25662614

25672615
// This can be called after a longjmp in update.
25682616
void codegen_free(void) {
2569-
if (C(code_buf)) {
2570-
free(C(code_buf));
2571-
}
25722617
if (C(dynasm)) {
25732618
dasm_free(&C(dynasm));
25742619
}

dumpdyo.c

Lines changed: 0 additions & 23 deletions
This file was deleted.

0 commit comments

Comments
 (0)