implementation module LinkerOffsets;

import
	StdEnv;
import DebugUtilities;	
	
from Offsets import Remove_at_size;
import
	SymbolTable; 
	
/*
Remove_at_size :: !String -> !String;
Remove_at_size s = remove_at_size_i (size s-1);
		{
			remove_at_size_i -1
				= s;
			remove_at_size_i i
				| s.[i]<>'@'
					= remove_at_size_i (i-1);
					= s % (0,i-1) +++t;
					{
						t :: {#Char};
						t = createArray (size s-i) '\0';
					}
		}
*/

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

compute_module_offsets :: SymbolIndexListKind Int [*Xcoff] Int Int *{#Bool} ModuleOffsets -> (*{#Bool},!Int,!ModuleOffsets,![*Xcoff]);
compute_module_offsets _ _ [] offset0 file_symbol_index marked_bool_a module_offsets0
			= (marked_bool_a, offset0,module_offsets0, []);

						
compute_module_offsets kind base [xcoff=:{n_symbols,symbol_table=symbol_table=:{text_symbols,data_symbols,bss_symbols,symbols}}:xcoff_list] offset0 file_symbol_index marked_bool_a module_offsets0	
	# (marked_bool_a,offset1,symbols, module_offsets1)
		= compute_section_module_offsets base file_symbol_index marked_bool_a 
			(select_kind kind) symbols offset0 module_offsets0;
			  
	  (marked_bool_a,offset,module_offsets, xcoff_list)
        = compute_module_offsets kind base xcoff_list offset1 (file_symbol_index+n_symbols) marked_bool_a module_offsets1;
			
	= (marked_bool_a,offset,module_offsets,[{xcoff & symbol_table={symbol_table & symbols=symbols}}:xcoff_list]);
{

	select_kind :: !SymbolIndexListKind -> !SymbolIndexList;
	select_kind Text = text_symbols;
	select_kind Data = data_symbols;
	select_kind Bss  = bss_symbols;
};

compute_module_offsets_for_user_defined_sections :: {#Char} Int !*[*Xcoff] Int Int *{#Bool} *{#Int} -> *(.{#Bool},Int,*{#Int},[.Xcoff]);
compute_module_offsets_for_user_defined_sections _ _ [] offset0 file_symbol_index marked_bool_a module_offsets0
	= (marked_bool_a, offset0,module_offsets0, []);
compute_module_offsets_for_user_defined_sections kind base [xcoff=:{n_symbols,symbol_table=symbol_table=:{extra_sections,symbols}}:xcoff_list] offset0 file_symbol_index marked_bool_a module_offsets0	
	# (marked_bool_a,offset1,symbols, module_offsets1)
		= compute_section_module_offsets base file_symbol_index marked_bool_a 
			(select_kind kind) symbols offset0 module_offsets0;
			  
	  (marked_bool_a,offset,module_offsets, xcoff_list)
        = compute_module_offsets_for_user_defined_sections kind base xcoff_list offset1 (file_symbol_index+n_symbols) marked_bool_a module_offsets1;
			
	= (marked_bool_a,offset,module_offsets,[{xcoff & symbol_table={symbol_table & symbols=symbols}}:xcoff_list]);
{
	select_kind :: !String -> !SymbolIndexList;
	select_kind user_section_name
		#! extra_section
			= filter (\{es_name} -> user_section_name == es_name) extra_sections;
		| isEmpty extra_section
			= EmptySymbolIndex;
			=  (hd extra_section).es_symbols;
}

compute_section_module_offsets :: Int Int *{#Bool} SymbolIndexList *SymbolArray Int ModuleOffsets -> (*{#Bool},!Int,!*SymbolArray,!ModuleOffsets);
compute_section_module_offsets _ file_symbol_index marked_bool_a EmptySymbolIndex symbol_array offset0 module_offsets0
	= (marked_bool_a,offset0,symbol_array,module_offsets0 );
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]
		= 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;
		
compute_module_offset :: Int Symbol Int Int Int ModuleOffsets -> (!Int,!ModuleOffsets);
compute_module_offset 0 (Module _ length _ _ _ _) module_n offset0 file_symbol_index module_offsets0
	= (aligned_offset0+length,{module_offsets0 & [file_symbol_index+module_n] = aligned_offset0});
	
		{
			aligned_offset0=(offset0+alignment_mask) bitand (bitnot alignment_mask);
			alignment_mask=dec (1<<alignment);
			alignment = 2;
		}
		
compute_module_offset base (Module  _ length _ _ _ _) module_n offset0 file_symbol_index module_offsets0
//	| True <<- ("compute_module_offset",hex_int (base),length)
	= (base,{module_offsets1 & [file_symbol_index+module_n] = base + offset});
	{
		(offset,module_offsets1) = module_offsets0![file_symbol_index+module_n];
		
	}
	
compute_module_offset base EmptySymbol module_n offset0 file_symbol_index module_offsets0
	= abort "compute_module_offset base EmptySymbol";

//import RWSDebug, ExtInt;

	
// E :: !a !.b -> .b;
// E a b = b;

compute_imported_library_symbol_offsets :: !LibraryList !Int !Int !Int !Int !*{#Bool} !*{#Int} -> (!*{#Bool},!LibraryList,!Int,!Int,!*{#Int});
compute_imported_library_symbol_offsets EmptyLibraryList text_offset0 thunk_data_offset0 n_libraries symbol_n marked_bool_a module_offset_a0
	= (marked_bool_a,EmptyLibraryList,text_offset0,thunk_data_offset0,module_offset_a0);
compute_imported_library_symbol_offsets (Library library_name _ library_symbols n_symbols library_list0) text_offset0 thunk_data_offset0 n_libraries symbol_n marked_bool_a module_offset_a0
	# (marked_bool_a,imported_symbols,text_offset1,thunk_data_offset1,module_offset_a1)
		= compute_library_symbol_offsets library_symbols symbol_n text_offset0 thunk_data_offset0 marked_bool_a module_offset_a0;

	#  (marked_bool_a,library_list1,text_offset2,thunk_data_offset2,module_offset_a2)
		= compute_imported_library_symbol_offsets library_list0 text_offset1 thunk_data_offset1 (inc n_libraries) (symbol_n+n_symbols) marked_bool_a module_offset_a1;
	  n_imported_symbols = (text_offset1-text_offset0) / 6;

	= (marked_bool_a,Library library_name 0 imported_symbols n_imported_symbols library_list1,text_offset2,thunk_data_offset2,module_offset_a2);
	{
		compute_library_symbol_offsets :: LibrarySymbolsList Int Int Int *{#Bool} *{#Int} -> (*{#Bool},!LibrarySymbolsList,!Int,!Int,!*{#Int});
		compute_library_symbol_offsets EmptyLibrarySymbolsList symbol_n text_offset0 thunk_data_offset0 marked_bool_a module_offset_a0
			= (marked_bool_a,EmptyLibrarySymbolsList,text_offset0,thunk_data_offset0+4,module_offset_a0);
		compute_library_symbol_offsets (LibrarySymbol symbol_name symbol_list) symbol_n text_offset0 thunk_data_offset0 marked_bool_a module_offset_a0
			| marked_bool_a.[symbol_n]
				= (marked_bool_a1,LibrarySymbol symbol_name imported_symbols,text_offset1,thunk_data_offset1,module_offset_a1);
				{
					(marked_bool_a1,imported_symbols,text_offset1,thunk_data_offset1,module_offset_a1)
						= compute_library_symbol_offsets symbol_list (symbol_n+2) (text_offset0+6) (thunk_data_offset0+4) marked_bool_a 
							{module_offset_a0 & [symbol_n]=text_offset0
							,[symbol_n+1]=thunk_data_offset0
							
							};
				}
				= compute_library_symbol_offsets symbol_list (symbol_n+2) text_offset0 thunk_data_offset0 marked_bool_a module_offset_a0;
	}

/*
from DynamicLink import SetCurrentLibrary, StoreLong, GetFuncAddress;
Dcompute_imported_library_symbol_offsets :: LibraryList Int Int Int *{#Bool} *{#Int} -> (*{#Bool},!LibraryList,!Int,!*{#Int}); 
Dcompute_imported_library_symbol_offsets EmptyLibraryList thunk_data_offset0 n_libraries symbol_n marked_bool_a module_offset_a0
	= (marked_bool_a,EmptyLibraryList,thunk_data_offset0,module_offset_a0);

Dcompute_imported_library_symbol_offsets (Library library_name base_of_client_dll library_symbols n_symbols library_list0) thunk_data_offset0 n_libraries symbol_n marked_bool_a module_offset_a0
	#! (ok,library) 
		= SetCurrentLibrary library_name
	|	not ok
		=	abort "Dcompute_imported_library_symbol_offsets: library doesn't exist"

		# (library,marked_bool_a, /* imported_symbols */ _,thunk_data_offset1,module_offset_a1)
			= compute_library_symbol_offsets library library_symbols symbol_n thunk_data_offset0 marked_bool_a module_offset_a0;
		| not (CloseLibrary library)
			= abort "Dcompute_imported_library_symbol_offsets: error"
		
			# (marked_bool_a,library_list1,thunk_data_offset2, module_offset_a2)
				= Dcompute_imported_library_symbol_offsets library_list0 thunk_data_offset1 (inc n_libraries) (symbol_n+n_symbols) marked_bool_a module_offset_a1; 
		
			# n_imported_symbols 
				= (thunk_data_offset1-thunk_data_offset0) / 4;	
		
			= (marked_bool_a, Library library_name base_of_client_dll library_symbols n_symbols/* imported_symbols n_imported_symbols*/ library_list1,thunk_data_offset2,module_offset_a2); {}
	{
		compute_library_symbol_offsets :: !*Int LibrarySymbolsList Int Int *{#Bool} *{#Int} -> (!*Int,*{#Bool},!LibrarySymbolsList, !Int,!*{#Int});
		compute_library_symbol_offsets library EmptyLibrarySymbolsList symbol_n thunk_data_offset0 marked_bool_a module_offset_a0
			= (library,marked_bool_a,EmptyLibrarySymbolsList, thunk_data_offset0 /*+4*/,module_offset_a0);
		
		compute_library_symbol_offsets library (LibrarySymbol symbol_name symbol_list) symbol_n thunk_data_offset0 marked_bool_a module_offset_a0
			| marked_bool_a.[symbol_n]
				#! (func_address,library1) 
					= GetFuncAddress (Remove_at_size symbol_name) base_of_client_dll library; 
					
					#	ok	
						= StoreLong (symbol_name) thunk_data_offset0 func_address;



					|	not ok 
						= abort ("Dcompute_imported_library_symbol_offsets: can not store long");
		
						= (library2,marked_bool_a1,LibrarySymbol symbol_name imported_symbols,thunk_data_offset1,module_offset_a1);
						{
							(library2,marked_bool_a1,imported_symbols,thunk_data_offset1,module_offset_a1)
								= compute_library_symbol_offsets library1 symbol_list (symbol_n+2) (thunk_data_offset0+4) marked_bool_a 
									{module_offset_a0 & [symbol_n]= func_address,
									[symbol_n+1]= thunk_data_offset0 };
						}
						
						
						
					
				// unmarked symbol
				= compute_library_symbol_offsets library symbol_list (symbol_n+2) thunk_data_offset0 marked_bool_a module_offset_a0; 
	}
	
E :: !a .b -> .b;
E a b = b;
	
CloseLibrary :: !*Int -> !Bool;
CloseLibrary _ = 	code { 
		ccall CloseLibrary "I-I"
	};
*/