@@ -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+
21832196static 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.
25682616void codegen_free (void ) {
2569- if (C (code_buf )) {
2570- free (C (code_buf ));
2571- }
25722617 if (C (dynasm )) {
25732618 dasm_free (& C (dynasm ));
25742619 }
0 commit comments