aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2007-09-21 05:31:19 +0000
committerIan Lance Taylor <iant@google.com>2007-09-21 05:31:19 +0000
commitc51e6221b8abc026554349b0e8aa59477753b57b (patch)
tree69da000e6f8a21292026aaa1e7a6b040a5298c45
parentec51df9f1064740196d016ed12c2624049d80ba9 (diff)
downloadgdb-c51e6221b8abc026554349b0e8aa59477753b57b.zip
gdb-c51e6221b8abc026554349b0e8aa59477753b57b.tar.gz
gdb-c51e6221b8abc026554349b0e8aa59477753b57b.tar.bz2
Use nops when doing alignment padding between code sections.
-rw-r--r--gold/i386.cc68
-rw-r--r--gold/layout.cc3
-rw-r--r--gold/output.cc46
-rw-r--r--gold/output.h44
-rw-r--r--gold/target.h20
5 files changed, 173 insertions, 8 deletions
diff --git a/gold/i386.cc b/gold/i386.cc
index 6c1b987..6eb0b2c 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -63,6 +63,10 @@ class Target_i386 : public Sized_target<32, false>
elfcpp::Elf_types<32>::Elf_Addr view_address,
off_t view_size);
+ // Return a string used to fill a code section with nops.
+ std::string
+ do_code_fill(off_t length);
+
private:
// The class which scans relocations.
struct Scan
@@ -212,6 +216,7 @@ const Target::Target_info Target_i386::i386_info =
elfcpp::EM_386, // machine_code
false, // has_make_symbol
false, // has_resolve
+ true, // has_code_fill
"/usr/lib/libc.so.1", // dynamic_linker
0x08048000, // text_segment_address
0x1000, // abi_pagesize
@@ -1490,6 +1495,69 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
view_size);
}
+// Return a string used to fill a code section with nops to take up
+// the specified length.
+
+std::string
+Target_i386::do_code_fill(off_t length)
+{
+ if (length >= 16)
+ {
+ // Build a jmp instruction to skip over the bytes.
+ unsigned char jmp[5];
+ jmp[0] = 0xe9;
+ elfcpp::Swap_unaligned<32, false>::writeval(jmp + 1, length - 5);
+ return (std::string(reinterpret_cast<char*>(&jmp[0]), 5)
+ + std::string(length - 5, '\0'));
+ }
+
+ // Nop sequences of various lengths.
+ const char nop1[1] = { 0x90 }; // nop
+ const char nop2[2] = { 0x66, 0x90 }; // xchg %ax %ax
+ const char nop3[3] = { 0x8d, 0x76, 0x00 }; // leal 0(%esi),%esi
+ const char nop4[4] = { 0x8d, 0x74, 0x26, 0x00}; // leal 0(%esi,1),%esi
+ const char nop5[5] = { 0x90, 0x8d, 0x74, 0x26, // nop
+ 0x00 }; // leal 0(%esi,1),%esi
+ const char nop6[6] = { 0x8d, 0xb6, 0x00, 0x00, // leal 0L(%esi),%esi
+ 0x00, 0x00 };
+ const char nop7[7] = { 0x8d, 0xb4, 0x26, 0x00, // leal 0L(%esi,1),%esi
+ 0x00, 0x00, 0x00 };
+ const char nop8[8] = { 0x90, 0x8d, 0xb4, 0x26, // nop
+ 0x00, 0x00, 0x00, 0x00 }; // leal 0L(%esi,1),%esi
+ const char nop9[9] = { 0x89, 0xf6, 0x8d, 0xbc, // movl %esi,%esi
+ 0x27, 0x00, 0x00, 0x00, // leal 0L(%edi,1),%edi
+ 0x00 };
+ const char nop10[10] = { 0x8d, 0x76, 0x00, 0x8d, // leal 0(%esi),%esi
+ 0xbc, 0x27, 0x00, 0x00, // leal 0L(%edi,1),%edi
+ 0x00, 0x00 };
+ const char nop11[11] = { 0x8d, 0x74, 0x26, 0x00, // leal 0(%esi,1),%esi
+ 0x8d, 0xbc, 0x27, 0x00, // leal 0L(%edi,1),%edi
+ 0x00, 0x00, 0x00 };
+ const char nop12[12] = { 0x8d, 0xb6, 0x00, 0x00, // leal 0L(%esi),%esi
+ 0x00, 0x00, 0x8d, 0xbf, // leal 0L(%edi),%edi
+ 0x00, 0x00, 0x00, 0x00 };
+ const char nop13[13] = { 0x8d, 0xb6, 0x00, 0x00, // leal 0L(%esi),%esi
+ 0x00, 0x00, 0x8d, 0xbc, // leal 0L(%edi,1),%edi
+ 0x27, 0x00, 0x00, 0x00,
+ 0x00 };
+ const char nop14[14] = { 0x8d, 0xb4, 0x26, 0x00, // leal 0L(%esi,1),%esi
+ 0x00, 0x00, 0x00, 0x8d, // leal 0L(%edi,1),%edi
+ 0xbc, 0x27, 0x00, 0x00,
+ 0x00, 0x00 };
+ const char nop15[15] = { 0xeb, 0x0d, 0x90, 0x90, // jmp .+15
+ 0x90, 0x90, 0x90, 0x90, // nop,nop,nop,...
+ 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90 };
+
+ const char* nops[16] = {
+ NULL,
+ nop1, nop2, nop3, nop4, nop5, nop6, nop7,
+ nop8, nop9, nop10, nop11, nop12, nop13, nop14, nop15
+ };
+
+ return std::string(nops[length], length);
+}
+
// The selector for i386 object files.
class Target_selector_i386 : public Target_selector
diff --git a/gold/layout.cc b/gold/layout.cc
index 3e8a223..35de9e4 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -28,7 +28,8 @@ Layout_task_runner::run(Workqueue* workqueue)
// Now we know the final size of the output file and we know where
// each piece of information goes.
- Output_file* of = new Output_file(this->options_);
+ Output_file* of = new Output_file(this->options_,
+ this->input_objects_->target());
of->open(file_size);
// Queue up the final set of tasks.
diff --git a/gold/output.cc b/gold/output.cc
index ddf2ebb..bbd7af1 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -863,6 +863,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
dynsym_index_(0),
input_sections_(),
first_input_offset_(0),
+ fills_(),
needs_symtab_index_(false),
needs_dynsym_index_(false),
should_link_to_symtab_(false),
@@ -923,19 +924,41 @@ Output_section::add_input_section(Relobj* object, unsigned int shndx,
}
}
- off_t ssize = this->data_size();
- ssize = align_address(ssize, addralign);
- this->set_data_size(ssize + shdr.get_sh_size());
+ off_t offset_in_section = this->data_size();
+ off_t aligned_offset_in_section = align_address(offset_in_section,
+ addralign);
+
+ if (aligned_offset_in_section > offset_in_section
+ && (shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) != 0
+ && object->target()->has_code_fill())
+ {
+ // We need to add some fill data. Using fill_list_ when
+ // possible is an optimization, since we will often have fill
+ // sections without input sections.
+ off_t fill_len = aligned_offset_in_section - offset_in_section;
+ if (this->input_sections_.empty())
+ this->fills_.push_back(Fill(offset_in_section, fill_len));
+ else
+ {
+ // FIXME: When relaxing, the size needs to adjust to
+ // maintain a constant alignment.
+ std::string fill_data(object->target()->code_fill(fill_len));
+ Output_data_const* odc = new Output_data_const(fill_data, 1);
+ this->input_sections_.push_back(Input_section(odc));
+ }
+ }
+
+ this->set_data_size(aligned_offset_in_section + shdr.get_sh_size());
// We need to keep track of this section if we are already keeping
// track of sections, or if we are relaxing. FIXME: Add test for
// relaxing.
- if (! this->input_sections_.empty())
+ if (!this->input_sections_.empty())
this->input_sections_.push_back(Input_section(object, shndx,
shdr.get_sh_size(),
addralign));
- return ssize;
+ return aligned_offset_in_section;
}
// Add arbitrary data to an output section.
@@ -1105,6 +1128,16 @@ Output_section::write_header(const Layout* layout,
void
Output_section::do_write(Output_file* of)
{
+ off_t output_section_file_offset = this->offset();
+ for (Fill_list::iterator p = this->fills_.begin();
+ p != this->fills_.end();
+ ++p)
+ {
+ std::string fill_data(of->target()->code_fill(p->length()));
+ of->write(output_section_file_offset + p->section_offset(),
+ fill_data.data(), fill_data.size());
+ }
+
for (Input_section_list::iterator p = this->input_sections_.begin();
p != this->input_sections_.end();
++p)
@@ -1496,8 +1529,9 @@ Output_segment::write_section_headers_list(const Layout* layout,
// Output_file methods.
-Output_file::Output_file(const General_options& options)
+Output_file::Output_file(const General_options& options, Target* target)
: options_(options),
+ target_(target),
name_(options.output_file_name()),
o_(-1),
file_size_(0),
diff --git a/gold/output.h b/gold/output.h
index 49cc7ca..b219805 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -1533,6 +1533,37 @@ class Output_section : public Output_data
typedef std::vector<Input_section> Input_section_list;
+ // Fill data. This is used to fill in data between input sections.
+ // When we have to keep track of the input sections, we can use an
+ // Output_data_const, but we don't want to have to keep track of
+ // input sections just to implement fills. For a fill we record the
+ // offset, and the actual data to be written out.
+ class Fill
+ {
+ public:
+ Fill(off_t section_offset, off_t length)
+ : section_offset_(section_offset), length_(length)
+ { }
+
+ // Return section offset.
+ off_t
+ section_offset() const
+ { return this->section_offset_; }
+
+ // Return fill length.
+ off_t
+ length() const
+ { return this->length_; }
+
+ private:
+ // The offset within the output section.
+ off_t section_offset_;
+ // The length of the space to fill.
+ off_t length_;
+ };
+
+ typedef std::vector<Fill> Fill_list;
+
// Add a new output section by Input_section.
void
add_output_section_data(Input_section*);
@@ -1590,6 +1621,10 @@ class Output_section : public Output_data
Input_section_list input_sections_;
// The offset of the first entry in input_sections_.
off_t first_input_offset_;
+ // The fill data. This is separate from input_sections_ because we
+ // often will need fill sections without needing to keep track of
+ // input sections.
+ Fill_list fills_;
// Whether this output section needs a STT_SECTION symbol in the
// normal symbol table. This will be true if there is a relocation
// which needs it.
@@ -1765,7 +1800,12 @@ class Output_segment
class Output_file
{
public:
- Output_file(const General_options& options);
+ Output_file(const General_options& options, Target*);
+
+ // Get a pointer to the target.
+ Target*
+ target() const
+ { return this->target_; }
// Open the output file. FILE_SIZE is the final size of the file.
void
@@ -1801,6 +1841,8 @@ class Output_file
private:
// General options.
const General_options& options_;
+ // Target.
+ Target* target_;
// File name.
const char* name_;
// File descriptor.
diff --git a/gold/target.h b/gold/target.h
index 9181a93..06c7c3d 100644
--- a/gold/target.h
+++ b/gold/target.h
@@ -63,6 +63,11 @@ class Target
has_resolve() const
{ return this->pti_->has_resolve; }
+ // Whether this target has a specific code fill function.
+ bool
+ has_code_fill() const
+ { return this->pti_->has_code_fill; }
+
// Return the default name of the dynamic linker.
const char*
dynamic_linker() const
@@ -89,6 +94,13 @@ class Target
finalize_sections(const General_options* options, Layout* layout)
{ return this->do_finalize_sections(options, layout); }
+ // Return a string to use to fill out a code section. This is
+ // basically one or more NOPS which must fill out the specified
+ // length in bytes.
+ std::string
+ code_fill(off_t length)
+ { return this->do_code_fill(length); }
+
protected:
// This struct holds the constant information for a child class. We
// use a struct to avoid the overhead of virtual function calls for
@@ -105,6 +117,8 @@ class Target
bool has_make_symbol;
// Whether this target has a specific resolve function.
bool has_resolve;
+ // Whether this target has a specific code fill function.
+ bool has_code_fill;
// The default dynamic linker name.
const char* dynamic_linker;
// The default text segment address.
@@ -124,6 +138,12 @@ class Target
do_finalize_sections(const General_options*, Layout*)
{ }
+ // Virtual function which must be implemented by the child class if
+ // needed.
+ virtual std::string
+ do_code_fill(off_t)
+ { gold_unreachable(); }
+
private:
Target(const Target&);
Target& operator=(const Target&);