Commit 48626b10 authored by John van Groningen's avatar John van Groningen
Browse files

optimising linker for ELF object format for ia32 and sparc processors

parent fdcde68b
definition module elf_linker;
from StdFile import ::Files;
link_elf_files :: ![String] !String !Files -> (!Bool,![String],!Files);
This diff is collapsed.
definition module elf_linker2;
from StdFile import ::Files;
import elf_linker_types;
:: *NamesTable :== SNamesTable;
:: SNamesTable :== {!NamesTableElement};
:: NamesTableElement
= NamesTableElement !String !Int !Int !NamesTableElement // symbol_name symbol_n file_n symbol_list
| EmptyNamesTableElement;
n_symbols_of_xcoff_list :: !Int ![Xcoff] -> (!Int,![Xcoff]);
write_elf_headers :: !Int !Int !Int !Int !Int !Int !Int !*File -> *File;
SIZE_OF_SECTION_HEADER:==40;
STT_NOTYPE:==0;
STT_OBJECT:==1;
STT_FUNC:==2;
STT_SECTION:==3;
STT_FILE:==4;
STB_LOCAL:==0;
STB_GLOBAL:==1;
SHN_COMMON:==0xfff2;
N_UNDEF:==0;
TEXT_SECTION:==1;
DATA_SECTION:==2;
BSS_SECTION:==3;
sort_modules :: !*SXcoff -> .SXcoff;
create_names_table :: NamesTable;
insert_symbol_in_symbol_table :: !String Int Int !NamesTable -> NamesTable;
find_symbol_in_symbol_table :: !String !NamesTable -> (!NamesTableElement,!NamesTable);
read_xcoff_file :: !String NamesTable Bool !Files Int -> (![String],!*String,!*String,!Xcoff,!NamesTable,!Files);
empty_xcoff :: .SXcoff;
This diff is collapsed.
definition module elf_linker_types;
:: *SymbolArray :== SSymbolArray;
:: SSymbolArray :== {!Symbol};
:: Symbol
= Module !Int !Int !Int !Int !Int !Int !String !Int // section_n offset length virtual_address file_offset n_relocations relocations align
| Label !Int !Int !Int // section_n offset module_n
| SectionLabel !Int !Int // section_n offset
| ImportLabel !String // label_name
| ImportedLabel !Int !Int // file_n symbol_n
| ImportedLabelPlusOffset !Int !Int !Int // file_n symbol_noffset
| UndefinedLabel !Int
| EmptySymbol;
:: SymbolIndexList = SymbolIndex !Int !SymbolIndexList | EmptySymbolIndex;
:: *Xcoff :== *SXcoff;
:: SXcoff ={
file_name :: !String,
symbol_table :: !.SSymbolTable,
n_symbols :: !Int
};
:: *SymbolTable :== *SSymbolTable;
:: SSymbolTable ={
text_symbols :: !SymbolIndexList,
data_symbols :: !SymbolIndexList,
bss_symbols :: !SymbolIndexList,
imported_symbols:: !SymbolIndexList,
section_symbol_ns::!.{#Int},
symbols :: !.SSymbolArray
};
:: XcoffArray :== {#SXcoff};
implementation module elf_linker_types;
definition module elf_relocations;
import StdInt,StdArray,StdFile;
import elf_linker_types;
BigOrLittleEndian big little :== little;
SIZE_OF_RELOCATION:==8;
R_386_NONE:==0;
R_386_32:==1;
R_386_PC32:==2;
SHT_RELA:==4;
SHT_REL:==9;
SHT_relocations:==SHT_REL;
RELOCATION_TYPE_OFFSET:== 4;
RELOCATION_SYMBOL_N_OFFSET:== 5;
(BYTE) string i :== toInt (string.[i]);
(WORD) :: !{#Char} !Int -> Int;
// (WORD) string i = (string BYTE (i+1)<<8) bitor (string BYTE i);
(LONG) :: !{#Char} !Int -> Int;
// (LONG) string i = (string BYTE (i+3)<<24) bitor (string BYTE (i+2)<<16) bitor (string BYTE (i+1)<<8) bitor (string BYTE i);
(TBYTE) :: !{#Char} !Int -> Int;
// (TBYTE) string i = (string BYTE (i+2)<<16) bitor (string BYTE (i+1)<<8) bitor (string BYTE i);i
shstrtab_data_relocations_section_name_offset :== 38;
shstrtab_symbol_table_section_name_offset :== 48;
shstrtab_string_table_section_name_offset :== 56;
shstrtab_size :== 64;
write_elf_header :: !*File -> *File;
write_shstrtab_end :: !*File -> *File;
count_relocations :: !Int !{#Char} !{!Symbol} -> Int;
write_module_relocations :: !Symbol !Int !Int !SSymbolArray !XcoffArray !{#Int} !{#Int} !*File -> *File;
relocate_text :: !.Int Int Int Int Int {#Char} {#SXcoff} {#Int} {#Int} {!Symbol} !*{#.Char} -> .{#Char};
relocate_data :: Int Int Int Int Int String Int {#Int} {#Int} {!Symbol} XcoffArray *{#Char}-> *{#Char};
implementation module elf_relocations;
import StdInt,StdChar,StdClass,StdArray,StdFile;
import elf_linker_types;
TEXT_SECTION:==1;
(BYTE) string i :== toInt (string.[i]);
(WORD) :: !{#Char} !Int -> Int;
(WORD) string i = (string BYTE (i+1)<<8) bitor (string BYTE i);
(LONG) :: !{#Char} !Int -> Int;
(LONG) string i
= (string BYTE (i+3)<<24) bitor (string BYTE (i+2)<<16) bitor (string BYTE (i+1)<<8) bitor (string BYTE i);
(TBYTE) :: !{#Char} !Int -> Int;
(TBYTE) string i = (string BYTE (i+2)<<16) bitor (string BYTE (i+1)<<8) bitor (string BYTE i);
(FWI) infixl;
(FWI) f i :== fwritei i f;
(FWS) infixl;
(FWS) f s :== fwrites s f;
write_elf_header :: !*File -> *File;
write_elf_header file
= file
FWI 0x464c457f
FWI 0x00010101
FWI 0
FWI 0
FWI 0x00030001
FWI 1
FWI 0
FWI 0
FWI 0x34
FWI 0
FWI 0x00000034
FWI 0x00280000
FWI 0x00010009;
write_shstrtab_end :: !*File -> *File;
write_shstrtab_end file
= file
FWS ".rel.text\000"
FWS ".rel.data\000"
FWS ".symtab\000"
FWS ".strtab\000";
count_relocations :: !Int !{#Char} !{!Symbol} -> Int;
count_relocations old_n_module_relocations relocations symbol_array
= count_relocations 0 0;
{
count_relocations relocation_n n_module_relocations
| relocation_n==old_n_module_relocations
= n_module_relocations;
# relocation_index=relocation_n * SIZE_OF_RELOCATION;
relocation_type=relocations BYTE (relocation_index+RELOCATION_TYPE_OFFSET);
| relocation_type<>R_386_PC32
= count_relocations (relocation_n+1) (n_module_relocations+1);
# relocation_symbol_n=relocations TBYTE (relocation_index+RELOCATION_SYMBOL_N_OFFSET);
= case symbol_array.[relocation_symbol_n] of {
UndefinedLabel symbol_n
= count_relocations (relocation_n+1) (n_module_relocations+1);
_
= count_relocations (relocation_n+1) n_module_relocations;
};
}
write_module_relocations :: !Symbol !Int !Int !SSymbolArray !XcoffArray !{#Int} !{#Int} !*File -> *File;
write_module_relocations (Module _ _ _ _ _ n_module_relocations relocations _) module_offset file_symbol_index symbol_array xcoff_a module_offset_a offset_a pe_file
= write_relocations 0 n_module_relocations relocations pe_file;
{
write_relocations relocation_n n_relocations relocations pe_file
| relocation_n==n_relocations
= pe_file;
# relocation_index=relocation_n * SIZE_OF_RELOCATION;
relocation_type=relocations BYTE (relocation_index+RELOCATION_TYPE_OFFSET);
relocation_symbol_n=relocations TBYTE (relocation_index+RELOCATION_SYMBOL_N_OFFSET);
relocation_offset=relocations LONG relocation_index;
= case symbol_array.[relocation_symbol_n] of {
Module section_n _ _ _ _ _ _ _
# relocation_symbol_n=section_n;
| relocation_type==R_386_PC32
= write_relocations_none relocation_offset relocation_symbol_n relocation_n n_relocations relocations pe_file;
= write_relocations2 relocation_offset relocation_type relocation_symbol_n relocation_n n_relocations relocations pe_file;
Label section_n label_offset section_symbol_n
# (Module section_n _ _ _ _ _ _ _) = symbol_array.[section_symbol_n];
# relocation_symbol_n=section_n;
| relocation_type==R_386_PC32
= write_relocations_none relocation_offset relocation_symbol_n relocation_n n_relocations relocations pe_file;
= write_relocations2 relocation_offset relocation_type relocation_symbol_n relocation_n n_relocations relocations pe_file;
ImportedLabelPlusOffset file_n symbol_n label_offset
# (Module section_n _ _ _ _ _ _ _) = xcoff_a.[file_n].symbol_table.symbols.[symbol_n];
# relocation_symbol_n=section_n;
| relocation_type==R_386_PC32
= write_relocations_none relocation_offset relocation_symbol_n relocation_n n_relocations relocations pe_file;
= write_relocations2 relocation_offset relocation_type relocation_symbol_n relocation_n n_relocations relocations pe_file;
UndefinedLabel symbol_n
# relocation_symbol_n=symbol_n+5;
= write_relocations2 relocation_offset relocation_type relocation_symbol_n relocation_n n_relocations relocations pe_file;
ImportedLabel file_n symbol_n // for commons in .bss
# (Module section_n _ _ _ _ _ _ _) = xcoff_a.[file_n].symbol_table.symbols.[symbol_n];
# relocation_symbol_n=section_n;
| relocation_type==R_386_PC32
= write_relocations_none relocation_offset relocation_symbol_n relocation_n n_relocations relocations pe_file;
= write_relocations2 relocation_offset relocation_type relocation_symbol_n relocation_n n_relocations relocations pe_file;
_
= write_relocations2 relocation_offset relocation_type relocation_symbol_n relocation_n n_relocations relocations pe_file;
};
write_relocations2 relocation_offset relocation_type relocation_symbol_n relocation_n n_relocations relocations pe_file
# pe_file = pe_file FWI (module_offset+relocation_offset) FWI (relocation_type bitor (relocation_symbol_n<<8));
= write_relocations (relocation_n+1) n_relocations relocations pe_file;
write_relocations_none relocation_offset relocation_symbol_n relocation_n n_relocations relocations pe_file
// # pe_file = pe_file FWI (module_offset+relocation_offset) FWI (R_386_NONE bitor (relocation_symbol_n<<8));
= write_relocations (relocation_n+1) n_relocations relocations pe_file;
}
relocate_text :: !.Int Int Int Int Int {#Char} {#SXcoff} {#Int} {#Int} {!Symbol} !*{#.Char} -> .{#Char};
relocate_text n_relocations virtual_address real_module_offset virtual_module_offset first_symbol_n relocations xcoff_a marked_offset_a0 module_offset_a symbol_a text_a0
= relocate_text 0 symbol_a text_a0;
{
relocate_text relocation_n symbol_a text_a0
| relocation_n==n_relocations
= text_a0;
# relocation_index=relocation_n * SIZE_OF_RELOCATION;
relocation_type=relocations BYTE (relocation_index+RELOCATION_TYPE_OFFSET);
relocation_symbol_n=relocations TBYTE (relocation_index+RELOCATION_SYMBOL_N_OFFSET);
relocation_offset=relocations LONG relocation_index;
text1 = case relocation_type of {
R_386_PC32
-> relocate_branch symbol_a.[relocation_symbol_n] relocation_offset (relocation_offset-virtual_address) virtual_module_offset
real_module_offset module_offset_a first_symbol_n relocation_symbol_n symbol_a marked_offset_a0 xcoff_a text_a0;
R_386_32
-> relocate_long_pos symbol_a.[relocation_symbol_n] (relocation_offset-virtual_address) module_offset_a
first_symbol_n relocation_symbol_n symbol_a marked_offset_a0 xcoff_a text_a0;
R_386_NONE
-> text_a0;
}
= relocate_text (relocation_n+1) symbol_a text1;
}
relocate_data :: Int Int Int Int Int String Int {#Int} {#Int} {!Symbol} XcoffArray *{#Char}-> *{#Char};
relocate_data relocation_n n_relocations virtual_module_offset virtual_section_offset real_module_offset text_relocations
first_symbol_n module_offset_a marked_offset_a0 symbol_a xcoff_a data0
| relocation_n==n_relocations
= data0;
# relocation_index=relocation_n * SIZE_OF_RELOCATION;
relocation_type=text_relocations BYTE (relocation_index+4);
relocation_symbol_n=text_relocations TBYTE (relocation_index+RELOCATION_SYMBOL_N_OFFSET);
relocation_offset=text_relocations LONG relocation_index;
data1 = relocate_symbol relocation_type module_offset_a symbol_a marked_offset_a0 xcoff_a data0;
with {
relocate_symbol :: Int {#Int} {!Symbol} {#Int} XcoffArray *{#Char} -> *{#Char};
relocate_symbol R_386_32 module_offset_a symbol_a marked_offset_a0 xcoff_a data0
= 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 xcoff_a data0;
}
= relocate_data (relocation_n+1) n_relocations virtual_module_offset virtual_section_offset real_module_offset text_relocations
first_symbol_n module_offset_a marked_offset_a0 symbol_a xcoff_a data1;
relocate_branch :: Symbol Int Int Int Int {#Int} Int Int {!Symbol} {#Int} XcoffArray *{#Char} -> *{#Char};
relocate_branch (Module TEXT_SECTION virtual_label_offset _ _ _ _ _ _) relocation_offset index virtual_module_offset
real_module_offset module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 xcoff_a text0
# real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
= add_to_long_at_offset ((virtual_module_offset-relocation_offset)+(real_label_offset-real_module_offset)) index text0;
relocate_branch (Label _ /*TEXT_SECTION*/ offset module_n) relocation_offset index virtual_module_offset
real_module_offset module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 xcoff_a text0
= case symbol_a.[module_n] of {
Module TEXT_SECTION virtual_label_offset _ _ _ _ _ _
# real_label_offset = module_offset_a.[first_symbol_n+ /*symbol_n*/ module_n]+offset;
-> add_to_long_at_offset ((virtual_label_offset-relocation_offset)+(real_label_offset-real_module_offset)) index text0;
};
relocate_branch (ImportedLabel file_n symbol_n) relocation_offset index virtual_module_offset
real_module_offset module_offset_a first_symbol_n _ symbol_a marked_offset_a0 xcoff_a text0
| file_n<0
# real_label_offset = module_offset_a.[marked_offset_a0.[file_n + size marked_offset_a0]+symbol_n];
= add_to_long_at_offset ((virtual_module_offset-relocation_offset)+(real_label_offset-real_module_offset)) index text0;
# first_symbol_n = marked_offset_a0.[file_n];
symbol_a=xcoff_a.[file_n].symbol_table.symbols;
= case (symbol_a.[symbol_n]) of {
Module TEXT_SECTION _ _ _ _ _ _ _
# real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
-> add_to_long_at_offset ((virtual_module_offset-relocation_offset)+(real_label_offset-real_module_offset)) index text0;
// _ -> abort ("relocate_branch "+++file_name+++" "+++toString file_n+++" "+++toString symbol_n);
};
relocate_branch (ImportedLabelPlusOffset file_n symbol_n label_offset) relocation_offset index virtual_module_offset
real_module_offset module_offset_a first_symbol_n _ symbol_a marked_offset_a0 xcoff_a text0
# first_symbol_n = marked_offset_a0.[file_n];
symbol_a=xcoff_a.[file_n].symbol_table.symbols;
= case (symbol_a.[symbol_n]) of {
Module TEXT_SECTION _ _ _ _ _ _ _
# real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
-> add_to_long_at_offset ((virtual_module_offset-relocation_offset)+(real_label_offset-real_module_offset)+label_offset) index text0;
};
relocate_branch (UndefinedLabel _) relocation_offset index virtual_module_offset
real_module_offset module_offset_a first_symbol_n _ symbol_a marked_offset_a0 xcoff_a text
= text;
relocate_long_pos :: Symbol Int {#Int} Int Int {!Symbol} {#Int} XcoffArray *{#Char} -> *{#Char};
relocate_long_pos (Module section_n virtual_label_offset _ _ _ _ _ _) index module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 xcoff_a data0
# real_label_offset=module_offset_a.[first_symbol_n+symbol_n];
= add_to_long_at_offset real_label_offset index data0;
relocate_long_pos (Label _ offset module_n) index module_offset_a first_symbol_n symbol_n symbol_a marked_offset_a0 xcoff_a data0
= case symbol_a.[module_n] of {
Module _ virtual_label_offset _ _ _ _ _ _
# real_label_offset=module_offset_a.[first_symbol_n+module_n];
-> add_to_long_at_offset (real_label_offset+offset-virtual_label_offset) index data0;
};
relocate_long_pos (ImportedLabel file_n symbol_n) index module_offset_a first_symbol_n _ symbol_a marked_offset_a0 xcoff_a data0
| file_n<0
# real_label_offset = module_offset_a.[marked_offset_a0.[file_n + size marked_offset_a0]+symbol_n];
= add_to_long_at_offset real_label_offset index data0;
# first_symbol_n = marked_offset_a0.[file_n];
symbol_a=xcoff_a.[file_n].symbol_table.symbols;
= case symbol_a.[symbol_n] of {
Module section_n _ _ _ _ _ _ _
# real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
-> add_to_long_at_offset real_label_offset index data0;
};
relocate_long_pos (ImportedLabelPlusOffset file_n symbol_n label_offset) index module_offset_a first_symbol_n _ symbol_a marked_offset_a0 xcoff_a data0
# first_symbol_n = marked_offset_a0.[file_n];
symbol_a=xcoff_a.[file_n].symbol_table.symbols;
= case (symbol_a.[symbol_n]) of {
Module section_n _ _ _ _ _ _ _
# real_label_offset = module_offset_a.[first_symbol_n+symbol_n];
-> add_to_long_at_offset (real_label_offset+label_offset) index data0;
};
relocate_long_pos (UndefinedLabel _) index module_offset_a first_symbol_n _ symbol_a marked_offset_a0 xcoff_a data
= data;
add_to_long_at_offset :: Int Int *{#Char} -> *{#Char};
add_to_long_at_offset w index array
# index1 = index+1;
index2 = index+2;
index3 = index+3;
(v0,array)=array![index];
(v1,array)=array![index1];
(v2,array)=array![index2];
(v3,array)=array![index3];
#! array=array;
# v = (toInt v0)+(toInt v1<<8)+(toInt v2<<16)+(toInt v3<<24);
new_v=v+w;
= {array & [index]=toChar new_v,[index1]=toChar (new_v>>8),[index2]=toChar (new_v>>16),[index3]=toChar (new_v>>24)};
module linker;
import StdInt,StdFile,StdArray,StdBool,StdChar,StdString,StdClass;
import elf_linker,set_return_code;
/*
file_names = [
"_startup0.o","_startup1.o","_startup2.o","_system.o","t.o","nfib.o"
];
library_file_names = [
"kernel_library"
];
*/
/*
n_args :: Int;
n_args = code {
ccall n_args "-I"
}
program_arg :: !Int -> {#Char};
program_arg i = code {
ccall program_arg "I-S"
}
parse_arguments = program_arguments 1 n_args;
{
program_arguments n n_args
| n>=n_args
= ([],[]);
| size argument>=2 && argument.[0]=='-' && argument.[1]=='l'
= (files1,[argument % (2,size argument-1):libraries1]);
= ([argument:files1],libraries1);
{}{
argument=program_arg n;
(files1,libraries1)=program_arguments (inc n) n_args;
}
}
*/
import ArgEnv;
parse_arguments
# args=getCommandLine;
# n_args=size args;
# a = program_arguments 1;
{
program_arguments n
| n>=n_args
= ([],[]);
| size argument>=2 && argument.[0]=='-' && argument.[1]=='l'
= (files1,[argument % (2,size argument-1):libraries1]);
= ([argument:files1],libraries1);
{}{
argument=args.[n];
(files1,libraries1)=program_arguments (inc n);
}
}
= a;
Start world
# (file_names,library_file_names) = parse_arguments;
# [output_object_file_name:file_names] = file_names;
# ((ok,undefined_symbols),world) = accFiles (link_elf_files2 file_names output_object_file_name) world;
# world = set_return_code (if ok 0 (-1)) world;
# (stdout,world) = stdio world;
= print_errors undefined_symbols stdout;
print_errors [] f
= f;
print_errors [error:errors] f
= print_errors errors (fwritec '\n' (fwrites error f));
link_elf_files2 file_names exec_file_name files
# (ok,undefined_symbols,files) = link_elf_files file_names exec_file_name files;
= ((ok,undefined_symbols),files);
definition module elf_relocations;
import StdInt,StdArray,StdFile;
import elf_linker_types;
BigOrLittleEndian big little :== big;
SIZE_OF_RELOCATION:==12;
R_SPARC_NONE:==0;
R_SPARC_32:==3;
R_SPARC_WDISP30:==7;
R_SPARC_WDISP22:==8;
R_SPARC_HI22:==9;
R_SPARC_LO10:==12;
R_SPARC_UA32:==23;
SHT_RELA:==4;
SHT_REL:==9;
SHT_relocations:==SHT_RELA;
RELOCATION_TYPE_OFFSET :== 7;
RELOCATION_SYMBOL_N_OFFSET :== 4;
(BYTE) string i :== toInt (string.[i]);
(WORD) :: !{#Char} !Int -> Int;
// (WORD) string i = (string BYTE i<<8) bitor (string BYTE (i+1));
(LONG) :: !{#Char} !Int -> Int;
// (LONG) string i = (string BYTE i<<24) bitor (string BYTE (i+1)<<16) bitor (string BYTE (i+2)<<8) bitor (string BYTE (i+3));
(TBYTE) :: !{#Char} !Int -> Int;
// (TBYTE) string i = (string BYTE i<<16) bitor (string BYTE (i+1)<<8) bitor (string BYTE (i+2));
shstrtab_data_relocations_section_name_offset :== 39;
shstrtab_symbol_table_section_name_offset :== 50;
shstrtab_string_table_section_name_offset :== 58;
shstrtab_size :== 68;
write_elf_header :: !*File -> *File;
write_shstrtab_end :: !*File -> *File;
count_relocations :: !Int !{#Char} !{!Symbol} -> Int;
write_module_relocations :: !Symbol !Int !Int !SSymbolArray !XcoffArray !{#Int} !{#Int} !*File -> *File;
relocate_text :: !.Int Int Int Int Int {#Char} {#SXcoff} {#Int} {#Int} {!Symbol} !*{#.Char} -> .{#Char};
relocate_data :: Int Int Int Int Int String Int {#Int} {#Int} {!Symbol} XcoffArray *{#Char}-> *{#Char};
implementation module elf_relocations;
import StdInt,StdChar,StdArray,StdBool,StdClass,StdFile,StdMisc;
import elf_linker_types;
TEXT_SECTION:==1;
(BYTE) string i :== toInt (string.[i]);
(WORD) :: !{#Char} !Int -> Int;
(WORD) string i = (string BYTE i<<8) bitor (string BYTE (i+1));
(LONG) :: !{#Char} !Int -> Int;
(LONG) string i = (string BYTE i<<24) bitor (string BYTE (i+1)<<16) bitor (string BYTE (i+2)<<8) bitor (string BYTE (i+3));
(TBYTE) :: !{#Char} !Int -> Int;
(TBYTE) string i = (string BYTE i<<16) bitor (string BYTE (i+1)<<8) bitor (string BYTE (i+2));
(FWI) infixl;
(FWI) f i :== fwritei i f;
(FWS) infixl;
(FWS) f s :== fwrites s f;
write_elf_header :: !*File -> *File;
write_elf_header file
= file
FWI 0x7f454c46
FWI 0x01020100
FWI 0
FWI 0
FWI 0x00010002
FWI 1
FWI 0
FWI 0
FWI 0x34
FWI 0
FWI 0x00340000
FWI 0x00000028
FWI 0x00090001;
write_shstrtab_end :: !*File -> *File;
write_shstrtab_end file
= file