linker3.icl 73.9 KB
Newer Older
Diederik van Arkel's avatar
Diederik van Arkel committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
implementation module linker3;

import StdFile,StdArray,StdClass,StdEnum,StdInt,StdBool,StdChar;
from StdMisc import abort;
from StdList import ++;
from StdString import %;

import linker2,linker_resources;
import xcoff_linker;

// RWS (!=);
(!=) a b :== a<>b;

u_char_array_slice :: !*{#Char} !Int !Int -> (!*{#Char},!*{#Char});
u_char_array_slice array begin_index end_index = code {
		push_a 0
	.d 1 2 ii
		jsr	sliceAC
	.o 1 0 
};

// RWS (CHAR);
(CHAR) string i :== string.[i];

// RWS (BYTE);
(BYTE) string i :== toInt (string.[i]);

// RWS (LONG);
(LONG) string i
	= (string BYTE i<<24) bitor (string BYTE (i+1)<<16) bitor (string BYTE (i+2)<<8) bitor (string BYTE (i+3));

read_long :: *{#Char} Int -> (!Int,!*{#Char});
read_long a=:{[i]=e0,[i1]=e1,[i2]=e2,[i3]=e3} i
	= ((toInt e0<<24) bitor (toInt e1<<16) bitor (toInt e2<<8) bitor (toInt e3),a);
{
	i1=i+1;
	i2=i+2;
	i3=i+3;
}

/*
PRINT_STRING s	| !error = s; {}{ (error,_)=ferror (fwrites s stderr); }
PRINT_INT i 	| !error = i; {}{ (error,_)=ferror (fwritec ' ' (fwritei i stderr)); }
*/

:: *Sections = Sections !*String !*String !Sections | EndSections;

create_xcoff_boolean_array :: Int Int Int Int LibraryList [*Xcoff] -> (!*{#Bool},!*{#Int},!*{#*Xcoff});
create_xcoff_boolean_array n_xcoff_files n_xcoff_symbols n_libraries n_library_symbols library_list list0
	=	(createArray (n_xcoff_symbols+n_library_symbols) False,offset_array1,xcoff_a);
	{
		(offset_array1,xcoff_a) = fill_offsets 0 0 list0 (createArray (n_xcoff_files+n_libraries) 0) (xcoff_array n_xcoff_files);

		xcoff_array :: Int -> !*{#*Xcoff};
		xcoff_array n = { empty_xcoff \\ i<-[0..dec n]};
		
		fill_offsets :: Int Int [*Xcoff] *{#Int} *{#*Xcoff} -> (!*{#Int},!*{#*Xcoff});
		fill_offsets file_n offset [] offset_array xcoff_a
			= (fill_library_offsets library_list file_n offset offset_array,xcoff_a);
		fill_offsets file_n offset [xcoff=:{n_symbols}:xcoff_list] offset_array xcoff_a
			= fill_offsets (inc file_n) (offset+n_symbols) xcoff_list {offset_array & [file_n]=offset} {xcoff_a & [file_n]=xcoff};
		
		fill_library_offsets :: LibraryList Int Int *{#Int} -> *{#Int};
		fill_library_offsets EmptyLibraryList file_n offset offset_array
			= offset_array;
		fill_library_offsets (Library _ symbols n_symbols libraries) file_n offset offset_array
			= fill_library_offsets libraries (inc file_n) (offset+n_symbols) {offset_array & [file_n]=offset};
	}

:: OffsetArray :== {#Int};

/*
mark_toc0_symbols :: Int *{#Bool} [*Xcoff] -> (!*{#Bool},![*Xcoff]);
mark_toc0_symbols file_symbol_index marked_bool_a0 []
	= (marked_bool_a0,[]);
mark_toc0_symbols file_symbol_index marked_bool_a0 [xcoff_file0=:{symbol_table=:{toc0_symbol},n_symbols}:xcoff_files0]
	=	case toc0_symbol of {
			EmptySymbolIndex
				-> (marked_bool_a1,[xcoff_file0:xcoff_files1]);
			(SymbolIndex module_n EmptySymbolIndex)
				-> ({marked_bool_a1 & [file_symbol_index+module_n]=True},[xcoff_file0:xcoff_files1]);
		}
	{
		(marked_bool_a1,xcoff_files1) = mark_toc0_symbols (file_symbol_index+n_symbols) marked_bool_a0 xcoff_files0;
	}	
*/

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

compute_module_offsets :: Int [Xcoff] Int {#Bool} -> (!Int,!Int,!ModuleOffsets);
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);
	{
		compute_files_module_offsets :: [Xcoff] Int Int Int ModuleOffsets -> (!Int,!Int,!ModuleOffsets);
		compute_files_module_offsets [] text_offset0 toc_offset0 file_symbol_index module_offsets0
			= (text_offset0,toc_offset0,module_offsets0);
		compute_files_module_offsets [xcoff=:{n_symbols}:xcoff_list] text_offset0 toc_offset0 file_symbol_index module_offsets0
			= compute_files_module_offsets xcoff_list text_offset1 toc_offset1 (file_symbol_index+n_symbols) module_offsets3;
			{
				(text_offset1,module_offsets1)
					= compute_section_module_offsets file_symbol_index marked_bool_a symbol_table.text_symbols symbols text_offset0 module_offsets0;
				(toc_offset1,module_offsets2)
					= compute_data_section_module_offsets file_symbol_index symbol_table.toc_symbols symbols toc_offset0 module_offsets1;
				module_offsets3
					= compute_toc0_module_offset file_symbol_index symbol_table.toc0_symbol module_offsets2;
					
				symbol_table=xcoff.symbol_table;
				symbols=symbol_table.symbols;
			}
	}

	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};

compute_bss_module_offsets :: [Xcoff] Int Int {#Bool} ModuleOffsets -> (!Int,!ModuleOffsets);
compute_bss_module_offsets [] bss_offset0 file_symbol_index marked_bool_a module_offsets0
	= (bss_offset0,module_offsets0);
compute_bss_module_offsets [xcoff=:{n_symbols}:xcoff_list] bss_offset0 file_symbol_index marked_bool_a module_offsets0
	= compute_bss_module_offsets xcoff_list bss_offset1 (file_symbol_index+n_symbols) marked_bool_a module_offsets1;
	{
		(bss_offset1,module_offsets1)
			= compute_section_module_offsets file_symbol_index marked_bool_a symbol_table.bss_symbols symbol_table.symbols bss_offset0 module_offsets0;
		symbol_table=xcoff.symbol_table;
	}

compute_data_module_offsets :: [Xcoff] Int Int ModuleOffsets -> (!Int,!ModuleOffsets);
compute_data_module_offsets [] data_offset0 file_symbol_index module_offsets0
	= (data_offset0,module_offsets0);
compute_data_module_offsets [xcoff=:{n_symbols}:xcoff_list] data_offset0 file_symbol_index module_offsets0
	= compute_data_module_offsets xcoff_list data_offset1 (file_symbol_index+n_symbols) module_offsets1;
	{
		(data_offset1,module_offsets1)
			= compute_data_section_module_offsets file_symbol_index symbol_table.data_symbols symbol_table.symbols data_offset0 module_offsets0;
		symbol_table=xcoff.symbol_table;
	}

	compute_section_module_offsets :: Int {#Bool} SymbolIndexList SymbolArray Int ModuleOffsets -> (!Int,!ModuleOffsets);
	compute_section_module_offsets file_symbol_index marked_bool_a EmptySymbolIndex symbol_array offset0 module_offsets0
		= (offset0,module_offsets0);
	compute_section_module_offsets 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 file_symbol_index marked_bool_a symbol_list symbol_array offset0 module_offsets0;
			= compute_section_module_offsets file_symbol_index marked_bool_a symbol_list symbol_array offset1 module_offsets1;
			{
				(offset1,module_offsets1)=compute_module_offset module_symbol module_n offset0 file_symbol_index module_offsets0;
			}

	compute_data_section_module_offsets :: Int SymbolIndexList SymbolArray Int ModuleOffsets -> (!Int,!ModuleOffsets);
	compute_data_section_module_offsets file_symbol_index EmptySymbolIndex symbol_array offset0 module_offsets0
		= (offset0,module_offsets0);
	compute_data_section_module_offsets file_symbol_index (SymbolIndex module_n symbol_list) symbol_array=:{[module_n]=module_symbol} offset0 module_offsets0
		= compute_data_section_module_offsets file_symbol_index symbol_list symbol_array offset1 module_offsets1;
		{
			(offset1,module_offsets1)=compute_module_offset module_symbol module_n offset0 file_symbol_index module_offsets0;	
		}

		compute_module_offset :: Symbol Int Int Int ModuleOffsets -> (!Int,!ModuleOffsets);
		compute_module_offset (Module {length,align=alignment}) 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);
			}
		compute_module_offset (AliasModule _) module_n offset0 file_symbol_index module_offsets0
			= (offset0,module_offsets0);
		compute_module_offset (ImportedFunctionDescriptorTocModule _) module_n offset0 file_symbol_index module_offsets0
			= (offset0,module_offsets0);

::	TocTable = Toc !TocElem !.TocTable !.TocTable | EmptyTocTable;
::	TocElem = {global_module_n::!Int,symbol_n::!Int,offset::!Int};

insert_exported_symbol_in_toc_table :: Int Int Int Int Int Int *{!Symbol} {#Int} !*TocTable -> (!*{!Symbol},!*TocTable);
insert_exported_symbol_in_toc_table file_symbol_index symbol_module_n virtual_module_offset first_relocation_n relocation_symbol_n relocation_symbol_offset symbol_a=:{[relocation_symbol_n]=relocation_symbol} offset_a toc_table0
	= case relocation_symbol of {
		ImportedLabel {implab_file_n=imported_file_n,implab_symbol_n=symbol_n}
			| imported_file_n<0
				->	insert_symbol_in_toc_table (offset_a.[size offset_a+imported_file_n]+symbol_n) relocation_symbol_offset symbol_a toc_table0;
				->	insert_symbol_in_toc_table (offset_a.[imported_file_n]+symbol_n) relocation_symbol_offset symbol_a toc_table0;
		ImportedLabelPlusOffset {implaboffs_file_n=imported_file_n,implaboffs_symbol_n=symbol_n,implaboffs_offset=offset}
			->	insert_symbol_in_toc_table (offset_a.[imported_file_n]+symbol_n) (relocation_symbol_offset+offset) symbol_a toc_table0;
		Module {module_offset=offset}
			->	insert_symbol_in_toc_table (file_symbol_index+relocation_symbol_n) (relocation_symbol_offset-offset) symbol_a toc_table0;
		Label {label_offset=offset}
			->	insert_symbol_in_toc_table (file_symbol_index+relocation_symbol_n) (relocation_symbol_offset-offset) symbol_a toc_table0;
		ImportedFunctionDescriptor {implab_file_n,implab_symbol_n}
			->	({symbol_a & [symbol_module_n] = ImportedFunctionDescriptorTocModule {
					imptoc_offset = virtual_module_offset,imptoc_file_n=implab_file_n,imptoc_symbol_n=implab_symbol_n
				  }},toc_table0);

	  }
	{
		insert_symbol_in_toc_table :: Int Int *SymbolArray *TocTable -> (!*SymbolArray,!*TocTable);
		insert_symbol_in_toc_table new_symbol_n new_offset symbol_a0 EmptyTocTable
			=	(symbol_a0,Toc {global_module_n=file_symbol_index+symbol_module_n,symbol_n=new_symbol_n,offset=new_offset} EmptyTocTable EmptyTocTable);
		insert_symbol_in_toc_table new_symbol_n new_offset symbol_a0 t=:(Toc toc_elem=:{symbol_n,offset} left right)
			| new_symbol_n<symbol_n
				=	(symbol_a1,Toc toc_elem left1 right); {
					(symbol_a1,left1) = insert_symbol_in_toc_table new_symbol_n new_offset symbol_a0 left;
				}
			| new_symbol_n>symbol_n
				=	(symbol_a1,Toc toc_elem left right1); {
					(symbol_a1,right1) = insert_symbol_in_toc_table new_symbol_n new_offset symbol_a0 right;
				}
			| new_offset==offset
				=	({symbol_a0 & [symbol_module_n]=AliasModule {
						alias_module_offset = virtual_module_offset,
						alias_first_relocation_n = first_relocation_n,
						alias_global_module_n = toc_elem.global_module_n
					  }},
//					  t
					  Toc toc_elem left right
					  );
			| new_offset<offset
				=	(symbol_a1,Toc toc_elem left1 right); {
					(symbol_a1,left1) = insert_symbol_in_toc_table new_symbol_n new_offset symbol_a0 left;
				}
				=	(symbol_a1,Toc toc_elem left right1); {
					(symbol_a1,right1) = insert_symbol_in_toc_table new_symbol_n new_offset symbol_a0 right;
				}
	}

split_data_symbol_lists_of_files2 :: {#Int} {#Bool} Sections [*Xcoff] *TocTable -> (!Sections,![*Xcoff],!*TocTable);
split_data_symbol_lists_of_files2 offset_a marked_bool_a sections xcoff_list toc_table0
	=	split_data_symbol_lists_of_files2 0 sections xcoff_list toc_table0;
	{
		split_data_symbol_lists_of_files2 :: Int Sections [*Xcoff] *TocTable -> (!Sections,![*Xcoff],!*TocTable);
		split_data_symbol_lists_of_files2 file_symbol_index EndSections [] toc_table0
			= (EndSections,[],toc_table0);
		split_data_symbol_lists_of_files2 file_symbol_index (Sections text_section data_section0 sections0) [xcoff=:{n_symbols,symbol_table,data_relocations,header={data_v_address}}:xcoff_list0] toc_table0 
		= (	Sections text_section data_section1 sections1,
			[ {xcoff & symbol_table={symbol_table & toc_symbols=toc_symbols1,data_symbols=data_symbols1,symbols=symbol_table2 }} : xcoff_list1],
			toc_table2
	  	);
		{
			(toc_symbols1,data_symbols1,symbol_table1,data_section1,toc_table1)
				= split_data_symbol_list2 symbol_table.data_symbols symbol_table.symbols data_section0 toc_table0;
			(sections1,xcoff_list1,toc_table2)
				= split_data_symbol_lists_of_files2 (file_symbol_index+n_symbols) sections0 xcoff_list0 toc_table1;
			symbol_table2 = case symbol_table.toc0_symbol of {
				SymbolIndex toc0_index EmptySymbolIndex
					-> remove_unmarked_symbols (inc toc0_index) n_symbols file_symbol_index marked_bool_a
						(remove_unmarked_symbols 0 toc0_index file_symbol_index marked_bool_a symbol_table1);
				EmptySymbolIndex
					-> remove_unmarked_symbols 0 n_symbols file_symbol_index marked_bool_a symbol_table1;
			}

		split_data_symbol_list2 :: SymbolIndexList *SymbolArray *String *TocTable -> (!SymbolIndexList,!SymbolIndexList,!*SymbolArray,!*String,!*TocTable);
		split_data_symbol_list2 EmptySymbolIndex symbol_array0 data_section0 toc_table0
			= (EmptySymbolIndex,EmptySymbolIndex,symbol_array0,data_section0,toc_table0);
		split_data_symbol_list2 (SymbolIndex module_n symbol_list) symbol_array0=:{[module_n]=module_symbol} data_section0 toc_table0
			| not marked_bool_a.[file_symbol_index+module_n]
				= split_data_symbol_list2 symbol_list symbol_array0 data_section0 toc_table0;
				= case module_symbol of {
					Module {section_n=TOC_SECTION,module_offset=virtual_module_offset,length=4,first_relocation_n,end_relocation_n}
						| first_relocation_n+1==end_relocation_n && relocation_type==R_POS && relocation_size==0x1f
							-> (SymbolIndex module_n toc_symbols,data_symbols,symbol_array2,data_section2,toc_table2);
							{
								(toc_symbols,data_symbols,symbol_array2,data_section2,toc_table2)
									= split_data_symbol_list2 symbol_list symbol_array1 data_section1 toc_table1;
								(symbol_array1,toc_table1)
									= insert_exported_symbol_in_toc_table file_symbol_index module_n virtual_module_offset first_relocation_n
										relocation_symbol_n relocation_symbol_offset symbol_array0 offset_a toc_table0;
							}
						{
							relocation_type=data_relocations BYTE (relocation_index+9);
							relocation_size=data_relocations BYTE (relocation_index+8);
							relocation_symbol_n=(inc (data_relocations LONG (relocation_index+4))) >> 1;
							//relocation_offset=data_relocations LONG relocation_index;

							relocation_index=first_relocation_n * SIZE_OF_RELOCATION;					
	
							(relocation_symbol_offset,data_section1) = read_long data_section0 (virtual_module_offset-data_v_address);	
						}
					Module {section_n=TOC_SECTION}
						-> (SymbolIndex module_n toc_symbols,data_symbols,symbol_array1,data_section1,toc_table1); {
							(toc_symbols,data_symbols,symbol_array1,data_section1,toc_table1)
								= split_data_symbol_list2 symbol_list symbol_array0 data_section0 toc_table0;
						}
					Module {section_n=DATA_SECTION}
						-> (toc_symbols,SymbolIndex module_n data_symbols,symbol_array1,data_section1,toc_table1); {
							(toc_symbols,data_symbols,symbol_array1,data_section1,toc_table1)
								= split_data_symbol_list2 symbol_list symbol_array0 data_section0 toc_table0;
						};
				}
		
			remove_unmarked_symbols :: !Int !Int !Int !{#Bool} !*SymbolArray -> *SymbolArray;
			remove_unmarked_symbols index n_symbols first_symbol_index marked_bool_a symbols
				| index>=n_symbols
					= symbols;
				| marked_bool_a.[first_symbol_index+index]
					= remove_unmarked_symbols (inc index) n_symbols first_symbol_index marked_bool_a symbols;
				# (symbol,symbols) = uselect symbols index;
				= case symbol of {
					Module {section_n=TOC_SECTION,module_offset=virtual_module_offset,length=4,first_relocation_n,end_relocation_n}
						| first_relocation_n+1==end_relocation_n
							-> remove_unmarked_symbols (inc index) n_symbols first_symbol_index marked_bool_a symbols;
					_
						-> remove_unmarked_symbols (inc index) n_symbols first_symbol_index marked_bool_a { symbols & [index]=EmptySymbol };
				}
		}
	}

compute_imported_library_symbol_offsets :: LibraryList Int Int !{#Bool} *{#Int} -> (!LibraryList,!Int,!*{#Int});
compute_imported_library_symbol_offsets library_list text_offset symbol_n marked_bool_a module_offset_a
	# (library_list,text_offset,_,module_offset_a)
		= compute_imported_library_symbol_offsets_lp library_list text_offset 0 symbol_n module_offset_a;
		with {
			compute_imported_library_symbol_offsets_lp :: LibraryList Int Int Int *{#Int} -> (!LibraryList,!Int,!Int,!*{#Int});
			compute_imported_library_symbol_offsets_lp EmptyLibraryList text_offset toc_offset symbol_n module_offset_a
				=	(EmptyLibraryList,text_offset,toc_offset,module_offset_a);
			compute_imported_library_symbol_offsets_lp (Library library_name library_symbols n_symbols library_list) text_offset0 toc_offset symbol_n module_offset_a
			#	(imported_symbols,text_offset1,toc_offset,module_offset_a)
					= compute_library_symbol_offsets library_symbols symbol_n text_offset0 toc_offset module_offset_a;
						with {
							compute_library_symbol_offsets :: LibrarySymbolsList Int Int Int *{#Int} -> (!LibrarySymbolsList,!Int,!Int,!*{#Int});
							compute_library_symbol_offsets EmptyLibrarySymbolsList symbol_n text_offset toc_offset module_offset_a
								= (EmptyLibrarySymbolsList,text_offset,toc_offset,module_offset_a);
							compute_library_symbol_offsets (LibrarySymbol symbol_name symbol_list) symbol_n text_offset toc_offset module_offset_a
								| marked_bool_a.[symbol_n]
									# (imported_symbols,text_offset,toc_offset,module_offset_a)
										= compute_library_symbol_offsets symbol_list (symbol_n+2) (text_offset+24) (toc_offset+4)
											{module_offset_a & [symbol_n]=text_offset,[symbol_n+1]=toc_offset};
									= (LibrarySymbol symbol_name imported_symbols,text_offset,toc_offset,module_offset_a);
									= compute_library_symbol_offsets symbol_list (symbol_n+2) text_offset toc_offset module_offset_a;
						}
				(library_list,text_offset,toc_offset,module_offset_a)
					= compute_imported_library_symbol_offsets_lp library_list text_offset1 toc_offset (symbol_n+n_symbols) module_offset_a;
				n_imported_symbols2 = (text_offset1-text_offset0) / 12;
			=	(Library library_name imported_symbols n_imported_symbols2 library_list,text_offset,toc_offset,module_offset_a);
		}
	= (library_list,text_offset,module_offset_a);


(FWI) infixl;
(FWI) f i :== fwritei i f;

(FWS) infixl;
(FWS) f s :== fwrites s f;

(FWC) infixl;
(FWC) f c :== fwritec c f;

(FWZ) infixl;
(FWZ) f i :== write_zero_bytes_to_file i f;

write_code_to_output_files :: [Xcoff] Int {#Bool} {#Int} {#Int} SymbolsArray Bool Sections !*File *Files -> (![*String],!*File,!*Files,![Xcoff]);
write_code_to_output_files [] first_symbol_n marked_bool_a module_offset_a marked_offset_a0 symbols_a one_pass_link sections pef_file0 files0
	= ([],pef_file0,files0,[]);
write_code_to_output_files [xcoff=:{n_symbols,header}:xcoff_list] first_symbol_n marked_bool_a module_offset_a marked_offset_a0 symbols_a one_pass_link (Sections text_section data_section sections) pef_file0 files0
	| one_pass_link && size text_section==header.text_section_size
		= let! {
			xcoff1= {xcoff & text_relocations="",symbol_table={xcoff.symbol_table & text_symbols = EmptySymbolIndex}};
		} in
			([data_section1 : data_strings],pef_file2,files1,[xcoff1 :xcoff_list1]);
		{
			(pef_file1,data_section1)
				= write_code_to_pef_file xcoff first_symbol_n marked_bool_a module_offset_a marked_offset_a0 symbols_a text_section data_section pef_file0;
			(data_strings,pef_file2,files1,xcoff_list1)
				= write_code_to_output_files xcoff_list (first_symbol_n+n_symbols) marked_bool_a module_offset_a marked_offset_a0 symbols_a one_pass_link sections pef_file1 files0;
		}
	| one_pass_link && size text_section==0
		= let! {
			xcoff1= {xcoff & text_relocations="",symbol_table={xcoff.symbol_table & text_symbols = EmptySymbolIndex}};
		} in
		  if (ok0 && ok1 && ok2)
			([data_section1 : data_strings],pef_file2,files3,[xcoff1 :xcoff_list1])
			(abort "Read error");
		{
			(ok0,xcoff_file0,files1)	= fopen header.file_name FReadData files0;
			(ok1,xcoff_file1)			= fseek xcoff_file0 header.text_section_offset FSeekSet;
			(text_string,xcoff_file2)	= freads xcoff_file1 header.text_section_size;
			(ok2,files2) 				= fclose xcoff_file2 files1;

			(pef_file1,data_section1)
				= write_code_to_pef_file xcoff first_symbol_n marked_bool_a module_offset_a marked_offset_a0 symbols_a text_string data_section pef_file0;

			(data_strings,pef_file2,files3,xcoff_list1)
				= write_code_to_output_files xcoff_list (first_symbol_n+n_symbols) marked_bool_a module_offset_a marked_offset_a0 symbols_a one_pass_link sections pef_file1 files2;
		};
		= let! {
			xcoff1= {xcoff & text_relocations="",symbol_table={xcoff.symbol_table & text_symbols = EmptySymbolIndex}};
		} in
		  if (ok0 && ok1 && ok2 && ok3)
			([data_string1 : data_strings],pef_file2,files3,[xcoff1 : xcoff_list1])
			(abort "Read error");
		{
			(ok0,xcoff_file0,files1)	= fopen header.file_name FReadData files0;

			(ok1,xcoff_file1)			= fseek xcoff_file0 header.text_section_offset FSeekSet;
			(text_string,xcoff_file2)	= freads xcoff_file1 header.text_section_size;

			(ok2,xcoff_file3)			= fseek xcoff_file2 header.data_section_offset FSeekSet;
			(data_string,xcoff_file4)	= freads xcoff_file3 header.data_section_size;

			(ok3,files2) 				= fclose xcoff_file4 files1;

			(pef_file1,data_string1)
				 = write_code_to_pef_file xcoff first_symbol_n marked_bool_a module_offset_a marked_offset_a0 symbols_a text_string data_string pef_file0;
			(data_strings,pef_file2,files3,xcoff_list1)
				= write_code_to_output_files xcoff_list (first_symbol_n+n_symbols) marked_bool_a module_offset_a marked_offset_a0 symbols_a one_pass_link sections pef_file1 files2;
		};

write_code_to_pef_file :: Xcoff Int {#Bool} {#Int} {#Int} SymbolsArray !*String *String *File -> (!*File,!*String);
write_code_to_pef_file
		{header={file_name,text_section_offset,text_section_size,data_section_offset,data_section_size,text_v_address,data_v_address},
				 symbol_table={text_symbols,symbols,toc0_symbol},text_relocations,data_relocations}
		first_symbol_n marked_bool_a module_offset_a marked_offset_a0 symbols_a text_section data_section pef_file0
	=	write_text_to_pef_file text_symbols 0 symbols text_section data_section pef_file0;
	{
		write_text_to_pef_file :: SymbolIndexList Int SymbolArray *String *String *File -> (!*File,!*String);
		write_text_to_pef_file EmptySymbolIndex offset0 symbol_table text_a0 data_section pef_file0
			= (pef_file0,data_section);
		write_text_to_pef_file (SymbolIndex module_n symbol_list) offset0 symbol_table=:{[module_n] = symbol} text_a0 data_section pef_file0
			| marked_bool_a.[first_symbol_n+module_n]
				= write_text_to_pef_file symbol_list offset1 symbol_table text_a1 data_section1 pef_file1;
				{
					(text_a1,data_section1,offset1,pef_file1) = write_text_module_to_pef_file symbol offset0 module_offset_a pef_file0;
				};
				= write_text_to_pef_file symbol_list offset0 symbol_table text_a0 data_section pef_file0;
			{}{
				write_text_module_to_pef_file :: Symbol Int {#Int} *File -> (!*String,!*String,!Int,!*File);
				write_text_module_to_pef_file (Module {section_n=TEXT_SECTION,module_offset=virtual_module_offset,length,first_relocation_n,end_relocation_n,align=alignment})
						offset0 module_offset_a=:{[o_i]=real_module_offset} pef_file0
					= (text_a2,data_section1,aligned_offset0+length,fwrites text_string (write_zero_bytes_to_file (aligned_offset0-offset0) pef_file0));
					{
						(text_string,text_a2) = u_char_array_slice text_a1 offset (offset+length-1);
						offset=virtual_module_offset-text_v_address;
						o_i=first_symbol_n+module_n;
						
						aligned_offset0=(offset0+alignment_mask) bitand (bitnot alignment_mask);
						alignment_mask=dec (1<<alignment);

						(text_a1,data_section1) = relocate_text first_relocation_n symbols text_a0 data_section;

						relocate_text :: Int SymbolArray *String *String -> (!*String,!*String);
						relocate_text relocation_n symbol_a text_a0 data_section
							| relocation_n==end_relocation_n
								= (text_a0,data_section);
							| relocation_type==R_TRL && (relocation_size==0x8f || relocation_size==0x0f)
								= relocate_text (inc relocation_n) symbol_a text1 data_section1;
								{
									(text1,data_section1)
										= relocate_trl symbol_a.[relocation_symbol_n] symbol_a.[toc0_symbol_n] (relocation_offset-text_v_address) data_v_address
											module_offset_a first_symbol_n relocation_symbol_n symbol_a marked_offset_a0 symbols_a data_relocations text_a0 data_section;

									(SymbolIndex toc0_symbol_n _)=toc0_symbol;
								}
								= relocate_text (inc relocation_n) symbol_a text1 data_section;
								{
									text1 = case relocation_type of {
										R_BR
											| relocation_size==0x8f
												-> relocate_short_branch symbol_a.[relocation_symbol_n] (relocation_offset-text_v_address) virtual_module_offset 
													real_module_offset module_offset_a first_symbol_n relocation_symbol_n symbol_a text_a0;
											| relocation_size==0x99
												-> relocate_branch symbol_a.[relocation_symbol_n] (relocation_offset-text_v_address) virtual_module_offset
													real_module_offset module_offset_a first_symbol_n relocation_symbol_n symbol_a marked_offset_a0 symbols_a text_a0;
										R_TOC
											| relocation_size==0x8f || relocation_size==0x0f
												-> relocate_toc symbol_a.[relocation_symbol_n] symbol_a.[toc0_symbol_n] 
													(relocation_offset-text_v_address) module_offset_a first_symbol_n relocation_symbol_n marked_offset_a0 text_a0;
												{
													(SymbolIndex toc0_symbol_n _)=toc0_symbol;
												}
										R_REF
											-> text_a0;
										R_MW_BR
											| relocation_size==0x8f
												-> relocate_mw_short_branch symbol_a.[relocation_symbol_n] (relocation_offset-text_v_address) virtual_module_offset 
													real_module_offset module_offset_a first_symbol_n relocation_symbol_n symbol_a text_a0;
											| relocation_size==0x99
												-> relocate_mw_branch symbol_a.[relocation_symbol_n] (relocation_offset-text_v_address) virtual_module_offset
													real_module_offset module_offset_a first_symbol_n relocation_symbol_n symbol_a marked_offset_a0 symbols_a text_a0;
										R_MW_TOC
											| relocation_size==0x8f || relocation_size==0x0f
												-> relocate_mw_toc symbol_a.[relocation_symbol_n]
													(relocation_offset-text_v_address) module_offset_a first_symbol_n relocation_symbol_n marked_offset_a0 text_a0;
									}
								}
							{							
								relocation_type=text_relocations BYTE (relocation_index+9);
								relocation_size=text_relocations BYTE (relocation_index+8);
								relocation_symbol_n=(inc (text_relocations LONG (relocation_index+4))) >> 1;
								relocation_offset=text_relocations LONG relocation_index;

								relocation_index=relocation_n * SIZE_OF_RELOCATION;
							}
					}
			}
	}

write_imported_library_functions_code :: LibraryList Int *File -> *File;
write_imported_library_functions_code EmptyLibraryList descriptor_offset0 pef_file0
	= pef_file0;
write_imported_library_functions_code (Library _ imported_symbols _ library_list) descriptor_offset0 pef_file0
	=	write_imported_library_functions_code library_list descriptor_offset1 pef_file1;
	{
		(descriptor_offset1,pef_file1) = write_library_functions_code imported_symbols descriptor_offset0 pef_file0;
		
		write_library_functions_code :: LibrarySymbolsList Int *File -> (!Int,!*File);
		write_library_functions_code EmptyLibrarySymbolsList descriptor_offset0 pef_file0
			= (descriptor_offset0,pef_file0);
		write_library_functions_code (LibrarySymbol symbol_name symbol_list) descriptor_offset0 pef_file0
			= write_library_functions_code symbol_list (descriptor_offset0+4) pef_file1;
			{
				pef_file1 = pef_file0
					FWI (/*0x81820000*/0x81828000+descriptor_offset0) FWI 0x90410014 FWI 0x800C0000 FWI 0x804C0004 FWI 0x7C0903A6 FWI 0x4E800420;
			}
	}

relocate_data :: Int Int Int Int Int String Int {#Int} {#Int} {!Symbol} SymbolsArray *{#Char}-> *{#Char};
relocate_data relocation_n end_relocation_n virtual_module_offset virtual_section_offset real_module_offset data_relocations
		first_symbol_n module_offset_a marked_offset_a0 symbol_a symbols_a data0
	| relocation_n==end_relocation_n
		= data0;
		= relocate_data (inc relocation_n) end_relocation_n virtual_module_offset virtual_section_offset real_module_offset data_relocations
						first_symbol_n module_offset_a marked_offset_a0 symbol_a symbols_a data1;
	{
		data1 = relocate_symbol relocation_type module_offset_a symbol_a marked_offset_a0 symbols_a data0;
		
		relocate_symbol :: Int {#Int} {!Symbol} {#Int} SymbolsArray *{#Char} -> *{#Char};
		relocate_symbol R_POS module_offset_a symbol_a marked_offset_a0 symbols_a data0
			| relocation_size==0x1f
				= relocate_long_pos symbol_a.[relocation_symbol_n] (relocation_offset-virtual_section_offset) module_offset_a 
									first_symbol_n relocation_symbol_n symbol_a marked_offset_a0 symbols_a data0;
		relocate_symbol R_MW_POS module_offset_a symbol_a marked_offset_a0 symbols_a data0
			| relocation_size==0x1f
				= relocate_mw_long_pos symbol_a.[relocation_symbol_n] (relocation_offset-virtual_section_offset) module_offset_a 
									first_symbol_n relocation_symbol_n symbol_a marked_offset_a0 symbols_a data0;

		relocation_type=data_relocations BYTE (relocation_index+9);
		relocation_size=data_relocations BYTE (relocation_index+8);
		relocation_symbol_n=(inc (data_relocations LONG (relocation_index+4))) >> 1;
		relocation_offset=data_relocations LONG relocation_index;

		relocation_index=relocation_n * SIZE_OF_RELOCATION;
	}

relocate_long_pos :: Symbol Int {#Int} Int Int {!Symbol} {#Int} SymbolsArray *{#Char} -> *{#Char};
relocate_long_pos (Module {section_n,module_offset=virtual_label_offset}) index module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 symbols_a data0
	= add_to_long_at_offset (real_label_offset-virtual_label_offset) index data0;
	{
		real_label_offset=module_offset_a.[first_symbol_n+symbol_n];
	}
relocate_long_pos (Label {label_section_n=section_n,label_offset=offset,label_module_n=module_n}) index module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 symbols_a data0
	= relocate_long_pos symbol_a.[module_n] index module_offset_a first_symbol_n module_n symbol_a marked_offset_a0 symbols_a data0;
relocate_long_pos (ImportedLabel {implab_file_n=file_n,implab_symbol_n=symbol_n}) index module_offset_a first_symbol_n _ symbol_a marked_offset_a0 symbols_a data0
	| file_n<0
		=	add_to_long_at_offset real_label_offset index data0;
		{
			real_label_offset = module_offset_a.[marked_offset_a0.[file_n + size marked_offset_a0]+symbol_n];
		}
		=	relocate_long_pos_of_module_in_another_module symbols_a.[file_n,symbol_n];
		{
			relocate_long_pos_of_module_in_another_module (Module {section_n})
				= add_to_long_at_offset real_label_offset index data0;
				{
					real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
				}
/*			relocate_long_pos_of_module_in_another_module (Label {label_section_n=section_n,label_offset=offset,label_module_n=module_n})
				= case symbols_a.[file_n,module_n] of {
					Module {section_n,module_offset=v_module_offset}
						-> add_to_long_at_offset (real_label_offset+(offset-v_module_offset)) index data0;
						{
							real_label_offset = module_offset_a.[first_symbol_n+module_n];
						}
				}
*/
			first_symbol_n = marked_offset_a0.[file_n];
		}
relocate_long_pos (ImportedLabelPlusOffset {implaboffs_file_n=file_n,implaboffs_symbol_n=symbol_n,implaboffs_offset=label_offset}) index module_offset_a first_symbol_n _ symbol_a marked_offset_a0 symbols_a data0
		=	case (symbols_a.[file_n,symbol_n]) of {
				Module {section_n}
					-> add_to_long_at_offset (real_label_offset+label_offset) index data0;
					{
						real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
					}
			}
		{
			first_symbol_n = marked_offset_a0.[file_n];
		}

relocate_short_branch :: Symbol Int Int Int {#Int} Int Int {!Symbol} *{#Char} -> *{#Char};
relocate_short_branch (Module {section_n=TEXT_SECTION,module_offset=virtual_label_offset}) index virtual_module_offset
		real_module_offset {[o_i]=real_label_offset} first_symbol_n symbol_n symbol_a text0
	= add_to_word_at_offset ((virtual_module_offset-virtual_label_offset)+(real_label_offset-real_module_offset)) index text0;
	{
		o_i=first_symbol_n+symbol_n;
	}
relocate_short_branch (Label {label_section_n=TEXT_SECTION,label_offset=offset,label_module_n=module_n}) index virtual_module_offset real_module_offset module_offset_a first_symbol_n symbol_n symbol_a text0
	= relocate_short_branch symbol_a.[module_n] index virtual_module_offset real_module_offset module_offset_a first_symbol_n module_n symbol_a text0;

relocate_branch :: Symbol Int Int Int {#Int} Int Int {!Symbol} {#Int} SymbolsArray *{#Char} -> *{#Char};
relocate_branch (Module {section_n=TEXT_SECTION,module_offset=virtual_label_offset}) index virtual_module_offset
		real_module_offset module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 symbols_a text0
	= add_to_branch_offset_at_offset ((virtual_module_offset-virtual_label_offset)+(real_label_offset-real_module_offset)) index text0;
	{
		real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
	}
relocate_branch (Label {label_section_n=TEXT_SECTION,label_offset=offset,label_module_n=module_n}) index virtual_module_offset 
		real_module_offset module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 symbols_a text0
	= relocate_branch symbol_a.[module_n] index virtual_module_offset 
		real_module_offset module_offset_a first_symbol_n module_n symbol_a marked_offset_a0 symbols_a text0;
relocate_branch (ImportedLabel {implab_file_n=file_n,implab_symbol_n=symbol_n}) index virtual_module_offset
		real_module_offset module_offset_a first_symbol_n _ symbol_a marked_offset_a0 symbols_a text0
	| file_n<0
		= load_toc_after_branch index (add_to_branch_offset_at_offset (virtual_module_offset+(real_label_offset-real_module_offset)) index text0);
		{
			real_label_offset = module_offset_a.[marked_offset_a0.[file_n + size marked_offset_a0]+symbol_n];
		}
		= relocate_branch_to_another_module symbols_a.[file_n,symbol_n] index virtual_module_offset
			real_module_offset module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 symbols_a text0;
		{
			relocate_branch_to_another_module :: Symbol Int Int Int {#Int} Int Int {!Symbol} {#Int} SymbolsArray *{#Char} -> *{#Char};
			relocate_branch_to_another_module (Module {section_n=TEXT_SECTION}) index virtual_module_offset
					real_module_offset module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 symbols_a text0
				= add_to_branch_offset_at_offset (virtual_module_offset+(real_label_offset-real_module_offset)) index text0;
				{
					real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
				}
/*
			relocate_branch_to_another_module (Label TEXT_SECTION offset module_n) index virtual_module_offset 
					real_module_offset module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 symbols_a text0
				= relocate_branch_to_a_label_in_another_module symbol_a.[module_n] index (virtual_module_offset+offset)
					real_module_offset module_offset_a first_symbol_n module_n symbol_a marked_offset_a0 symbols_a text0;

				relocate_branch_to_a_label_in_another_module :: Symbol Int Int Int {#Int} Int Int {!Symbol} {#Int} SymbolsArray *{#Char} -> *{#Char};
				relocate_branch_to_a_label_in_another_module (Module {section_n=TEXT_SECTION,module_offset=v_module_offset} index offset
						real_module_offset module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 symbols_a text0
					= add_to_branch_offset_at_offset ((offset-v_module_offset)+(real_label_offset-real_module_offset)) index text0;
					{
						real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
					}
*/
			first_symbol_n = marked_offset_a0.[file_n];
		}
relocate_branch (ImportedLabelPlusOffset {implaboffs_file_n=file_n,implaboffs_symbol_n=symbol_n,implaboffs_offset=label_offset}) index virtual_module_offset
		real_module_offset module_offset_a first_symbol_n _ symbol_a marked_offset_a0 symbols_a text0
	=	case (symbols_a.[file_n,symbol_n]) of {
			Module {section_n=TEXT_SECTION}
				->	add_to_branch_offset_at_offset (virtual_module_offset+(real_label_offset-real_module_offset)+label_offset) index text0;
				{
					real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
				}	
		}
	{
		first_symbol_n = marked_offset_a0.[file_n];
	}

relocate_toc :: Symbol Symbol Int {#Int} Int Int {#Int} *{#Char} -> *{#Char};
relocate_toc (Module {section_n=TOC_SECTION,module_offset=virtual_label_offset}) (Module {/*section_n=TOC_SECTION,*/module_offset=virtual_toc0_offset}) index
				module_offset_a first_symbol_n symbol_n marked_offset_a text0
	=	add_to_word_at_offset ((virtual_toc0_offset-virtual_label_offset)+real_label_offset-32768) index text0;
	{
		real_label_offset=module_offset_a.[first_symbol_n+symbol_n];
	}
relocate_toc (AliasModule {alias_module_offset,alias_global_module_n}) (Module {/*section_n=TOC_SECTION,*/module_offset=virtual_toc0_offset}) index
				module_offset_a first_symbol_n symbol_n marked_offset_a text0
	=	add_to_word_at_offset ((virtual_toc0_offset-alias_module_offset)+real_label_offset-32768) index text0;
	{
		real_label_offset=module_offset_a.[alias_global_module_n];
	}
relocate_toc (ImportedFunctionDescriptorTocModule {imptoc_offset,imptoc_file_n,imptoc_symbol_n}) (Module {/*section_n=TOC_SECTION,*/module_offset=virtual_toc0_offset}) index
				module_offset_a first_symbol_n symbol_n marked_offset_a text0
	=	add_to_word_at_offset ((virtual_toc0_offset-imptoc_offset)+real_label_offset-32768) index text0;
	{
		real_label_offset=module_offset_a.[marked_offset_a.[imptoc_file_n + size marked_offset_a]+imptoc_symbol_n+1];
	}

relocate_mw_long_pos (Module {section_n,module_offset=virtual_label_offset}) index module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 symbols_a data0
	= add_to_long_at_offset real_label_offset index data0;
	{
		real_label_offset=module_offset_a.[first_symbol_n+symbol_n];
	}
relocate_mw_long_pos (Label {label_section_n=section_n,label_offset=offset,label_module_n=module_n}) index module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 symbols_a data0
	= relocate_mw_long_pos symbol_a.[module_n] index module_offset_a first_symbol_n module_n symbol_a marked_offset_a0 symbols_a data0;
relocate_mw_long_pos (ImportedLabel {implab_file_n=file_n,implab_symbol_n=symbol_n}) index module_offset_a first_symbol_n _ symbol_a marked_offset_a0 symbols_a data0
	| file_n<0
		=	add_to_long_at_offset real_label_offset index data0;
		{
			real_label_offset = module_offset_a.[marked_offset_a0.[file_n + size marked_offset_a0]+symbol_n];
		}
		=	relocate_mw_long_pos_of_module_in_another_module symbols_a.[file_n,symbol_n];
		{
			relocate_mw_long_pos_of_module_in_another_module (Module {section_n})
				= add_to_long_at_offset real_label_offset index data0;
				{
					real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
				}
			first_symbol_n = marked_offset_a0.[file_n];
		}
relocate_mw_long_pos (ImportedLabelPlusOffset {implaboffs_file_n=file_n,implaboffs_symbol_n=symbol_n,implaboffs_offset=label_offset}) index module_offset_a first_symbol_n _ symbol_a marked_offset_a0 symbols_a data0
		=	case (symbols_a.[file_n,symbol_n]) of {
				Module {section_n}
					-> add_to_long_at_offset (real_label_offset+label_offset) index data0;
					{
						real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
					}
			}
		{
			first_symbol_n = marked_offset_a0.[file_n];
		}

relocate_mw_short_branch (Module {section_n=TEXT_SECTION}) index virtual_module_offset real_module_offset {[o_i]=real_label_offset} first_symbol_n symbol_n symbol_a text0
	= add_to_word_at_offset (virtual_module_offset+real_label_offset-(real_module_offset+index)) index text0;
	{
		o_i=first_symbol_n+symbol_n;
	}
relocate_mw_short_branch (Label {label_section_n=TEXT_SECTION,label_offset=offset,label_module_n=module_n}) index virtual_module_offset real_module_offset module_offset_a first_symbol_n symbol_n symbol_a text0
	= relocate_mw_short_branch symbol_a.[module_n] index virtual_module_offset real_module_offset module_offset_a first_symbol_n module_n symbol_a text0;

relocate_mw_branch (Module {section_n=TEXT_SECTION}) index virtual_module_offset
		real_module_offset module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 symbols_a text0
	= add_to_branch_offset_at_offset (virtual_module_offset+real_label_offset-(real_module_offset+index)) index text0;
	{
		real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
	}
relocate_mw_branch (Label {label_section_n=TEXT_SECTION,label_offset=offset,label_module_n=module_n}) index virtual_module_offset 
		real_module_offset module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 symbols_a text0
	= relocate_mw_branch symbol_a.[module_n] index virtual_module_offset 
		real_module_offset module_offset_a first_symbol_n module_n symbol_a marked_offset_a0 symbols_a text0;
relocate_mw_branch (ImportedLabel {implab_file_n=file_n,implab_symbol_n=symbol_n}) index virtual_module_offset
		real_module_offset module_offset_a first_symbol_n _ symbol_a marked_offset_a0 symbols_a text0
	| file_n<0
		= load_toc_after_branch index (add_to_branch_offset_at_offset (virtual_module_offset+real_label_offset-(real_module_offset+index)) index text0);
		{
			real_label_offset = module_offset_a.[marked_offset_a0.[file_n + size marked_offset_a0]+symbol_n];
		}
		= relocate_branch_to_another_module symbols_a.[file_n,symbol_n] index virtual_module_offset
			real_module_offset module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 symbols_a text0;
		{
			relocate_branch_to_another_module :: Symbol Int Int Int {#Int} Int Int {!Symbol} {#Int} SymbolsArray *{#Char} -> *{#Char};
			relocate_branch_to_another_module (Module {section_n=TEXT_SECTION}) index virtual_module_offset
					real_module_offset module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 symbols_a text0
				= add_to_branch_offset_at_offset (virtual_module_offset+real_label_offset-(real_module_offset+index)) index text0;
				{
					real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
				}
			first_symbol_n = marked_offset_a0.[file_n];
		}
relocate_mw_branch (ImportedLabelPlusOffset {implaboffs_file_n=file_n,implaboffs_symbol_n=symbol_n,implaboffs_offset=label_offset}) index virtual_module_offset
		real_module_offset module_offset_a first_symbol_n _ symbol_a marked_offset_a0 symbols_a text0
	=	case (symbols_a.[file_n,symbol_n]) of {
			Module {section_n=TEXT_SECTION}
				->	add_to_branch_offset_at_offset (virtual_module_offset+real_label_offset-(real_module_offset+index)+label_offset) index text0;
				{
					real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
				}	
		}
	{
		first_symbol_n = marked_offset_a0.[file_n];
	}

relocate_mw_toc (Module {section_n=TOC_SECTION}) index module_offset_a first_symbol_n symbol_n marked_offset_a text0
	=	add_to_word_at_offset (real_label_offset-32768) index text0;
	{
		real_label_offset=module_offset_a.[first_symbol_n+symbol_n];
	}
relocate_mw_toc (AliasModule {alias_global_module_n}) index module_offset_a first_symbol_n symbol_n marked_offset_a text0
	=	add_to_word_at_offset (real_label_offset-32768) index text0;
	{
		real_label_offset=module_offset_a.[alias_global_module_n];
	}
relocate_mw_toc (ImportedFunctionDescriptorTocModule {imptoc_file_n,imptoc_symbol_n}) index module_offset_a first_symbol_n symbol_n marked_offset_a text0
	=	add_to_word_at_offset (real_label_offset-32768) index text0;
	{
		real_label_offset=module_offset_a.[marked_offset_a.[imptoc_file_n + size marked_offset_a]+imptoc_symbol_n+1];
	}

relocate_trl :: Symbol Symbol Int Int {#Int} Int Int {!Symbol} {#Int} SymbolsArray String *String *String -> (!*String,!*String);
relocate_trl symbol toc0_symbol index data_v_address module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 symbols_a data_relocations text0 data0
	= case symbol of {
		Module {section_n=TOC_SECTION,length=4,first_relocation_n,end_relocation_n}
			| first_relocation_n+1==end_relocation_n && relocation_type==R_POS && relocation_size==0x1f
				-> relocate_trl1 relocation_index;
			{}{
				relocation_index=first_relocation_n * SIZE_OF_RELOCATION;
				
				relocation_type=data_relocations BYTE (relocation_index+9);
				relocation_size=data_relocations BYTE (relocation_index+8);
			}
		AliasModule {alias_first_relocation_n}
			-> relocate_trl1 relocation_index;
			{
				relocation_index=alias_first_relocation_n * SIZE_OF_RELOCATION;
			}
		_
			-> (relocate_toc symbol toc0_symbol index module_offset_a first_symbol_n symbol_n marked_offset_a0 text0,data0);
	}
	{
		relocate_trl1 :: Int -> (!*String,!*String);
		relocate_trl1 relocation_index
			= relocate_trl2 symbol_a.[relocation_symbol_n] first_symbol_n relocation_symbol_n;
		{
			relocation_symbol_n=(inc (data_relocations LONG (relocation_index+4))) >> 1;
			relocation_offset=data_relocations LONG relocation_index;
		
			(offset,data1)=read_long data0 (relocation_offset-data_v_address);

			relocate_trl2 :: Symbol Int Int -> (!*String,!*String);
			relocate_trl2 (Module {section_n,module_offset=virtual_label_offset}) first_symbol_n symbol_n
				= relocate_trl3 section_n new_offset;
				{
					new_offset = real_label_offset+offset-virtual_label_offset;
					real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
				}
			relocate_trl2 (Label {label_offset=offset,label_module_n=module_n}) first_symbol_n symbol_n
				= relocate_trl2 symbol_a.[module_n] first_symbol_n module_n;
			relocate_trl2 (ImportedLabel {implab_file_n=imported_file_n,implab_symbol_n=imported_symbol_n}) first_symbol_n symbol_n
				| imported_file_n<0
					=	(relocate_toc symbol toc0_symbol index module_offset_a first_symbol_n symbol_n marked_offset_a0 text0,data1);
					=	case (symbols_a.[imported_file_n,imported_symbol_n]) of {
							Module {section_n}
								-> relocate_trl3 section_n new_offset;
						};
						{
							new_offset=real_label_offset+offset;
							real_label_offset = module_offset_a.[marked_offset_a0.[imported_file_n]+imported_symbol_n];
						}
			relocate_trl2 (ImportedLabelPlusOffset {implaboffs_file_n=imported_file_n,implaboffs_symbol_n=imported_symbol_n,implaboffs_offset=label_offset}) first_symbol_n symbol_n
				=	case (symbols_a.[imported_file_n,imported_symbol_n]) of {
						Module {section_n}
							-> relocate_trl3 section_n new_offset;
					};
					{
						new_offset=real_label_offset+label_offset+offset;
						real_label_offset = module_offset_a.[marked_offset_a0.[imported_file_n]+imported_symbol_n];
					}

			relocate_trl3 :: Int Int -> (!*String,!*String);
			relocate_trl3 section_n new_offset
				| (section_n==DATA_SECTION || section_n==BSS_SECTION) && (new_offset bitand 0xffff)==new_offset
					= (change_lwz_to_addi (new_offset-32768) index text0,data1);
					= (relocate_toc symbol toc0_symbol index module_offset_a first_symbol_n symbol_n marked_offset_a0 text0,data1);
		}
	}

change_lwz_to_addi :: Int Int *{#Char} -> *{#Char};
change_lwz_to_addi w index array=:{[index_2]=a_i_2}
	| (toInt a_i_2 bitand 252) == 128
		= {array & [index_2]=toChar ((toInt a_i_2 bitand 3) bitor 56),[index]=toChar (w>>8),[index1]=toChar w};
	{}{
		index_2 = index-2;
		index1 = inc index;
	}

add_to_word_at_offset :: Int Int *{#Char} -> *{#Char};
add_to_word_at_offset w index array=:{[index]=v0,[index1]=v1}
	= {array & [index]=toChar (new_v>>8),[index1]=toChar new_v};{
		new_v=v+w;
		v = (toInt v0<<8) + (toInt v1);
		index1 = inc index;
	}

add_to_branch_offset_at_offset :: Int Int *{#Char} -> *{#Char};
add_to_branch_offset_at_offset w index array=:{[index]=v0,[index1]=v1,[index2]=v2,[index3]=v3}
	= {array & [index]=new_v0,[index1]=toChar (new_v>>16),[index2]=toChar (new_v>>8),[index3]=toChar (new_v)};
	{
		new_v0 = toChar ((toInt v0 bitand 0xfc) bitor ((new_v>>24) bitand 3));
		
		new_v=v+w;
		v = ((toInt v0 bitand 3)<<24)+(toInt v1<<16)+(toInt v2<<8)+(toInt v3);

		index1 = index+1;
		index2 = index+2;
		index3 = index+3;
	}

add_to_long_at_offset :: Int Int *{#Char} -> *{#Char};
add_to_long_at_offset w index array=:{[index]=v0,[index1]=v1,[index2]=v2,[index3]=v3}
	= {array & [index]=toChar (new_v>>24),[index1]=toChar (new_v>>16),[index2]=toChar (new_v>>8),[index3]=toChar new_v};{
		new_v=v+w;
		v = (toInt v0<<24) + (toInt v1<<16)+(toInt v2<<8)+toInt v3;
		index1=index+1;
		index2=index+2;
		index3=index+3;
	}

load_toc_after_branch :: Int *{#Char} -> *{#Char};
load_toc_after_branch index text0=:{[index4]=n0,[index5]=n1,[index6]=n2,[index7]=n3}
	| n0==toChar 0x60 && n1=='\0' && n2=='\0' && n3=='\0'
		= {text0 & [index4]=toChar 0x80,[index5]=toChar 0x41,[index6]=toChar 0x00,[index7]=toChar 0x14};
	{}{
		index4=index+4;
		index5=index+5;
		index6=index+6;
		index7=index+7;
	}

write_toc_to_pef_files :: [*String] [Xcoff] Int Int {#Bool} {#Int} {#Int} SymbolsArray *File -> (!Int,![*{#Char}],!*File);
write_toc_to_pef_files [] [] first_symbol_n offset0 marked_bool_a module_offset_a marked_offset_a symbols_a pef_file0
	= (offset0,[],pef_file0);
write_toc_to_pef_files [data_section:data_section_list] [xcoff=:{n_symbols,header={data_v_address},symbol_table={toc_symbols,symbols},data_relocations}:xcoff_list] first_symbol_n offset0 marked_bool_a module_offset_a marked_offset_a symbols_a pef_file0
	= (offset2,[data_section_a : data_section_list1],pef_file2); {
		(offset2,data_section_list1,pef_file2)
			= write_toc_to_pef_files data_section_list xcoff_list (first_symbol_n+n_symbols) offset1 marked_bool_a module_offset_a marked_offset_a symbols_a pef_file1;
		(data_section_a,offset1,pef_file1)
			= write_toc_or_data_to_pef_file toc_symbols first_symbol_n offset0 data_v_address symbols data_relocations marked_bool_a
					module_offset_a marked_offset_a symbols_a data_section pef_file0;
	}

write_data_to_pef_files :: [*{#Char}] [Xcoff] Int Int {#Bool} {#Int} {#Int} SymbolsArray *File -> *File;
write_data_to_pef_files [] [] first_symbol_n offset0 marked_bool_a module_offset_a marked_offset_a symbols_a pef_file0
	= pef_file0;
write_data_to_pef_files [data_section_a:data_section_list] [xcoff=:{n_symbols,header={data_v_address},symbol_table={data_symbols,symbols},data_relocations}:xcoff_list] first_symbol_n offset0 marked_bool_a module_offset_a marked_offset_a symbols_a pef_file0
	= write_data_to_pef_files data_section_list xcoff_list (first_symbol_n+n_symbols) offset1 marked_bool_a module_offset_a marked_offset_a symbols_a pef_file1; {
		(_,offset1,pef_file1)
			= write_toc_or_data_to_pef_file data_symbols first_symbol_n offset0 data_v_address symbols data_relocations marked_bool_a
					module_offset_a marked_offset_a symbols_a data_section_a pef_file0;
	}

	write_toc_or_data_to_pef_file :: SymbolIndexList Int Int Int SymbolArray String {#Bool} {#Int} {#Int} SymbolsArray *{#Char} *File -> (!*{#Char},!Int,!*File);
	write_toc_or_data_to_pef_file EmptySymbolIndex first_symbol_n offset0 data_v_address symbol_table data_relocations marked_bool_a module_offset_a marked_offset_a0 symbols_a data_a0 pef_file0
		= (data_a0,offset0,pef_file0);
	write_toc_or_data_to_pef_file (SymbolIndex module_n symbol_list) first_symbol_n offset0 data_v_address symbol_table=:{[module_n] = symbol} data_relocations marked_bool_a module_offset_a marked_offset_a0 symbols_a data_a0 pef_file0
		| marked_bool_a.[first_symbol_n+module_n]
			= write_toc_or_data_to_pef_file symbol_list first_symbol_n offset1 data_v_address symbol_table data_relocations marked_bool_a module_offset_a marked_offset_a0 symbols_a data_a1 pef_file1;
			{
				(data_a1,offset1,pef_file1) = write_data_module_to_pef_file symbol offset0 module_offset_a marked_offset_a0 symbols_a data_a0 pef_file0;
			};
			= write_toc_or_data_to_pef_file symbol_list first_symbol_n offset0 data_v_address symbol_table data_relocations marked_bool_a module_offset_a marked_offset_a0 symbols_a data_a0 pef_file0;
		{}{
			write_data_module_to_pef_file :: Symbol Int {#Int} {#Int} SymbolsArray *{#Char} *File -> (!*{#Char},!Int,!*File);
			write_data_module_to_pef_file (Module {section_n,module_offset=virtual_module_offset,length,first_relocation_n,end_relocation_n,align=alignment})
					offset0 module_offset_a=:{[o_i]=real_module_offset} marked_offset_a0 symbols_a data_a0 pef_file0
				| section_n==DATA_SECTION || section_n==TOC_SECTION
					= (data_a2,aligned_offset0+length,fwrites data_string (write_zero_bytes_to_file (aligned_offset0-offset0) pef_file0));
				{}{
					(data_string,data_a2) = u_char_array_slice data_a1 offset (offset+length-1);
					offset=virtual_module_offset-data_v_address;
					o_i=first_symbol_n+module_n;
					
					aligned_offset0=(offset0+alignment_mask) bitand (bitnot alignment_mask);
					alignment_mask=dec (1<<alignment);
					
					data_a1 = relocate_data first_relocation_n end_relocation_n virtual_module_offset data_v_address real_module_offset data_relocations
											first_symbol_n module_offset_a marked_offset_a0 symbol_table symbols_a data_a0;
				}
			write_data_module_to_pef_file (AliasModule _) offset0 module_offset_a marked_offset_a0 symbols_a data_a0 pef_file0
				=	(data_a0,offset0,pef_file0);
			write_data_module_to_pef_file (ImportedFunctionDescriptorTocModule _) offset0 module_offset_a marked_offset_a0 symbols_a data_a0 pef_file0
				=	(data_a0,offset0,pef_file0);
		}

(THEN) infixl;
(THEN) a f :== f a;

write_xcoff_loader library_list n_libraries n_imported_symbols string_table_file_names_size string_table_size main_offset
				n_loader_relocations loader_relocations xcoff_file0
	=	xcoff_file1
			THEN write_symbol_table library_list 0 1
			THEN write_loader_relocations_for_imported_symbols 0 n_imported_symbols
			THEN write_xcoff_loader_relocations loader_relocations
			FWC '\0' FWC '\0' FWC '\0'
			THEN write_library_file_names library_list
			THEN write_symbol_string_table library_list
			THEN write_zero_bytes_to_file (aligned_string_table_size-string_table_size)
			FWI 0;
	{

		xcoff_file1 = xcoff_file0
			FWI 1 FWI n_imported_symbols FWI (n_loader_relocations+n_imported_symbols) FWI import_file_list_length FWI (1+n_libraries) 
			FWI loader_import_offset FWI string_table_size FWI (loader_import_offset+import_file_list_length);

		aligned_string_table_size=(string_table_size+3) bitand (-4);

		loader_import_offset=32+24*n_imported_symbols+12*(n_loader_relocations+n_imported_symbols);
		import_file_list_length=3+string_table_file_names_size;
		
		write_loader_relocations_for_imported_symbols symbol_n n_symbols xcoff_file
			| n_symbols==0
				= xcoff_file;
				= write_loader_relocations_for_imported_symbols (inc symbol_n) (dec n_symbols)
					(xcoff_file FWI (symbol_n<<2) FWI (3+symbol_n) FWI 0x1F000002);
	
		write_library_file_names EmptyLibraryList pef_file0
			= pef_file0;
		write_library_file_names (Library file_name _ _ libraries) pef_file0
			= write_library_file_names libraries (pef_file0 FWC '\0' FWS file_name FWC '\0' FWC '\0');
			
		write_symbol_table EmptyLibraryList string_table_offset0 file_number xcoff_file0
			= xcoff_file0;
		write_symbol_table (Library _ imported_symbols _ libraries) string_table_offset0 file_number xcoff_file0
			= write_symbol_table libraries string_table_offset1 (inc file_number) xcoff_file1;
			{
				(string_table_offset1,xcoff_file1) = write_symbol_table_entries imported_symbols string_table_offset0 xcoff_file0;

				write_symbol_table_entries :: LibrarySymbolsList Int *File -> (!Int,!*File);
				write_symbol_table_entries EmptyLibrarySymbolsList string_table_offset0 xcoff_file0
					= (string_table_offset0,xcoff_file0);
				write_symbol_table_entries (LibrarySymbol symbol_name symbols) string_table_offset0 xcoff_file0
					| size symbol_name<=8
						= write_symbol_table_entries symbols string_table_offset0
							(xcoff_file0 FWS symbol_name FWZ (8 - size symbol_name) FWI 0 FWI 0x00004000 FWI file_number FWI 0);
						= write_symbol_table_entries symbols (3 + size symbol_name + string_table_offset0)
							(xcoff_file0 FWI 0 FWI (string_table_offset0+2) FWI 0 FWI 0x00004000 FWI file_number FWI 0);
			}