2000-12-07 Kazu Hirata <kazu@hxi.com>
[external/binutils.git] / bfd / elf64-x86-64.c
1 /* X86-64 specific support for 64-bit ELF
2    Copyright 2000 Free Software Foundation, Inc.
3    Contributed by Jan Hubicka <jh@suse.cz>.
4
5 This file is part of BFD, the Binary File Descriptor library.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #include "bfd.h"
22 #include "sysdep.h"
23 #include "libbfd.h"
24 #include "elf-bfd.h"
25
26 #include "elf/x86-64.h"
27
28 /* We use only the RELA entries.  */
29 #define USE_RELA
30
31 /* In case we're on a 32-bit machine, construct a 64-bit "-1" value.  */
32 #define MINUS_ONE (~ (bfd_vma) 0)
33
34 /* The relocation "howto" table.  Order of fields:
35    type, size, bitsize, pc_relative, complain_on_overflow, special_function,
36    name, partial_inplace, src_mask, dst_pack, pcrel_offset  */
37 static reloc_howto_type x86_64_elf_howto_table[] = {
38   HOWTO(R_X86_64_NONE,          0,0, 0,false,0,complain_overflow_dont,    0, "R_X86_64_NONE",   false,0x00000000,0x00000000,false),
39   HOWTO(R_X86_64_64,    0,4,64,false,0,complain_overflow_bitfield,0, "R_X86_64_64",     false,MINUS_ONE ,MINUS_ONE ,false),
40   HOWTO(R_X86_64_PC32,          0,4,32,true ,0,complain_overflow_signed  ,0, "R_X86_64_PC32",   false,0xffffffff,0xffffffff,true),
41   HOWTO(R_X86_64_GOT32,         0,4,32,false,0,complain_overflow_signed  ,0, "R_X86_64_GOT32",  false,0xffffffff,0xffffffff,false),
42   HOWTO(R_X86_64_PLT32,         0,4,32,true ,0,complain_overflow_signed  ,0, "R_X86_64_PLT32",  false,0xffffffff,0xffffffff,true),
43   HOWTO(R_X86_64_COPY,     0,4,32,false,0,complain_overflow_bitfield,0, "R_X86_64_COPY",   false,0xffffffff,0xffffffff,false),
44   HOWTO(R_X86_64_GLOB_DAT, 0,4,64,false,0,complain_overflow_bitfield,0,"R_X86_64_GLOB_DAT",false,MINUS_ONE ,MINUS_ONE ,false),
45   HOWTO(R_X86_64_RELATIVE ,0,4,64,false,0,complain_overflow_bitfield,0,"R_X86_64_RELATIVE",false,MINUS_ONE ,MINUS_ONE ,false),
46   HOWTO(R_X86_64_JUMP_SLOT,0,4,64,false,0,complain_overflow_bitfield,0,"R_X86_64_JUMP_SLOT",false,MINUS_ONE,MINUS_ONE ,false),
47   HOWTO(R_X86_64_GOTPCREL, 0,4,32,true, 0,complain_overflow_signed  ,0, "R_X86_64_PCREL",  false,0xffffffff,0xffffffff,true),
48   HOWTO(R_X86_64_32,    0,4,32,false,0,complain_overflow_unsigned,0, "R_X86_64_32",     false,0xffffffff,0xffffffff,false),
49   HOWTO(R_X86_64_32S,   0,4,32,false,0,complain_overflow_signed,  0, "R_X86_64_32S",    false,0xffffffff,0xffffffff,false),
50   HOWTO(R_X86_64_16,    0,1,16,false,0,complain_overflow_bitfield,0, "R_X86_64_16",     false,0xffff    ,0xffff,    false),
51   HOWTO(R_X86_64_PC16,          0,1,16,true ,0,complain_overflow_bitfield,0, "R_X86_64_PC16",   false,0xffff    ,0xffff,    true),
52   HOWTO(R_X86_64_8,     0,0, 8,false,0,complain_overflow_signed  ,0, "R_X86_64_8",      false,0xff      ,0xff,      false),
53   HOWTO(R_X86_64_PC8,   0,0, 8,true ,0,complain_overflow_signed  ,0, "R_X86_64_PC8",    false,0xff      ,0xff,      true),
54 };
55
56 /* Map BFD relocs to the x86_64 elf relocs.  */
57 struct elf_reloc_map {
58   bfd_reloc_code_real_type bfd_reloc_val;
59   unsigned char elf_reloc_val;
60 };
61
62 static CONST struct elf_reloc_map x86_64_reloc_map[] =
63 {
64   { BFD_RELOC_NONE,           R_X86_64_NONE, },
65   { BFD_RELOC_64,             R_X86_64_64,   },
66   { BFD_RELOC_32_PCREL,               R_X86_64_PC32, },
67   { BFD_RELOC_X86_64_GOT32,   R_X86_64_GOT32,},
68   { BFD_RELOC_X86_64_PLT32,   R_X86_64_PLT32,},
69   { BFD_RELOC_X86_64_COPY,    R_X86_64_COPY, },
70   { BFD_RELOC_X86_64_GLOB_DAT,        R_X86_64_GLOB_DAT, },
71   { BFD_RELOC_X86_64_JUMP_SLOT,       R_X86_64_JUMP_SLOT, },
72   { BFD_RELOC_X86_64_RELATIVE,        R_X86_64_RELATIVE, },
73   { BFD_RELOC_X86_64_GOTPCREL,        R_X86_64_GOTPCREL, },
74   { BFD_RELOC_32,             R_X86_64_32, },
75   { BFD_RELOC_X86_64_32S,     R_X86_64_32S, },
76   { BFD_RELOC_16,             R_X86_64_16, },
77   { BFD_RELOC_16_PCREL,               R_X86_64_PC16, },
78   { BFD_RELOC_8,              R_X86_64_8, },
79   { BFD_RELOC_8_PCREL,                R_X86_64_PC8, },
80 };
81
82 static reloc_howto_type *elf64_x86_64_reloc_type_lookup
83   PARAMS ((bfd *, bfd_reloc_code_real_type));
84 static void elf64_x86_64_info_to_howto
85   PARAMS ((bfd *, arelent *, Elf64_Internal_Rela *));
86 static struct bfd_link_hash_table *elf64_x86_64_link_hash_table_create
87   PARAMS ((bfd *));
88 static boolean elf64_x86_64_relocate_section
89   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
90          Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
91
92 /* Given a BFD reloc type, return a HOWTO structure.  */
93 static reloc_howto_type *
94 elf64_x86_64_reloc_type_lookup (abfd, code)
95      bfd *abfd ATTRIBUTE_UNUSED;
96      bfd_reloc_code_real_type code;
97 {
98   unsigned int i;
99   for (i = 0; i < sizeof (x86_64_reloc_map) / sizeof (struct elf_reloc_map);
100        i++)
101     {
102       if (x86_64_reloc_map[i].bfd_reloc_val == code)
103         return &x86_64_elf_howto_table[(int)
104                                        x86_64_reloc_map[i].elf_reloc_val];
105     }
106   return 0;
107 }
108
109 /* Given an x86_64 ELF reloc type, fill in an arelent structure.  */
110
111 static void
112 elf64_x86_64_info_to_howto (abfd, cache_ptr, dst)
113      bfd *abfd ATTRIBUTE_UNUSED;
114      arelent *cache_ptr;
115      Elf64_Internal_Rela *dst;
116 {
117   unsigned r_type;
118
119   r_type = ELF64_R_TYPE (dst->r_info);
120   BFD_ASSERT (r_type < (unsigned int) R_X86_64_max);
121   cache_ptr->howto = &x86_64_elf_howto_table[r_type];
122   BFD_ASSERT (r_type == cache_ptr->howto->type);
123 }
124
125 /* Hash table functions - these will be used by dynamic linking code and
126    right now they are needed to keep ld happy.  */
127
128 /* x86_64  ELF linker hash table.  */
129
130 struct elf64_x86_64_link_hash_table {
131   struct elf_link_hash_table root;
132 };
133
134 /* Get the X86-64 ELF linker hash table from a link_info structure.  */
135
136 #define elf64_x86_64_hash_table(p) \
137   ((struct elf64_x86_64_link_hash_table *) ((p)->hash))
138
139 /* Create an X86-64 ELF linker hash table.  */
140
141 static struct bfd_link_hash_table *
142 elf64_x86_64_link_hash_table_create (abfd)
143      bfd *abfd;
144 {
145   struct elf64_x86_64_link_hash_table *ret;
146
147   ret = ((struct elf64_x86_64_link_hash_table *)
148          bfd_alloc (abfd, sizeof (struct elf64_x86_64_link_hash_table)));
149   if (ret == (struct elf64_x86_64_link_hash_table *) NULL)
150     return NULL;
151
152   if (! _bfd_elf_link_hash_table_init (&ret->root, abfd,
153                                      _bfd_elf_link_hash_newfunc))
154     {
155       bfd_release (abfd, ret);
156       return NULL;
157     }
158
159   return &ret->root.root;
160 }
161
162 boolean
163 elf64_x86_64_elf_object_p (abfd)
164      bfd *abfd;
165 {
166   /* Set the right machine number for an x86-64 elf64 file.  */
167   bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_x86_64);
168   return true;
169 }
170
171 /* Relocate an x86_64 ELF section.  */
172
173 static boolean
174 elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section,
175                              contents, relocs, local_syms, local_sections)
176      bfd *output_bfd;
177      struct bfd_link_info *info;
178      bfd *input_bfd;
179      asection *input_section;
180      bfd_byte *contents;
181      Elf_Internal_Rela *relocs;
182      Elf_Internal_Sym *local_syms;
183      asection **local_sections;
184 {
185   bfd *dynobj;
186   Elf_Internal_Shdr *symtab_hdr;
187   struct elf_link_hash_entry **sym_hashes;
188   bfd_vma *local_got_offsets;
189   asection *sreloc;
190   Elf_Internal_Rela *rel;
191   Elf_Internal_Rela *relend;
192
193   dynobj = elf_hash_table (info)->dynobj;
194   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
195   sym_hashes = elf_sym_hashes (input_bfd);
196   local_got_offsets = elf_local_got_offsets (input_bfd);
197
198   sreloc = NULL;
199   if (dynobj != NULL)
200     abort ();
201
202   rel = relocs;
203   relend = relocs + input_section->reloc_count;
204   for (; rel < relend; rel++)
205     {
206       int r_type;
207       reloc_howto_type *howto;
208       unsigned long r_symndx;
209       struct elf_link_hash_entry *h;
210       Elf_Internal_Sym *sym;
211       asection *sec;
212       bfd_vma relocation;
213       bfd_reloc_status_type r;
214       unsigned int indx;
215
216       r_type = ELF64_R_TYPE (rel->r_info);
217
218       if ((indx = (unsigned) r_type) >= R_X86_64_max)
219         {
220           bfd_set_error (bfd_error_bad_value);
221           return false;
222         }
223       howto = x86_64_elf_howto_table + indx;
224
225       r_symndx = ELF64_R_SYM (rel->r_info);
226
227       if (info->relocateable)
228         {
229           /* This is a relocateable link.  We don't have to change
230              anything, unless the reloc is against a section symbol,
231              in which case we have to adjust according to where the
232              section symbol winds up in the output section.  */
233           if (r_symndx < symtab_hdr->sh_info)
234             {
235               sym = local_syms + r_symndx;
236               if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
237                 {
238                   sec = local_sections[r_symndx];
239                   rel->r_addend += sec->output_offset + sym->st_value;
240                 }
241             }
242
243           continue;
244         }
245
246       /* This is a final link.  */
247       h = NULL;
248       sym = NULL;
249       sec = NULL;
250       if (r_symndx < symtab_hdr->sh_info)
251         {
252           sym = local_syms + r_symndx;
253           sec = local_sections[r_symndx];
254           relocation = (sec->output_section->vma
255                         + sec->output_offset
256                         + sym->st_value);
257         }
258       else
259         {
260           h = sym_hashes[r_symndx - symtab_hdr->sh_info];
261           while (h->root.type == bfd_link_hash_indirect
262                  || h->root.type == bfd_link_hash_warning)
263             h = (struct elf_link_hash_entry *) h->root.u.i.link;
264           if (h->root.type == bfd_link_hash_defined
265               || h->root.type == bfd_link_hash_defweak)
266             {
267               sec = h->root.u.def.section;
268               if (sec->output_section == NULL)
269                 {
270                   (*_bfd_error_handler)
271                     (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"),
272                      bfd_get_filename (input_bfd), h->root.root.string,
273                      bfd_get_section_name (input_bfd, input_section));
274                   relocation = 0;
275                 }
276               else
277                 relocation = (h->root.u.def.value
278                               + sec->output_section->vma
279                               + sec->output_offset);
280             }
281           else if (h->root.type == bfd_link_hash_undefweak)
282             relocation = 0;
283           else
284             {
285               if (! ((*info->callbacks->undefined_symbol)
286                      (info, h->root.root.string, input_bfd,
287                       input_section, rel->r_offset,
288                       (!info->shared || info->no_undefined
289                        || ELF_ST_VISIBILITY (h->other)))))
290                 return false;
291               relocation = 0;
292             }
293         }
294       /* This function should support shared objects, but don't.  */
295       if (info->shared)
296         abort ();
297
298       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
299                                     contents, rel->r_offset,
300                                     relocation, rel->r_addend);
301
302       if (r != bfd_reloc_ok)
303         {
304           switch (r)
305             {
306             default:
307             case bfd_reloc_outofrange:
308               abort ();
309             case bfd_reloc_overflow:
310               {
311                 const char *name;
312
313                 if (h != NULL)
314                   name = h->root.root.string;
315                 else
316                   {
317                     name = bfd_elf_string_from_elf_section (input_bfd,
318                                                             symtab_hdr->sh_link,
319                                                             sym->st_name);
320                     if (name == NULL)
321                       return false;
322                     if (*name == '\0')
323                       name = bfd_section_name (input_bfd, sec);
324                   }
325                 if (! ((*info->callbacks->reloc_overflow)
326                        (info, name, howto->name, (bfd_vma) 0,
327                         input_bfd, input_section, rel->r_offset)))
328                   return false;
329               }
330               break;
331             }
332         }
333     }
334   return true;
335 }
336
337 #define TARGET_LITTLE_SYM             bfd_elf64_x86_64_vec
338 #define TARGET_LITTLE_NAME            "elf64-x86-64"
339 #define ELF_ARCH                      bfd_arch_i386
340 #define ELF_MACHINE_CODE              EM_X86_64
341 #define ELF_MAXPAGESIZE                       0x100000
342 #define elf_info_to_howto             elf64_x86_64_info_to_howto
343 #define bfd_elf64_bfd_reloc_type_lookup       elf64_x86_64_reloc_type_lookup
344 #define elf_backend_object_p            elf64_x86_64_elf_object_p
345 #define elf_backend_relocate_section  elf64_x86_64_relocate_section
346 #define bfd_elf64_bfd_link_hash_table_create elf64_x86_64_link_hash_table_create
347
348 #include "elf64-target.h"