Fix __bss_start assertion failure in _bfd_elf_fix_symbol_flags
[external/binutils.git] / bfd / elf64-bpf.c
1 /* Linux bpf specific support for 64-bit ELF
2    Copyright (C) 2019 Free Software Foundation, Inc.
3    Contributed by Oracle Inc.
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 3 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., 51 Franklin Street - Fifth Floor, Boston,
20    MA 02110-1301, USA.  */
21
22 #include "sysdep.h"
23 #include "bfd.h"
24 #include "libbfd.h"
25 #include "elf-bfd.h"
26 #include "elf/bpf.h"
27 #include "libiberty.h"
28
29 /* In case we're on a 32-bit machine, construct a 64-bit "-1" value.  */
30 #define MINUS_ONE (~ (bfd_vma) 0)
31
32 #define BASEADDR(SEC)   ((SEC)->output_section->vma + (SEC)->output_offset)
33
34 /* Handler for PC-relative relocations, which must be handled in
35    64-bit words.  */
36
37 static bfd_reloc_status_type
38 bpf_elf_insn_disp_reloc (bfd *abfd,
39                          arelent *reloc_entry,
40                          asymbol *symbol,
41                          void *data,
42                          asection *input_section,
43                          bfd *output_bfd,
44                          char **error_message ATTRIBUTE_UNUSED)
45 {
46   bfd_signed_vma relocation;
47   bfd_signed_vma addend;
48   reloc_howto_type *howto = reloc_entry->howto;
49
50   /* This part is from bfd_elf_generic_reloc.  */
51   if (output_bfd != NULL
52       && (symbol->flags & BSF_SECTION_SYM) == 0
53       && (! reloc_entry->howto->partial_inplace
54           || reloc_entry->addend == 0))
55     {
56       reloc_entry->address += input_section->output_offset;
57       return bfd_reloc_ok;
58     }
59
60   /* This works because partial_inplace is FALSE.  */
61   if (output_bfd != NULL)
62     return bfd_reloc_continue;
63
64   if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
65     return bfd_reloc_outofrange;
66
67   relocation = (symbol->value
68                 + symbol->section->output_section->vma
69                 + symbol->section->output_offset);
70   /* Make it PC relative.  */
71   relocation -= (input_section->output_section->vma
72                  + input_section->output_offset);
73   relocation -= reloc_entry->address;
74   /* Make it 64-bit words.  */
75   relocation = relocation / 8;
76
77   /* Get the addend from the instruction and apply it.  */
78   switch (howto->bitsize)
79     {
80     default:
81       abort ();
82       break;
83     case 16:
84       addend = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address + 2);
85       break;
86     case 32:
87       addend = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address + 4);
88       break;
89     }
90
91   if ((addend & (((~howto->src_mask) >> 1) & howto->src_mask)) != 0)
92     addend -= (((~howto->src_mask) >> 1) & howto->src_mask) << 1;
93   relocation += addend;
94
95   /* Write out the relocated value.  */
96   switch (howto->bitsize)
97     {
98     default:
99       abort ();
100       break;
101     case 16:
102       bfd_put_16 (abfd, relocation, (bfd_byte *) data + reloc_entry->address + 2);
103       break;
104     case 32:
105       bfd_put_32 (abfd, relocation, (bfd_byte *) data + reloc_entry->address + 4);
106       break;
107     }
108
109   /* Check for overflow.  */
110   if (howto->complain_on_overflow == complain_overflow_signed)
111     {
112       bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1;
113       bfd_signed_vma reloc_signed_min = ~reloc_signed_max;
114       
115       if (relocation > reloc_signed_max || relocation < reloc_signed_min)
116         return bfd_reloc_overflow;
117     }
118   else
119     abort();
120
121   return bfd_reloc_ok;
122 }
123
124 /* Relocation tables.  */
125 static reloc_howto_type bpf_elf_howto_table [] =
126 {
127   /* This reloc does nothing.  */
128   HOWTO (R_BPF_NONE,            /* type */
129          0,                     /* rightshift */
130          3,                     /* size (0 = byte, 1 = short, 2 = long) */
131          0,                     /* bitsize */
132          FALSE,                 /* pc_relative */
133          0,                     /* bitpos */
134          complain_overflow_dont, /* complain_on_overflow */
135          bfd_elf_generic_reloc, /* special_function */
136          "R_BPF_NONE",          /* name */
137          FALSE,                 /* partial_inplace */
138          0,                     /* src_mask */
139          0,                     /* dst_mask */
140          FALSE),                /* pcrel_offset */
141
142   /* 64-immediate in LDDW instruction.  */
143   HOWTO (R_BPF_INSN_64,         /* type */
144          0,                     /* rightshift */
145          4,                     /* size (0 = byte, 1 = short, 2 = long) */
146          64,                    /* bitsize */
147          FALSE,                 /* pc_relative */
148          0,                     /* bitpos */
149          complain_overflow_signed, /* complain_on_overflow */
150          bfd_elf_generic_reloc, /* special_function */
151          "R_BPF_INSN_64",       /* name */
152          FALSE,                 /* partial_inplace */
153          0,                     /* src_mask */
154          MINUS_ONE,             /* dst_mask */
155          TRUE),                 /* pcrel_offset */
156
157   /* 32-immediate in LDDW instruction.  */
158   HOWTO (R_BPF_INSN_32,         /* type */
159          0,                     /* rightshift */
160          2,                     /* size (0 = byte, 1 = short, 2 = long) */
161          32,                    /* bitsize */
162          FALSE,                 /* pc_relative */
163          0,                     /* bitpos */
164          complain_overflow_signed, /* complain_on_overflow */
165          bfd_elf_generic_reloc, /* special_function */
166          "R_BPF_INSN_32",       /* name */
167          FALSE,                 /* partial_inplace */
168          0,                     /* src_mask */
169          0xffffffff,            /* dst_mask */
170          TRUE),                 /* pcrel_offset */
171
172   /* 16-bit offsets in instructions.  */
173   HOWTO (R_BPF_INSN_16,         /* type */
174          0,                     /* rightshift */
175          1,                     /* size (0 = byte, 1 = short, 2 = long) */
176          16,                    /* bitsize */
177          FALSE,                 /* pc_relative */
178          0,                     /* bitpos */
179          complain_overflow_signed, /* complain_on_overflow */
180          bfd_elf_generic_reloc, /* special_function */
181          "R_BPF_INSN_16",       /* name */
182          FALSE,                 /* partial_inplace */
183          0,                     /* src_mask */
184          0x0000ffff,            /* dst_mask */
185          TRUE),                 /* pcrel_offset */
186
187   /* 16-bit PC-relative address in jump instructions.  */
188   HOWTO (R_BPF_INSN_DISP16,     /* type */
189          0,                     /* rightshift */
190          1,                     /* size (0 = byte, 1 = short, 2 = long) */
191          16,                    /* bitsize */
192          TRUE,                  /* pc_relative */
193          32,                    /* bitpos */
194          complain_overflow_signed, /* complain_on_overflow */
195          bpf_elf_insn_disp_reloc, /* special_function */
196          "R_BPF_INSN_DISP16",   /* name */
197          FALSE,                 /* partial_inplace */
198          0xffff,                /* src_mask */
199          0xffff,                /* dst_mask */
200          TRUE),                 /* pcrel_offset */
201
202   HOWTO (R_BPF_DATA_8_PCREL,
203          0,                     /* rightshift */
204          0,                     /* size (0 = byte, 1 = short, 2 = long) */
205          8,                     /* bitsize */
206          TRUE,                  /* pc_relative */
207          0,                     /* bitpos */
208          complain_overflow_signed, /* complain_on_overflow */
209          bfd_elf_generic_reloc, /* special_function */
210          "R_BPF_8_PCREL",       /* name */
211          FALSE,                 /* partial_inplace */
212          0,                     /* src_mask */
213          0xff,                  /* dst_mask */
214          TRUE),                 /* pcrel_offset */
215
216   HOWTO (R_BPF_DATA_16_PCREL,
217          0,                     /* rightshift */
218          1,                     /* size (0 = byte, 1 = short, 2 = long) */
219          16,                    /* bitsize */
220          TRUE,                  /* pc_relative */
221          0,                     /* bitpos */
222          complain_overflow_signed, /* complain_on_overflow */
223          bfd_elf_generic_reloc, /* special_function */
224          "R_BPF_16_PCREL",      /* name */
225          FALSE,                 /* partial_inplace */
226          0,                     /* src_mask */
227          0xffff,                /* dst_mask */
228          TRUE),                 /* pcrel_offset */
229
230   HOWTO (R_BPF_DATA_32_PCREL,
231          0,                     /* rightshift */
232          2,                     /* size (0 = byte, 1 = short, 2 = long) */
233          32,                    /* bitsize */
234          TRUE,                  /* pc_relative */
235          0,                     /* bitpos */
236          complain_overflow_signed, /* complain_on_overflow */
237          bfd_elf_generic_reloc, /* special_function */
238          "R_BPF_32_PCREL",      /* name */
239          FALSE,                 /* partial_inplace */
240          0,                     /* src_mask */
241          0xffffffff,            /* dst_mask */
242          TRUE),                 /* pcrel_offset */
243
244   HOWTO (R_BPF_DATA_8,
245          0,                     /* rightshift */
246          0,                     /* size (0 = byte, 1 = short, 2 = long) */
247          8,                     /* bitsize */
248          FALSE,                 /* pc_relative */
249          0,                     /* bitpos */
250          complain_overflow_unsigned, /* complain_on_overflow */
251          bfd_elf_generic_reloc, /* special_function */
252          "R_BPF_DATA_8",        /* name */
253          FALSE,                 /* partial_inplace */
254          0,                     /* src_mask */
255          0xff,                  /* dst_mask */
256          FALSE),                /* pcrel_offset */
257
258   HOWTO (R_BPF_DATA_16,
259          0,                     /* rightshift */
260          1,                     /* size (0 = byte, 1 = short, 2 = long) */
261          16,                    /* bitsize */
262          FALSE,                 /* pc_relative */
263          0,                     /* bitpos */
264          complain_overflow_unsigned, /* complain_on_overflow */
265          bfd_elf_generic_reloc, /* special_function */
266          "R_BPF_DATA_16",       /* name */
267          FALSE,                 /* partial_inplace */
268          0,                     /* src_mask */
269          0xffff,                /* dst_mask */
270          FALSE),                /* pcrel_offset */
271
272   /* 32-bit PC-relative address in call instructions.  */
273   HOWTO (R_BPF_INSN_DISP32,     /* type */
274          0,                     /* rightshift */
275          2,                     /* size (0 = byte, 1 = short, 2 = long) */
276          32,                    /* bitsize */
277          TRUE,                  /* pc_relative */
278          0,                     /* bitpos */
279          complain_overflow_signed, /* complain_on_overflow */
280          bpf_elf_insn_disp_reloc, /* special_function */
281          "R_BPF_INSN_DISP32",   /* name */
282          FALSE,                 /* partial_inplace */
283          0xffffffff,            /* src_mask */
284          0xffffffff,            /* dst_mask */
285          TRUE),                 /* pcrel_offset */
286
287   /* 32-bit data.  */
288   HOWTO (R_BPF_DATA_32,         /* type */
289          0,                     /* rightshift */
290          2,                     /* size (0 = byte, 1 = short, 2 = long) */
291          32,                    /* bitsize */
292          FALSE,                 /* pc_relative */
293          0,                     /* bitpos */
294          complain_overflow_bitfield, /* complain_on_overflow */
295          bfd_elf_generic_reloc, /* special_function */
296          "R_BPF_DATA_32",       /* name */
297          FALSE,                 /* partial_inplace */
298          0,                     /* src_mask */
299          0xffffffff,            /* dst_mask */
300          TRUE),                 /* pcrel_offset */
301
302   /* 64-bit data.  */
303   HOWTO (R_BPF_DATA_64,         /* type */
304          0,                     /* rightshift */
305          4,                     /* size (0 = byte, 1 = short, 2 = long) */
306          64,                    /* bitsize */
307          FALSE,                 /* pc_relative */
308          0,                     /* bitpos */
309          complain_overflow_bitfield, /* complain_on_overflow */
310          bfd_elf_generic_reloc, /* special_function */
311          "R_BPF_DATA_64",       /* name */
312          FALSE,                 /* partial_inplace */
313          0,                     /* src_mask */
314          MINUS_ONE,             /* dst_mask */
315          TRUE),                 /* pcrel_offset */
316
317   HOWTO (R_BPF_DATA_64_PCREL,
318          0,                     /* rightshift */
319          4,                     /* size (0 = byte, 1 = short, 2 = long) */
320          64,                    /* bitsize */
321          TRUE,                  /* pc_relative */
322          0,                     /* bitpos */
323          complain_overflow_signed, /* complain_on_overflow */
324          bfd_elf_generic_reloc, /* special_function */
325          "R_BPF_64_PCREL",      /* name */
326          FALSE,                 /* partial_inplace */
327          0,                     /* src_mask */
328          MINUS_ONE,             /* dst_mask */
329          TRUE),                 /* pcrel_offset */
330 };
331 #undef AHOW
332
333 /* Map BFD reloc types to bpf ELF reloc types.  */
334
335 static reloc_howto_type *
336 bpf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
337                         bfd_reloc_code_real_type code)
338 {
339   /* Note that the bpf_elf_howto_table is indxed by the R_
340      constants.  Thus, the order that the howto records appear in the
341      table *must* match the order of the relocation types defined in
342      include/elf/bpf.h.  */
343
344   switch (code)
345     {
346     case BFD_RELOC_NONE:
347       return &bpf_elf_howto_table[ (int) R_BPF_NONE];
348
349     case BFD_RELOC_8_PCREL:
350       return &bpf_elf_howto_table[ (int) R_BPF_DATA_8_PCREL];
351     case BFD_RELOC_16_PCREL:
352       return &bpf_elf_howto_table[ (int) R_BPF_DATA_16_PCREL];
353     case BFD_RELOC_32_PCREL:
354       return &bpf_elf_howto_table[ (int) R_BPF_DATA_32_PCREL];
355     case BFD_RELOC_64_PCREL:
356       return &bpf_elf_howto_table[ (int) R_BPF_DATA_64_PCREL];
357
358     case BFD_RELOC_8:
359       return &bpf_elf_howto_table[ (int) R_BPF_DATA_8];
360     case BFD_RELOC_16:
361       return &bpf_elf_howto_table[ (int) R_BPF_DATA_16];
362     case BFD_RELOC_32:
363       return &bpf_elf_howto_table[ (int) R_BPF_DATA_32];
364     case BFD_RELOC_64:
365       return &bpf_elf_howto_table[ (int) R_BPF_DATA_64];
366
367     case BFD_RELOC_BPF_64:
368       return &bpf_elf_howto_table[ (int) R_BPF_INSN_64];
369     case BFD_RELOC_BPF_32:
370       return &bpf_elf_howto_table[ (int) R_BPF_INSN_32];
371     case BFD_RELOC_BPF_16:
372       return &bpf_elf_howto_table[ (int) R_BPF_INSN_16];
373     case BFD_RELOC_BPF_DISP16:
374       return &bpf_elf_howto_table[ (int) R_BPF_INSN_DISP16];
375     case BFD_RELOC_BPF_DISP32:
376       return &bpf_elf_howto_table[ (int) R_BPF_INSN_DISP32];
377
378     default:
379       /* Pacify gcc -Wall.  */
380       return NULL;
381     }
382   return NULL;
383 }
384
385 /* Map BFD reloc names to bpf ELF reloc names.  */
386
387 static reloc_howto_type *
388 bpf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
389 {
390   unsigned int i;
391
392   for (i = 0; i < ARRAY_SIZE (bpf_elf_howto_table); i++)
393     if (bpf_elf_howto_table[i].name != NULL
394         && strcasecmp (bpf_elf_howto_table[i].name, r_name) == 0)
395       return &bpf_elf_howto_table[i];
396
397   return NULL;
398 }
399
400 /* Set the howto pointer for a bpf reloc.  */
401
402 static bfd_boolean
403 bpf_info_to_howto (bfd *abfd, arelent *bfd_reloc,
404                     Elf_Internal_Rela *elf_reloc)
405 {
406   unsigned int r_type;
407
408   r_type = ELF64_R_TYPE (elf_reloc->r_info);
409   if (r_type >= (unsigned int) R_BPF_max)
410     {
411       /* xgettext:c-format */
412       _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
413                           abfd, r_type);
414       bfd_set_error (bfd_error_bad_value);
415       return FALSE;
416     }
417
418   bfd_reloc->howto = &bpf_elf_howto_table [r_type];
419   return TRUE;
420 }
421
422 /* Merge backend specific data from an object file to the output
423    object file when linking.  */
424
425 static bfd_boolean
426 elf64_bpf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
427 {
428   /* Check if we have the same endianness.  */
429   if (! _bfd_generic_verify_endian_match (ibfd, info))
430     return FALSE;
431
432   return TRUE;
433 }
434
435 /* The macros below configure the architecture.  */
436
437 #define TARGET_LITTLE_SYM bpf_elf64_le_vec
438 #define TARGET_LITTLE_NAME "elf64-bpfle"
439
440 #define TARGET_BIG_SYM bpf_elf64_be_vec
441 #define TARGET_BIG_NAME "elf64-bpfbe"
442
443 #define ELF_ARCH bfd_arch_bpf
444 #define ELF_MACHINE_CODE EM_BPF
445
446 #define ELF_MAXPAGESIZE 0x100000
447
448 #define elf_info_to_howto_rel bpf_info_to_howto
449 #define elf_info_to_howto bpf_info_to_howto
450
451 #define elf_backend_may_use_rel_p               1
452 #define elf_backend_may_use_rela_p              0
453 #define elf_backend_default_use_rela_p          0
454
455 #define elf_backend_can_gc_sections             0
456
457 #define elf_symbol_leading_char                 '_'
458 #define bfd_elf64_bfd_reloc_type_lookup         bpf_reloc_type_lookup
459 #define bfd_elf64_bfd_reloc_name_lookup         bpf_reloc_name_lookup
460
461 #define bfd_elf64_bfd_merge_private_bfd_data elf64_bpf_merge_private_bfd_data
462
463 #include "elf64-target.h"