예제 #1
0
 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.DefinedIn = state.cur_section;
     if (sym.DefinedIn == null)
     {
         output.AddSymbol(sym);
         sym.Offset = state.cur_offset;
     }
     else
         sym.Offset = state.cur_sect_offset;
 }
예제 #2
0
            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;

                Regex r = new Regex(WildcardToRegex(input_section));

                switch (selection)
                {
                    case InputFileSelection.All:
                        sections = new List<binary_library.ISection>();
                        foreach (binary_library.IBinaryFile ifile in inputs)
                        {
                            binary_library.ISection sect = ifile.FindSection(r);
                            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(r);
                            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(r);
                                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.DefinedIn = osect;
                        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);
            }
예제 #3
0
        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);

            // Resolve weak symbols
            Dictionary<string, int> globl_syms = new Dictionary<string, int>();
            int sym_idx = 0;
            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))
                    {
                        // 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.DefinedIn = target_section;
                        new_reloc.References.Offset = target_section_offset;
                        new_reloc.References.Size = reloc_target.Size;
                        new_reloc.References.Name = reloc_target.Name;
                        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 (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++;
            }

            // Mark the output as executable
            output.IsExecutable = true;
        }