implementation module LinkerOffsets;

import StdEnv;
import SymbolTable;
import State;

from ExtInt import roundup_to_multiple;

import pdLinkerOffsets;

// misschien base als parameter
//compute_offsets2 :: !Int !*State !a -> (!a,!*State) | ComputeOffsets a;
compute_offsets2 :: a .b .c ![.(a -> .(.c -> .(.b -> (.c,.b))))] -> (.c,.b);
compute_offsets2 base state offset l
	#! (offset,state)
		= foldl (\(offset,state) compute_section_offsets -> compute_section_offsets base offset state) (offset,state) 
				l; //[compute_text_section_offsets,compute_data_section_offsets];
			
	#! {library_offset,end_text_offset,end_toc_offset,end_data_offset, begin_bss_offset,end_bss_offset,end_bss_offset_a}
		= offset;
	= (offset,state);
		
compute_module_offsets2 :: (!a -> !.(Int -> !.(Int -> .(!.b -> .(!*State -> *(!.b,!*State)))))) !Int !a !.b !Int !*State -> *(!.b,!*State);
compute_module_offsets2 compute_section_offsets_per_xcoff file_n base /*[xcoff=:{n_symbols,symbol_table}:xcoff_list]*/ offset file_symbol_index state=:{n_xcoff_files}
	| file_n == n_xcoff_files
		= (offset,state);

		// body; per xcoff 		
		#! (offset,state)
			= compute_section_offsets_per_xcoff base file_n file_symbol_index offset state;
		
		#! (n_symbols,state)
			= selacc_n_symbols file_n state;
		= compute_module_offsets2 compute_section_offsets_per_xcoff (inc file_n) base offset (file_symbol_index+n_symbols) state;
	
// marked symbols; on SymbolIndexList
compute_section_module_offsets2 :: !Int !Int !Int !SymbolIndexList  !Int !*State -> (!Int,!*State);
compute_section_module_offsets2 _ file_n file_symbol_index EmptySymbolIndex offset0 state 
	= (offset0,state);
compute_section_module_offsets2 base file_n file_symbol_index (SymbolIndex module_n symbol_list) offset0 state=:{marked_bool_a}  
	| not marked_bool_a.[file_symbol_index+module_n]
		// unmarked symbols
		= compute_section_module_offsets2 base file_n file_symbol_index symbol_list offset0 state;

		# (module_symbol, state)
			= sel_symbol file_n module_n state;
		# (offset1,state)
			= compute_module_offset2 base module_symbol module_n offset0 file_symbol_index state;
		= compute_section_module_offsets2 base file_n file_symbol_index  symbol_list  offset1 state;

compute_unmarked_section_module_offsets2 :: !Int !Int !Int !SymbolIndexList  !Int !*State -> (!Int,!*State);
compute_unmarked_section_module_offsets2 _ file_n file_symbol_index EmptySymbolIndex offset0 state 
	= (offset0,state);
compute_unmarked_section_module_offsets2 base file_n file_symbol_index (SymbolIndex module_n symbol_list) offset0 state  
	# (module_symbol, state)
		= sel_symbol file_n module_n state;
	# (offset1,state)
		= compute_module_offset2 base module_symbol module_n offset0 file_symbol_index state;
		= compute_unmarked_section_module_offsets2 base file_n file_symbol_index  symbol_list offset1 state;

compute_module_offset2 :: !Int !Symbol !Int !Int !Int !*State -> (!Int,!*State);
compute_module_offset2 0 (Module {length,align=alignment}) module_n offset0 file_symbol_index state=:{module_offset_a}
	#! module_offset_a
		= {module_offset_a & [file_symbol_index+module_n] = aligned_offset0};
	= (aligned_offset0+length,{state & module_offset_a = module_offset_a});
	{
		aligned_offset0=(offset0+alignment_mask) bitand (bitnot alignment_mask);
		alignment_mask=dec (1<<alignment);
	}
	
compute_module_offset2 base (Module _) module_n _ file_symbol_index state=:{module_offset_a}
	#! (offset,module_offset)
		= module_offset_a![file_symbol_index + module_n];
	#! module_offset_a
		= {module_offset & [file_symbol_index + module_n] = base + offset};
	= (base,{state & module_offset_a = module_offset_a});
		
