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;
                    }
                }
            }
Beispiel #5
0
        /* 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);
        }
Beispiel #6
0
        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);