implementation module CommonObjectToDisk; import StdEnv; import ExtString; import xcoff; from Relocations import relocate_text; import State, SymbolTable; USE_FREADSTRING use_freadstring normal :== normal; //use_freadstring :: *WriteOutputRecord = { file_or_memory :: !Int , offset :: !Int , string :: !{#Char} , file_n :: !Int , module_n :: !Int , state :: !*State }; class Target2 a where { WriteOutput :: !WriteOutputRecord !*a -> (!*State,*a) }; /* :: WriteState = { n_symbol_index_lists :: !Int // .text, .data and (possible) user sections , do_relocations :: !Bool , data_buffer :: *{#Char} , user_buffer :: *{#Char} }; :: *UserBuffer = { ub_section_name :: !String , ub_buffer :: *{#Char} }; */ //WriteCode import PlatformLinkOptions; :: *WriteState = { do_relocations :: !Bool , buffers :: !*{*{#Char}} , buffers_i :: !*{#Int} , text_offset :: !Int , text_buffer :: !*{#Char} }; DefaultWriteState :: !*WriteState; DefaultWriteState = { WriteState | do_relocations = True , buffers = {} , buffers_i = {} , text_offset = 0 , text_buffer = {} }; import Sections, utilities; WriteCode :: !*File !*PlatformLinkOptions !*State !*Files -> (!*File,!*PlatformLinkOptions,!*State,!*Files,!*WriteState); WriteCode pe_file platform_link_options state=:{n_xcoff_files} files #! ws = DefaultWriteState; // Create buffers #! (buffers,buffers_i,platform_link_options) = create_buffers platform_link_options; #! ws = { ws & buffers = buffers , buffers_i = buffers_i }; #! (ws,pe_file,state,files) = write_code 0 0 ws pe_file state files; = (pe_file,platform_link_options,state,files,ws); where { write_code :: !Int !Int !*WriteState !*File !*State !*Files -> !*(!*WriteState,!*File,!*State,!*Files); write_code file_n first_symbol_n ws pe_file state files | file_n >= n_xcoff_files = (ws,pe_file,state,files); // open xcoff file #! (file_name, state) = select_file_name file_n state; #! (n_symbols, state) = select_n_symbols file_n state; #! (ok,xcoff_file,files) = fopen file_name FReadData files; | not ok = abort ("Cannot read file: "+++ file_name); // ? #! (ws,pe_file,state,xcoff_file,file_n,first_symbol_n) = write_optimized ws pe_file state xcoff_file file_n first_symbol_n file_name; // close xcoff file #! (ok,files) = fclose xcoff_file files; | not ok = abort ("Error while reading file: "+++file_name); = write_code (inc file_n) first_symbol_n ws pe_file state files; } // WriteCode write_optimized :: !*WriteState !*File !*State !*File !Int Int !String -> !*(!*WriteState,!*File,!*State,!*File,!Int,!Int); write_optimized ws pe_file state=:{n_xcoff_files} xcoff_file file_n first_symbol_n file_name #! (ws,pe_file,state,xcoff_file) = select_symbol_index_lists_to_write ws pe_file state xcoff_file file_n first_symbol_n; /* | inc file_n == n_xcoff_files = (ws,pe_file,state,xcoff_file,file_n,first_symbol_n); #! (file_name2, state) = select_file_name (inc file_n) state #! (n_symbols, state) = select_n_symbols file_n state; | file_name2 == file_name = write_optimized ws pe_file state xcoff_file (inc file_n) (first_symbol_n+n_symbols) file_name; */ #! (n_symbols, state) = select_n_symbols file_n state; = (ws,pe_file,state,xcoff_file,file_n,first_symbol_n + n_symbols); import RWSDebugChoice; write_code_to_pe_files :: !Int !Bool !Int !Int !(!Int,!Int) !State !Bool !*a !*Files -> ((!*a,!(!Int,!Int),!State),!*Files) | Target2 a; write_code_to_pe_files n_xcoff_files do_relocations file_n first_symbol_n offset0 state one_pass_link pe_file files | file_n >= n_xcoff_files = ((pe_file,offset0,state),files); # (file_name, state) = select_file_name file_n state; # (n_symbols, state) = select_n_symbols file_n state; # (ok,xcoff_file,files) = fopen file_name FReadData files; | not ok //<<- file_name = abort ("Cannot read file: "+++ file_name); # (file_n,first_symbol_n,state,offset,xcoff_file,pe_file) = write_code file_name file_n do_relocations first_symbol_n offset0 state xcoff_file pe_file; #! (end1,xcoff_file) = fposition xcoff_file; # (ok,files) = fclose xcoff_file files; | not ok = abort ("Error while reading file: "+++file_name); // # (pe_file,offset,state,files) = write_code_to_pe_files n_xcoff_files do_relocations (inc file_n) first_symbol_n offset state one_pass_link pe_file files; // = (pe_file,state,files); where { /* ** file_n < n_xcoff_files */ write_code file_name file_n do_relocations first_symbol_n offset0 state xcoff_file pe_file #! (state,offset,xcoff_file,pe_file) = write_code_to_pe_file file_n do_relocations first_symbol_n offset0 state xcoff_file pe_file; | next_file_n == n_xcoff_files = (file_n,first_symbol_n,state,offset,xcoff_file,pe_file); #! (file_name2, state) = select_file_name next_file_n state # (n_symbols, state) = select_n_symbols file_n state; | file_name2 == file_name = write_code file_name next_file_n do_relocations (first_symbol_n+n_symbols) offset state xcoff_file pe_file; = (file_n,first_symbol_n + n_symbols,state,offset,xcoff_file,pe_file); where { next_file_n = inc file_n } } //import DebugUtilities; F a b :== b; // Auxillary functions /* #! (ws,pe_file,state,xcoff_file) = write_symbol_index_lists ws pe_file state xcoff_file file_n first_symbol_n; */ select_symbol_index_lists_to_write :: !*WriteState !*File !*State !*File !Int !Int -> !*(!*WriteState,!*File,!*State,!*File); select_symbol_index_lists_to_write ws=:{text_offset} pe_file state xcoff_file file_n first_symbol_n // select text symbols #! (text_symbols,state) = selacc_text_symbols file_n state; #! (ws,pe_file,state,xcoff_file,text_offset) = write_symbol_index_lists (-1) text_symbols text_offset ws pe_file state xcoff_file; // select data symbols #! (data_offset,ws) = ws!buffers_i.[0]; #! (data_symbols,state) = selacc_data_symbols file_n state; #! (ws,pe_file,state,xcoff_file,data_offset) = write_symbol_index_lists 0 data_symbols data_offset ws pe_file state xcoff_file; #! ws = { ws & text_offset = text_offset, buffers_i.[0] = data_offset }; // other symbols #! (extra_sections,state) = state!xcoff_a.[file_n].symbol_table.extra_sections; #! (ws,pe_file,state,xcoff_file) = foldSt write_user_symbol_index_list extra_sections (ws,pe_file,state,xcoff_file); /* extra_sections :: [ExtraSection] }; :: ExtraSection = { es_name :: !String , es_flags :: !Int , es_symbols :: !SymbolIndexList , es_buffer_n :: !Int }; */ = (ws,pe_file,state,xcoff_file); where { write_user_symbol_index_list extra_section=:{es_buffer_n,es_symbols} (ws,pe_file,state,xcoff_file) #! (user_offset,ws) = ws!buffers_i.[es_buffer_n]; #! (ws,pe_file,state,xcoff_file,user_offset) = write_symbol_index_lists es_buffer_n es_symbols user_offset ws pe_file state xcoff_file; #! ws = {ws & buffers_i.[es_buffer_n] = user_offset} = (ws,pe_file,state,xcoff_file); // = abort "aa"; write_symbol_index_lists :: !Int !SymbolIndexList !Int !*WriteState !*File !*State !*File -> !*(*WriteState,!*File,!*State,!*File,!Int); write_symbol_index_lists _ EmptySymbolIndex offset ws pe_file state xcoff_file = (ws,pe_file,state,xcoff_file,offset); write_symbol_index_lists buffer_n (SymbolIndex module_n symbol_list) offset ws pe_file state xcoff_file #! (symbol, state) = sel_symbol file_n module_n state; #! (marked, state) = selacc_marked_bool_a (first_symbol_n+module_n) state; | marked #! (ws,pe_file,state,xcoff_file,offset) = /*F (toString offset +++ (if (buffer_n == 0) " data" " text"))*/ write_symbol_module_to_pe_file symbol offset ws pe_file state xcoff_file; = write_symbol_index_lists buffer_n symbol_list offset ws pe_file state xcoff_file; = write_symbol_index_lists buffer_n symbol_list offset ws pe_file state xcoff_file; where { sel_data_buffer :: !Int !*WriteState -> !*(!*{#Char},!*WriteState); sel_data_buffer buffer_n ws=:{buffers} #! (buffer_n1,buffers) = replace buffers buffer_n {}; = (buffer_n1,{ws & buffers = buffers}); sel_text_buffer :: !*WriteState -> !*(!*{#Char},!*WriteState); sel_text_buffer ws=:{text_buffer} = (text_buffer,{ws & text_buffer = {} }); write_symbol_module_to_pe_file :: !Symbol !Int !*WriteState !*File !*State !*File -> !*(!*WriteState,!*File,!*State,!*File,!Int); write_symbol_module_to_pe_file (Module virtual_module_offset length virtual_address file_offset n_relocations relocations) offset ws=:{do_relocations} pe_file state xcoff_file #! (real_module_offset,state) = selacc_module_offset_a (first_symbol_n+module_n) state; #!(ok,xcoff_file) = fseek xcoff_file file_offset FSeekSet; | not ok = abort "write_symbol_module_to_pe_file: failed seek"; #! (start,text_a0,xcoff_file,ws) = case (USE_FREADSTRING ((True) && (buffer_n <> (-1))) False) of { True #! (buffer,ws) = sel_data_buffer buffer_n ws; #! aligned_offset = roundup_to_multiple offset 4; #! (length2,buffer,xcoff_file) = freadsubstring aligned_offset length buffer xcoff_file; -> (aligned_offset,buffer,xcoff_file,ws); False /* // NEW ... #! (text_buffer,ws) = sel_text_buffer ws; #! (s_text_buffer,text_buffer) = usize text_buffer; #! text_buffer = case (s_text_buffer < length) of { True // alloc text buffer -> createArray length ' '; False -> text_buffer; } #! (_,text_buffer,xcoff_file) = freadsubstring 0 length text_buffer xcoff_file; -> (0,text_buffer,xcoff_file,ws); // ... NEW */ // /* OLD ... #! (text_a0,xcoff_file) = freads xcoff_file length; -> (0,text_a0,xcoff_file,ws); //*/ } //ORIGINEEL1 /* #! (text_a0,xcoff_file) = freads xcoff_file length; #! start = 0 */ // relocate if necessary #! (text_a0,state) //(offset,pe_file,state) = case do_relocations of { False ->(text_a0,state); True #! (text_a1,state) = relocate_text module_n length /* end of JMP */ start 0 n_relocations file_n virtual_module_offset real_module_offset first_symbol_n state text_a0 virtual_address relocations; -> (text_a1,state); }; // write #! aligned_offset = roundup_to_multiple offset 4; #! (pe_file,ws) = case (buffer_n == (-1)) of { True #! pe_file = write_nop_bytes (aligned_offset - offset) pe_file; // /* OLD ... #! pe_file = fwrites text_a0 pe_file; /* #! (text_a0,pe_file) = fwritesubstring 0 length text_a0 pe_file; #! ws = { ws & text_buffer = text_a0 }; */ -> (pe_file,ws); False #! ws = USE_FREADSTRING { ws & buffers = {ws.buffers & [buffer_n] = text_a0} } (copy 0 text_a0 aligned_offset ws); // #! (_,ws) // = copy 0 text_a0 aligned_offset ws; -> (pe_file,ws); }; = (ws,pe_file,state,xcoff_file,aligned_offset + length ); where { copy :: !Int !{#Char} !Int *WriteState -> /*!*(!Int,*/ !*WriteState; // ); copy i s j d | i == size s = d; //= (j,d); = copy (inc i) s (inc j) {d & buffers.[buffer_n].[j /*+ 0 */] = s.[i]}; } // write_symbol_module_to_pe_file } // write_symbol_index_lists write_nop_bytes :: !Int !*File -> !*File; write_nop_bytes i file | i == 0 = file; = write_nop_bytes (dec i) (fwritec '\0' file); } import ExtInt; write_code_to_pe_file :: !Int !Bool !Int (!Int,!Int) !State !*File !*a -> (!State,(!Int,!Int),!*File,!*a) | Target2 a; write_code_to_pe_file file_n do_relocations first_symbol_n (text_offset0,data_offset0) state xcoff_file pe_file #! (text_symbols,state) = selacc_text_symbols file_n state; #! (state,text_offset,xcoff_file,pe_file) = write_text_to_pe_file Text text_symbols text_offset0 state xcoff_file pe_file; #! (data_symbols,state) = selacc_data_symbols file_n state; #! (state,data_offset,xcoff_file,pe_file) = write_text_to_pe_file Data data_symbols data_offset0 state xcoff_file pe_file; = (state,(text_offset,data_offset),xcoff_file,pe_file); // = write_text_to_pe_file symbols offset0 state xcoff_file pe_file; { zz Text = 0; zz Data = 1; write_text_to_pe_file :: !SymbolIndexListKind !SymbolIndexList !Int !State !*File !*a -> (!State,!Int,!*File,!*a) | Target2 a; write_text_to_pe_file _ EmptySymbolIndex offset0 state xcoff_file pe_file = (state,offset0,xcoff_file,pe_file); write_text_to_pe_file mode1 (SymbolIndex module_n symbol_list) offset0 state xcoff_file pe_file # (symbol, state) = sel_symbol file_n module_n state; # (marked, state) = selacc_marked_bool_a (first_symbol_n+module_n) state; | marked # (state, offset1,xcoff_file,pe_file) = write_text_module_to_pe_file symbol offset0 state xcoff_file pe_file; // <<- ("marked",marked); = write_text_to_pe_file mode1 symbol_list offset1 state xcoff_file pe_file; = write_text_to_pe_file mode1 symbol_list offset0 state xcoff_file pe_file; {}{ write_text_module_to_pe_file :: !Symbol !Int !State !*File !*a -> !(!State,!Int,!*File,!*a) | Target2 a; write_text_module_to_pe_file (Module virtual_module_offset length virtual_address file_offset n_relocations relocations) offset0 state xcoff_file pe_file # (real_module_offset,state) = selacc_module_offset_a o_i state; # (ok,xcoff_file) = fseek xcoff_file file_offset FSeekSet; | not ok # (file_name, state1) = select_file_name file_n state; = abort ("write_text_module_to_pe_file: could not seek in file " +++ file_name +++ "\n This error results because the application is staically linked"); // JMP ... // only in case of dynamic linking text symbols # (text_a0,xcoff_file) = case ((n_relocations * SIZE_OF_RELOCATION) <> size relocations) of { True #! text_a0_with_extra_jmp = { (createArray length '\0') & [length - 5] = toChar 0xe9 }; #! (_,text_a0_with_extra_jmp,xcoff_file) = freadsubstring 0 (length - 5) text_a0_with_extra_jmp xcoff_file; -> F ("yep1; file_n: " +++ toString file_n +++ " module_n:" +++ hex_int module_n) (text_a0_with_extra_jmp,xcoff_file); False #! (text_a0,xcoff_file) = freads xcoff_file length; -> (text_a0,xcoff_file); } // ... JMP // # (text_a0,xcoff_file) // = freads xcoff_file length; # (file_name, state) = select_file_name file_n state; | F("^" +++ (toString file_n) +++ "^^" +++ file_name) size text_a0==length #! write_output_record = { WriteOutputRecord | file_or_memory = (zz mode1), offset = offset0, string = text_a1 /* case do_relocations of { True -> text_a1; //(write_nop_bytes (aligned_offset0-offset0) text_a1); False -> text_a1; } */ , file_n = file_n , module_n = module_n , state = state1 }; #! (state2,pe_file) = WriteOutput write_output_record pe_file; = (state2,aligned_offset0+length,xcoff_file,pe_file); { aligned_offset0=(offset0+alignment_mask) bitand (bitnot alignment_mask); alignment_mask=dec (1< relocate_text 0 state text_a0; -> relocate_text module_n length /* end of JMP */ 0 0 n_relocations file_n virtual_module_offset real_module_offset first_symbol_n state text_a0 virtual_address relocations; _ -> (text_a0,state); //abort "No relocations permitted"; } } { o_i=first_symbol_n+module_n; } } } write_nop_bytes :: !Int !{#Char} -> !{#Char}; write_nop_bytes n string = (createArray n (toChar 0x90)) +++ string; select_data_or_code_symbols :: !SymbolIndexListKind !Int !State -> (!SymbolIndexList,!State); select_data_or_code_symbols Text file_n state = selacc_text_symbols file_n state; select_data_or_code_symbols Data file_n state = selacc_data_symbols file_n state;