compute_module_offset2 _ (AliasModule _) module_n offset0 file_symbol_index state
	= (offset0,state);
compute_module_offset2 _ (ImportedFunctionDescriptorTocModule _) module_n offset0 file_symbol_index state
	= (offset0,state);


/*

//--------------------------------------------------------
// -------------
// zou eigenlijk nog wat aan gedaan moeten worden; misschien abstractie van het platform

compute_offsets :: !Int !Int !Int !LibraryList ![*Xcoff] !*{#Bool} -> (!Int,!Int,!Int,!Int,!Int,!LibraryList,!*{#Int},![*Xcoff],!*{#Bool});
compute_offsets n_xcoff_symbols n_library_symbols n_imported_symbols library_list0 xcoff_list4 marked_bool_a
	# base = 0;

	# (pef_text_section_size0,pef_toc_section_size0,module_offset_a0,xcoff_list4,marked_bool_a)
		= compute_module_offsets (n_xcoff_symbols+n_library_symbols) xcoff_list4 (n_imported_symbols<<2) marked_bool_a;

//	| True
//		= abort ("**" +++ toString pef_toc_section_size0);

	# (pef_data_section_size0,module_offset_a1,xcoff_list4)
		= compute_data_module_offsets base xcoff_list4 pef_toc_section_size0 0 module_offset_a0;


	# pef_data_section_size1 
		= (pef_data_section_size0+3) bitand (-4);

	# (pef_bss_section_end0,module_offset_a2,xcoff_list4,marked_bool_a)
		= compute_bss_module_offsets base xcoff_list4 pef_data_section_size1 0 marked_bool_a module_offset_a1;
		
	# (library_list1,pef_text_section_size1,module_offset_a3,marked_bool_a)
		= compute_imported_library_symbol_offsets library_list0 pef_text_section_size0 n_xcoff_symbols marked_bool_a module_offset_a2;
	= (pef_text_section_size0,pef_text_section_size1,pef_data_section_size0,pef_data_section_size1,pef_bss_section_end0,library_list1,module_offset_a3,xcoff_list4,marked_bool_a);

//:: *ModuleOffsets :== *{#Int};


// on Xcoff
compute_module_offsets :: Int [*Xcoff] Int *{#Bool} -> (!Int,!Int,!ModuleOffsets,![*Xcoff],*{#Bool});
compute_module_offsets n_symbols xcoff_list toc_offset0 marked_bool_a
	= compute_files_module_offsets xcoff_list 0 toc_offset0 0 (createArray n_symbols 0) marked_bool_a;
	{
		compute_files_module_offsets :: ![*Xcoff] Int Int Int ModuleOffsets *{#Bool} -> (!Int,!Int,!ModuleOffsets,![*Xcoff],*{#Bool});
		compute_files_module_offsets [] text_offset0 toc_offset0 file_symbol_index module_offsets0 marked_bool_a
			= (text_offset0,toc_offset0,module_offsets0,[],marked_bool_a);
			
		compute_files_module_offsets [xcoff=:{n_symbols,symbol_table}:xcoff_list] text_offset0 toc_offset0 file_symbol_index module_offsets0 marked_bool_a
			#! (text_offsetN,toc_offsetN,module_offsetsN,xcoff_listN,marked_bool_aN)
				= compute_files_module_offsets xcoff_list text_offset1 toc_offset1 (file_symbol_index+n_symbols) module_offsets3 marked_bool_a1;
			= (text_offsetN,toc_offsetN,module_offsetsN,[{xcoff & symbol_table = {symbol_table & symbols = symbols2}} : xcoff_listN],marked_bool_aN);
			{
				base = 0;
				
				(text_offset1,module_offsets1,marked_bool_a1,symbols1)
					= compute_section_module_offsets base file_symbol_index marked_bool_a symbol_table.text_symbols symbols text_offset0 module_offsets0;

				(toc_offset1,module_offsets2,symbols2)
					= compute_data_section_module_offsets base file_symbol_index symbol_table.toc_symbols symbols1 toc_offset0 module_offsets1;

				module_offsets3
					= compute_toc0_module_offset file_symbol_index symbol_table.toc0_symbol module_offsets2;
					
				symbols=symbol_table.symbols;
			}
	}

compute_bss_module_offsets :: !Int ![*Xcoff] Int Int !*{#Bool} ModuleOffsets -> (!Int,!ModuleOffsets,![*Xcoff],!*{#Bool});
compute_bss_module_offsets _ [] bss_offset0 file_symbol_index marked_bool_a module_offsets
	= (bss_offset0,module_offsets,[],marked_bool_a);

compute_bss_module_offsets base [xcoff=:{n_symbols,symbol_table}:xcoff_list] bss_offset0 file_symbol_index marked_bool_a module_offsets
	# (bss_offset1,module_offsets,marked_bool_a,symbols) 
		= compute_section_module_offsets base file_symbol_index marked_bool_a symbol_table.bss_symbols symbol_table.symbols bss_offset0 module_offsets;
	#! (bss_offset2,module_offsets,xcoff_list,marked_bool_a)
		= compute_bss_module_offsets base xcoff_list bss_offset1 (file_symbol_index+n_symbols) marked_bool_a module_offsets;
	= (bss_offset2,module_offsets,[{xcoff & symbol_table = {symbol_table & symbols = symbols}} : xcoff_list],marked_bool_a);

compute_data_module_offsets :: !Int ![*Xcoff] !Int !Int ModuleOffsets -> (!Int,!ModuleOffsets,![*Xcoff]);
compute_data_module_offsets _ [] data_offset0 file_symbol_index module_offsets0
	= (data_offset0,module_offsets0,[]);

compute_data_module_offsets base [xcoff=:{n_symbols,symbol_table}:xcoff_list] data_offset0 file_symbol_index module_offsets
	# (data_offset1,module_offsets,symbols) 
		= compute_data_section_module_offsets base file_symbol_index symbol_table.data_symbols symbol_table.symbols data_offset0 module_offsets;
	#! (data_offset2,module_offsets,xcoff_list)
		= compute_data_module_offsets base xcoff_list data_offset1 (file_symbol_index+n_symbols) module_offsets;
	= (data_offset2,module_offsets,[{xcoff & symbol_table = {symbol_table & symbols = symbols}} : xcoff_list]);
	
/*	
// on SymbolIndexLists  
compute_toc0_module_offset file_symbol_index EmptySymbolIndex module_offsets
	=	module_offsets;
compute_toc0_module_offset file_symbol_index (SymbolIndex module_n EmptySymbolIndex) module_offsets
	=	{module_offsets & [file_symbol_index+module_n] = 32768};
*/

