public override void DoCommand(binary_library.IBinaryFile output, IList <binary_library.IBinaryFile> inputs, LinkerScriptState state) { switch (_type) { case UpdateType.Add: state.cur_offset += new_offset; break; case UpdateType.Set: state.cur_offset = new_offset; break; case UpdateType.Subtract: state.cur_offset -= new_offset; break; case UpdateType.Align: if (new_offset != 0) { if ((state.cur_offset % new_offset) != 0) { state.cur_offset = (state.cur_offset / new_offset) * new_offset + new_offset; } } break; } }
public override void DoCommand(binary_library.IBinaryFile output, IList <binary_library.IBinaryFile> inputs, LinkerScriptState state) { binary_library.ISymbol sym = output.CreateSymbol(); sym.Name = name; sym.Type = binary_library.SymbolType.Global; sym.Offset = state.cur_sect_offset; state.cur_section.AddSymbol(sym); }
public override void DoCommand(binary_library.IBinaryFile output, IList <binary_library.IBinaryFile> inputs, LinkerScriptState state) { output.AddSection(state.cur_section); if (state.cur_section.HasData) { state.cur_offset += (ulong)state.data[state.cur_section].Count; } else { state.cur_offset += (ulong)state.cur_section.Length; } state.cur_section = state.prev_section; }
public override void DoCommand(binary_library.IBinaryFile output, IList <binary_library.IBinaryFile> inputs, LinkerScriptState state) { state.prev_section = state.cur_section; binary_library.ISection section = output.CreateSection(); section.Name = name; section.AddrAlign = addr_align; section.IsAlloc = isalloc; section.IsWriteable = iswrite; section.IsExecutable = isexec; section.HasData = hasdata; section.LoadAddress = state.cur_offset; state.cur_section = section; state.data[section] = new List <byte>(); state.cur_sect_offset = 0; if (hasdata && size < 0) { switch (size) { case -1: // elf dynamic if (output.Bitness == Bitness.Bits64) { state.cur_section.Length = 464; } else { state.cur_section.Length = 192; } break; case -2: // elf hash int ssize = 8; // nbuckets + nchain ssize += binary_library.elf.ElfFile.CalculateBucketCount(output.GetSymbolCount()) * 4; ssize += output.GetSymbolCount() * 4; state.cur_section.Length = ssize; break; } } }
/* Vtable: * * TIPtr (just to a glorified TypeSpec) * IFacePtr (to list of implemented interfaces) * Extends (to base classes for quick castclassex) * TypeSize (to allow MemberwiseClone to work without full Reflection) * Any target-specific data * Method 0 * ... * * IFaceList TODO * * */ public static void OutputVTable(TypeSpec ts, target.Target t, binary_library.IBinaryFile of, TysilaState s, MetadataStream base_m = null, ISection os = null, ISection data_sect = null) { // Don't compile if not for this architecture if (!t.IsTypeValid(ts)) { return; } /* New signature table */ s.sigt = new SignatureTable(ts.MangleType()); // If its a delegate type we also need to output its methods if (ts.IsDelegate && !ts.IsGenericTemplate) { s.r.DelegateRequestor.Request(ts); } if (os == null) { os = of.GetRDataSection(); } var d = os.Data; var ptr_size = t.GetCTSize(ir.Opcode.ct_object); os.Align(ptr_size); ulong offset = (ulong)os.Data.Count; /* Symbol */ var sym = of.CreateSymbol(); sym.Name = ts.MangleType(); sym.ObjectType = binary_library.SymbolObjectType.Object; sym.Offset = offset; sym.Type = binary_library.SymbolType.Global; os.AddSymbol(sym); if (base_m != null && ts.m != base_m) { sym.Type = SymbolType.Weak; } /* TIPtr */ var tiptr_offset = s.sigt.GetSignatureAddress(ts.Signature, t, s); var ti_reloc = of.CreateRelocation(); ti_reloc.Addend = tiptr_offset; ti_reloc.DefinedIn = os; ti_reloc.Offset = offset; ti_reloc.Type = t.GetDataToDataReloc(); ti_reloc.References = of.CreateSymbol(); ti_reloc.References.Name = s.sigt.GetStringTableName(); of.AddRelocation(ti_reloc); for (int i = 0; i < ptr_size; i++, offset++) { d.Add(0); } /* IFacePtr */ IRelocation if_reloc = null; if (!ts.IsGenericTemplate && !ts.IsInterface && ts.stype != TypeSpec.SpecialType.Ptr && ts.stype != TypeSpec.SpecialType.MPtr) { if_reloc = of.CreateRelocation(); if_reloc.DefinedIn = os; if_reloc.Offset = offset; if_reloc.Type = t.GetDataToDataReloc(); if_reloc.References = sym; of.AddRelocation(if_reloc); } for (int i = 0; i < ptr_size; i++, offset++) { d.Add(0); } /* Extends */ var ts_extends = ts.GetExtends(); if (ts_extends != null) { var ext_reloc = of.CreateRelocation(); ext_reloc.Addend = 0; ext_reloc.DefinedIn = os; ext_reloc.Offset = offset; ext_reloc.Type = t.GetDataToDataReloc(); var ext_sym = of.CreateSymbol(); ext_sym.Name = ts_extends.MangleType(); ext_reloc.References = ext_sym; of.AddRelocation(ext_reloc); s.r.VTableRequestor.Request(ts_extends); } for (int i = 0; i < ptr_size; i++, offset++) { d.Add(0); } if (ts.IsInterface || ts.IsGenericTemplate || ts.stype == TypeSpec.SpecialType.MPtr || ts.stype == TypeSpec.SpecialType.Ptr) { /* Type size is zero for somethinh we cannot * instantiate */ for (int i = 0; i < ptr_size; i++, offset++) { d.Add(0); } /* Flags */ AddFlags(d, ts, ref offset, t); /* BaseType */ AddBaseType(d, ts, of, os, ref offset, t, s); // Target-specific information t.AddExtraVTableFields(ts, d, ref offset); } else { /* Type size */ var tsize = t.IntPtrArray(BitConverter.GetBytes(GetTypeSize(ts, t))); foreach (var b in tsize) { d.Add(b); offset++; } /* Flags */ AddFlags(d, ts, ref offset, t); /* BaseType */ AddBaseType(d, ts, of, os, ref offset, t, s); // Target specific information t.AddExtraVTableFields(ts, d, ref offset); /* Virtual methods */ OutputVirtualMethods(ts, of, os, d, ref offset, t, s); /* Interface implementations */ // build list of implemented interfaces var ii = ts.ImplementedInterfaces; // first, add all interface implementations List <ulong> ii_offsets = new List <ulong>(); for (int i = 0; i < ii.Count; i++) { ii_offsets.Add(offset - sym.Offset); OutputInterface(ts, ii[i], of, os, d, ref offset, t, s); s.r.VTableRequestor.Request(ii[i]); } // point iface ptr here if_reloc.Addend = (long)offset - (long)sym.Offset; for (int i = 0; i < ii.Count; i++) { // list is pointer to interface declaration, then implementation var id_ptr_sym = of.CreateSymbol(); id_ptr_sym.Name = ii[i].MangleType(); var id_ptr_reloc = of.CreateRelocation(); id_ptr_reloc.Addend = 0; id_ptr_reloc.DefinedIn = os; id_ptr_reloc.Offset = offset; id_ptr_reloc.References = id_ptr_sym; id_ptr_reloc.Type = t.GetDataToDataReloc(); of.AddRelocation(id_ptr_reloc); for (int j = 0; j < ptr_size; j++, offset++) { d.Add(0); } // implementation var ii_ptr_reloc = of.CreateRelocation(); ii_ptr_reloc.Addend = (long)ii_offsets[i]; ii_ptr_reloc.DefinedIn = os; ii_ptr_reloc.Offset = offset; ii_ptr_reloc.References = sym; ii_ptr_reloc.Type = t.GetDataToDataReloc(); of.AddRelocation(ii_ptr_reloc); for (int j = 0; j < ptr_size; j++, offset++) { d.Add(0); } } // null terminate the list for (int j = 0; j < ptr_size; j++, offset++) { d.Add(0); } } sym.Size = (long)(offset - sym.Offset); /* Output signature table if any */ if (data_sect == null) { data_sect = of.GetDataSection(); } s.sigt.WriteToOutput(of, base_m, t, data_sect); }
public static void OutputStaticFields(metadata.TypeSpec ts, target.Target t, binary_library.IBinaryFile of, MetadataStream base_m = null, binary_library.ISection os = null, binary_library.ISection tlsos = null) { // Don't compile if not for this architecture if (!t.IsTypeValid(ts)) { return; } int align = 1; if (ts.SimpleType == 0) { align = GetTypeAlignment(ts, t, true); } if (os == null) { os = of.GetDataSection(); } os.Align(t.GetPointerSize()); os.Align(align); ulong offset = (ulong)os.Data.Count; ulong tl_offset = 0; if (tlsos != null) { tl_offset = (ulong)tlsos.Data.Count; } int cur_offset = 0; int cur_tloffset = 0; /* is_initialized */ for (int i = 0; i < t.psize; i++) { os.Data.Add(0); } cur_offset += t.psize; /* Iterate through methods looking for requested * one */ var first_fdef = ts.m.GetIntEntry(MetadataStream.tid_TypeDef, ts.tdrow, 4); var last_fdef = ts.m.GetLastFieldDef(ts.tdrow); for (uint fdef_row = first_fdef; fdef_row < last_fdef; fdef_row++) { // Ensure field is static or not as required var flags = ts.m.GetIntEntry(MetadataStream.tid_Field, (int)fdef_row, 0); if ((flags & 0x10) == 0x10) { // Increment by type size var fsig = (int)ts.m.GetIntEntry(MetadataStream.tid_Field, (int)fdef_row, 2); var ft = ts.m.GetFieldType(ref fsig, ts.gtparams, null); var ft_size = t.GetSize(ft); ft_size = util.util.align(ft_size, align); bool is_tls = ts.m.thread_local_fields[(int)fdef_row]; ISection cur_os = os; if (is_tls) { if (tlsos == null) { throw new NotSupportedException("No thread-local section provided"); } cur_os = tlsos; } /* See if there is any data defined as an rva */ var rva = ts.m.fieldrvas[(int)fdef_row]; if (rva != 0) { var rrva = (int)ts.m.ResolveRVA(rva); for (int i = 0; i < ft_size; i++) { cur_os.Data.Add(ts.m.file.ReadByte(rrva++)); } } else { for (int i = 0; i < ft_size; i++) { cur_os.Data.Add(0); } } /* Output any additional defined symbols */ foreach (var alias in ts.m.GetFieldAliases((int)fdef_row)) { var asym = of.CreateSymbol(); asym.Name = alias; asym.Offset = offset + (ulong)cur_offset; asym.Type = binary_library.SymbolType.Global; asym.ObjectType = binary_library.SymbolObjectType.Object; cur_os.AddSymbol(asym); asym.Size = ft_size; if (base_m != null && ts.m != base_m) { asym.Type = binary_library.SymbolType.Weak; } } if (is_tls) { cur_tloffset += ft_size; } else { cur_offset += ft_size; } } } if (cur_offset > 0) { /* Add symbol */ var sym = of.CreateSymbol(); sym.Name = ts.m.MangleType(ts) + "S"; sym.Offset = offset; sym.Type = binary_library.SymbolType.Global; sym.ObjectType = binary_library.SymbolObjectType.Object; os.AddSymbol(sym); sym.Size = os.Data.Count - (int)offset; if (base_m != null && ts.m != base_m) { sym.Type = binary_library.SymbolType.Weak; } } if (cur_tloffset > 0) { /* Add thread local symbol */ var sym = of.CreateSymbol(); sym.Name = ts.m.MangleType(ts) + "ST"; sym.Offset = tl_offset; sym.Type = binary_library.SymbolType.Global; sym.ObjectType = binary_library.SymbolObjectType.Object; tlsos.AddSymbol(sym); sym.Size = tlsos.Data.Count - (int)tl_offset; if (base_m != null && ts.m != base_m) { sym.Type = binary_library.SymbolType.Weak; } } }
public override void DoCommand(binary_library.IBinaryFile output, IList <binary_library.IBinaryFile> inputs, LinkerScriptState state) { // Generate a list of sections to include IList <binary_library.ISection> sections = null; switch (selection) { case InputFileSelection.All: sections = new List <binary_library.ISection>(); foreach (binary_library.IBinaryFile ifile in inputs) { binary_library.ISection sect = ifile.FindSection(input_section); if (sect != null) { sections.Add(sect); } } break; case InputFileSelection.AllNotSpecified: sections = new List <binary_library.ISection>(); foreach (binary_library.IBinaryFile ifile in inputs) { binary_library.ISection sect = ifile.FindSection(input_section); if ((sect != null) && (!state.included_sections.Contains(sect))) { sections.Add(sect); } } break; case InputFileSelection.Specific: sections = new List <binary_library.ISection>(); foreach (binary_library.IBinaryFile ifile in inputs) { System.IO.FileInfo fi = new System.IO.FileInfo(ifile.Filename); if (fi.Exists && (fi.Name == input_file)) { binary_library.ISection sect = ifile.FindSection(input_section); if ((sect != null) && (!state.included_sections.Contains(sect))) { sections.Add(sect); } } } break; } // Write the sections data to the section cache and its symbols to the output file binary_library.ISection osect = state.cur_section; foreach (binary_library.ISection sect in sections) { // Write the data if (osect.HasData) { if (sect.HasData) { foreach (byte b in sect.Data) { state.data[osect].Add(b); } } else { for (int i = 0; i < sect.Length; i++) { state.data[osect].Add(0); } } } else { osect.Length += sect.Length; } // Write the symbols int sym_count = sect.GetSymbolCount(); for (int i = 0; i < sym_count; i++) { ISymbol sym = sect.GetSymbol(i); ISymbol new_sym = output.CreateSymbol(); new_sym.Name = sym.Name; new_sym.Offset = state.cur_sect_offset + sym.Offset; new_sym.Size = sym.Size; new_sym.Type = sym.Type; new_sym.ObjectType = sym.ObjectType; osect.AddSymbol(new_sym); } // Save where this section is loaded to state.input_section_locations[sect] = new LinkerScriptState.InputSectionLocation { OutputSection = osect, OutputSectionOffset = state.cur_sect_offset }; state.cur_sect_offset += (ulong)sect.Length; } // Add the sections to the list of included sections state.included_sections.AddRange(sections); }
public void RunScript(binary_library.IBinaryFile output, IList <binary_library.IBinaryFile> inputs) { // First, identify the maximum sizes of common symbols Dictionary <string, SizeAlign> comm_syms = new Dictionary <string, SizeAlign>(); foreach (var iput in inputs) { var comm = iput.GetCommonSection(); if (comm != null) { for (int i = 0; i < comm.GetSymbolCount(); i++) { var comm_sym = comm.GetSymbol(i); if (comm_sym != null) { string name = comm_sym.Name; if (comm_sym.Type == SymbolType.Local) { name = iput.Filename + "." + name; } if (!comm_syms.ContainsKey(name) || comm_syms[name].Size < comm_sym.Size) { comm_syms[name] = new SizeAlign { Size = (int)comm_sym.Size, Align = (int)comm_sym.Offset, Sym = comm_sym } } ; } } } } int comm_len = 0; foreach (var k in comm_syms) { if ((comm_len % k.Value.Align) != 0) { comm_len = (comm_len / k.Value.Align) * k.Value.Align + k.Value.Align; } comm_len += k.Value.Size; } // Run the script LinkerScriptState state = new LinkerScriptState(); state.comm_length = comm_len; state.cur_section = output.GetGlobalSection(); foreach (ScriptEntry se in Script) { se.DoCommand(output, inputs, state); } if (Program.is_reloc) { output.IsExecutable = false; } else { output.IsExecutable = true; } Dictionary <string, int> globl_syms = new Dictionary <string, int>(); int sym_idx = 0; if (output.IsExecutable) { // Resolve weak symbols while (sym_idx < output.GetSymbolCount()) { ISymbol sym = output.GetSymbol(sym_idx); if (sym.Type == SymbolType.Weak) { // Whether to promote to a global symbol bool for_removal = false; // Have we found the appropriate global symbol before? if (globl_syms.ContainsKey(sym.Name)) { for_removal = true; // for removal } else { // Search from here onwards looking for a global // symbol with the same name for (int sym_idx_2 = sym_idx; sym_idx_2 < output.GetSymbolCount(); sym_idx_2++) { ISymbol sym_2 = output.GetSymbol(sym_idx_2); if (sym_2.Type == SymbolType.Global && sym_2.Name == sym.Name) { globl_syms[sym.Name] = sym_idx_2; for_removal = true; break; } } } if (for_removal) { output.RemoveSymbol(sym_idx); continue; } else { // Promote to a global symbol sym.Type = SymbolType.Global; globl_syms[sym.Name] = sym_idx; } } else if (sym.Type == SymbolType.Global) { globl_syms[sym.Name] = sym_idx; } sym_idx++; } // Resolve common symbols. If a global symbol is defined for // this, we use that, else we allocate a space in bss for it ulong cur_comm_sym_offset = state.comm_offset; foreach (var k in comm_syms.Keys) { if (!globl_syms.ContainsKey(k)) { // define a symbol in the common section for this if (state.comm_sect == null) { throw new Exception("Common sections used but no common section defined in linker script"); } uint align = (uint)comm_syms[k].Align; if ((cur_comm_sym_offset % align) != 0) { cur_comm_sym_offset = (cur_comm_sym_offset / align) * align + align; } ISymbol comm_sym = comm_syms[k].Sym; //comm_sym.DefinedIn = state.comm_sect; comm_sym.Offset = cur_comm_sym_offset; comm_sym.Name = k; cur_comm_sym_offset += (uint)comm_syms[k].Size; } } } // Now iterate through the data, saving to the appropriate sections foreach (KeyValuePair <binary_library.ISection, List <byte> > kvp in state.data) { if (kvp.Key != null) { if (kvp.Key.HasData) { kvp.Key.Length = kvp.Value.Count; for (int i = 0; i < kvp.Value.Count; i++) { kvp.Key.Data[i] = kvp.Value[i]; } } } } // Resolve relocations foreach (IBinaryFile ifile in inputs) { int reloc_count = ifile.GetRelocationCount(); for (int i = 0; i < reloc_count; i++) { IRelocation reloc = ifile.GetRelocation(i); // Is the location of the relocation included in the output? if (state.included_sections.Contains(reloc.DefinedIn)) { if (output.IsExecutable == false) { // Create a new relocation for the output file IRelocation new_copy_reloc = output.CreateRelocation(); new_copy_reloc.DefinedIn = state.input_section_locations[reloc.DefinedIn].OutputSection; new_copy_reloc.Offset = reloc.Offset + state.input_section_locations[reloc.DefinedIn].OutputSectionOffset; new_copy_reloc.Addend = reloc.Addend; new_copy_reloc.References = reloc.References; new_copy_reloc.Type = reloc.Type; output.AddRelocation(new_copy_reloc); continue; } // Where is the value to be relocated? LinkerScriptState.InputSectionLocation isl = state.input_section_locations[reloc.DefinedIn]; // Get the target of the relocation ISymbol reloc_target = reloc.References; ISection target_section = null; ulong target_section_offset = 0; if (reloc_target.DefinedIn == null) { // Try and find the requested symbol ISymbol found_target = output.FindSymbol(reloc_target.Name); if (found_target == null) { throw new Exception("Label '" + reloc_target.Name + "' not found"); } target_section = found_target.DefinedIn; target_section_offset = found_target.Offset; } else if (reloc_target.DefinedIn == reloc_target.DefinedIn.File.GetCommonSection()) { // Get full name of symbol string name = reloc_target.Name; if (reloc_target.Type == SymbolType.Local) { name = reloc_target.DefinedIn.File.Filename + "." + name; } target_section = state.comm_sect; if (globl_syms.ContainsKey(name)) { ISymbol found_target = output.FindSymbol(reloc_target.Name); if (found_target == null) { throw new Exception("Label '" + reloc_target.Name + "' not found"); } target_section = found_target.DefinedIn; target_section_offset = found_target.Offset; } else { target_section = state.comm_sect; target_section_offset = reloc_target.Offset; } } else { // Use the one stored in the relocation // First find out where the input section is located in the output if (!state.included_sections.Contains(reloc_target.DefinedIn)) { throw new Exception(); } LinkerScriptState.InputSectionLocation target_isl = state.input_section_locations[reloc_target.DefinedIn]; target_section = target_isl.OutputSection; target_section_offset = target_isl.OutputSectionOffset + reloc_target.Offset; } // Create a new relocation for the output file IRelocation new_reloc = output.CreateRelocation(); new_reloc.DefinedIn = isl.OutputSection; new_reloc.Offset = isl.OutputSectionOffset + reloc.Offset; new_reloc.Addend = reloc.Addend; new_reloc.References = output.CreateSymbol(); new_reloc.References.Offset = target_section_offset; new_reloc.References.Size = reloc_target.Size; new_reloc.References.Name = reloc_target.Name; target_section.AddSymbol(new_reloc.References); new_reloc.Type = reloc.Type; // Evaluate the relocation long val = new_reloc.Type.Evaluate(new_reloc); // Does it fit in the provided space? bool fits = true; ulong uval = BitConverter.ToUInt64(BitConverter.GetBytes(val), 0); var t = new_reloc.Type; ulong ext_mask = 0xffffffffffffffffUL << (t.BitLength + t.BitOffset); if ((t.BitLength + t.BitOffset) >= 64) { ext_mask = 0; } if (new_reloc.Type.IsSigned) { var sign_bit = (uval >> (t.BitLength + t.BitOffset - 1)) & 0x1; if (sign_bit == 1 && (uval & ext_mask) != ext_mask) { fits = false; } else if (sign_bit == 0 && (uval & ext_mask) != 0) { fits = false; } } else if ((uval & ext_mask) != 0) { fits = false; } if (fits == false) { throw new Exception("Relocation truncated to fit: " + reloc_target.Name + " against " + t.Name); } // Build the new value to reinsert in the data stream byte[] orig = new byte[8]; for (int idx = 0; idx < new_reloc.Type.Length; idx++) { orig[idx] = new_reloc.DefinedIn.Data[(int)new_reloc.Offset + idx]; } ulong orig_val = BitConverter.ToUInt64(orig, 0); // Mask out those bits we don't want orig_val &= new_reloc.Type.KeepMask; // Only set those bits we want uval &= new_reloc.Type.SetMask; uval |= orig_val; byte[] uvalb = BitConverter.GetBytes(uval); for (int idx = 0; idx < new_reloc.Type.Length; idx++) { new_reloc.DefinedIn.Data[(int)new_reloc.Offset + idx] = uvalb[idx]; } } } } // Remove local and undefined symbols from the output file sym_idx = 0; while (sym_idx < output.GetSymbolCount()) { ISymbol sym = output.GetSymbol(sym_idx); if (sym.Type == SymbolType.Local || sym.Type == SymbolType.Undefined) { output.RemoveSymbol(sym_idx); } else { sym_idx++; } } }
public abstract void DoCommand(binary_library.IBinaryFile output, IList <binary_library.IBinaryFile> inputs, LinkerScriptState state);