aboutsummaryrefslogtreecommitdiff
path: root/gold/i386.cc
blob: 32ee8814bbf55f8d16c61bed8d4f9054609010ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// i386.cc -- i386 target support for gold.

#include "gold.h"
#include "elfcpp.h"
#include "i386.h"
#include "object.h"
#include "target.h"
#include "target-reloc.h"
#include "target-select.h"

namespace
{

using namespace gold;

// The i386 target class.

class Target_i386 : public Sized_target<32, false>
{
 public:
  Target_i386()
    : Sized_target<32, false>(&i386_info)
  { }

  void
  relocate_section(const Symbol_table* symtab,
		   Sized_object<32, false>*,
		   unsigned int,
		   const unsigned char*,
		   size_t,
		   unsigned int,
		   const elfcpp::Elf_types<32>::Elf_Addr*,
		   Symbol**,
		   unsigned char*,
		   elfcpp::Elf_types<32>::Elf_Addr,
		   off_t);

  // The class which implements relocation.
  struct Relocate
  {
    inline void
    operator()(Sized_object<32, false>*, const elfcpp::Rel<32, false>&,
	       unsigned int r_type, Sized_symbol<32>*,
	       elfcpp::Elf_types<32>::Elf_Addr,
	       unsigned char*, elfcpp::Elf_types<32>::Elf_Addr);

  };

 private:
  static const Target::Target_info i386_info;
};

const Target::Target_info Target_i386::i386_info =
{
  32,			// size
  false,		// is_big_endian
  elfcpp::EM_386,	// machine_code
  false,		// has_make_symbol
  false,		// has_resolve,
  0x08048000,		// text_segment_address,
  0x1000,		// abi_pagesize
  0x1000		// common_pagesize
};

// Perform a relocation.

inline void
Target_i386::Relocate::operator()(Sized_object<32, false>* object,
				  const elfcpp::Rel<32, false>&,
				  unsigned int r_type,
				  Sized_symbol<32>*,
				  elfcpp::Elf_types<32>::Elf_Addr value,
				  unsigned char* view,
				  elfcpp::Elf_types<32>::Elf_Addr address)
{
  switch (r_type)
    {
    case elfcpp::R_386_NONE:
      break;

    case elfcpp::R_386_32:
      {
	elfcpp::Elf_Word* wv = reinterpret_cast<elfcpp::Elf_Word*>(view);
	unsigned int x = elfcpp::read_elf_word<false>(wv);
	elfcpp::write_elf_word<false>(wv, x + value);
      }
      break;

    case elfcpp::R_386_PC32:
      {
	elfcpp::Elf_Word* wv = reinterpret_cast<elfcpp::Elf_Word*>(view);
	unsigned int x = elfcpp::read_elf_word<false>(wv);
	elfcpp::write_elf_word<false>(wv, x + value - address);
      }
      break;

    default:
      fprintf(stderr, _("%s: %s: unsupported reloc %u\n"),
	      program_name, object->name().c_str(), r_type);
      // gold_exit(false);
    }
}

// Relocate section data.

void
Target_i386::relocate_section(const Symbol_table* symtab,
			      Sized_object<32, false>* object,
			      unsigned int sh_type,
			      const unsigned char* prelocs,
			      size_t reloc_count,
			      unsigned int local_count,
			      const elfcpp::Elf_types<32>::Elf_Addr* values,
			      Symbol** global_syms,
			      unsigned char* view,
			      elfcpp::Elf_types<32>::Elf_Addr address,
			      off_t view_size)
{
  if (sh_type == elfcpp::SHT_RELA)
    {
      fprintf(stderr, _("%s: %s: unsupported RELA reloc section\n"),
	      program_name, object->name().c_str());
      gold_exit(false);
    }

  gold::relocate_section<32, false, elfcpp::SHT_REL, Target_i386::Relocate>(
    symtab,
    object,
    prelocs,
    reloc_count,
    local_count,
    values,
    global_syms,
    view,
    address,
    view_size);
}

// The i386 target.

Target_i386 target_i386;

// The selector for i386 object files.

class Target_selector_i386 : public Target_selector
{
public:
  Target_selector_i386()
    : Target_selector(elfcpp::EM_386, 32, false)
  { }

  Target*
  recognize(int machine, int osabi, int abiversion) const;
};

// Recognize an i386 object file when we already know that the machine
// number is EM_386.

Target*
Target_selector_i386::recognize(int, int, int) const
{
  return &target_i386;
}

Target_selector_i386 target_selector_i386;

} // End anonymous namespace.