// marked symbols
compute_section_module_offsets :: Int Int *{#Bool} SymbolIndexList *SymbolArray Int ModuleOffsets -> (!Int,!ModuleOffsets,*{#Bool},*SymbolArray);
compute_section_module_offsets _ file_symbol_index marked_bool_a EmptySymbolIndex symbol_array offset0 module_offsets0
	= (offset0,module_offsets0,marked_bool_a,symbol_array);
compute_section_module_offsets base file_symbol_index marked_bool_a (SymbolIndex module_n symbol_list) symbol_array=:{[module_n]=module_symbol} offset0 module_offsets0
	| not marked_bool_a.[file_symbol_index+module_n]
		// unmarked symbols
		= compute_section_module_offsets base file_symbol_index marked_bool_a symbol_list symbol_array offset0 module_offsets0;
		
		# (offset1,module_offsets1)
			= compute_module_offset base module_symbol module_n offset0 file_symbol_index module_offsets0;
		= compute_section_module_offsets base file_symbol_index marked_bool_a symbol_list symbol_array offset1 module_offsets1;

// unmarked symbols
compute_data_section_module_offsets :: Int Int SymbolIndexList *SymbolArray Int ModuleOffsets -> (!Int,!ModuleOffsets,*SymbolArray);
compute_data_section_module_offsets _ file_symbol_index EmptySymbolIndex symbol_array0 offset0 module_offsets0
	= (offset0,module_offsets0,symbol_array0);

compute_data_section_module_offsets base file_symbol_index (SymbolIndex module_n symbol_list) symbol_array=:{[module_n]=module_symbol} offset0 module_offsets0
	# (offset1,module_offsets1)
		= compute_module_offset base module_symbol module_n offset0 file_symbol_index module_offsets0;	
	= compute_data_section_module_offsets base file_symbol_index symbol_list symbol_array offset1 module_offsets1;
*/

