Commit | Line | Data |
---|---|---|
f8861f5d | 1 | /* tc-bpf.c -- Assembler for the Linux eBPF. |
250d07de | 2 | Copyright (C) 2019-2021 Free Software Foundation, Inc. |
f8861f5d JM |
3 | Contributed by Oracle, Inc. |
4 | ||
5 | This file is part of GAS, the GNU Assembler. | |
6 | ||
7 | GAS 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, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GAS 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 GAS; see the file COPYING. If not, write to | |
19 | the Free Software Foundation, 51 Franklin Street - Fifth Floor, | |
20 | Boston, MA 02110-1301, USA. */ | |
21 | ||
22 | #include "as.h" | |
23 | #include "subsegs.h" | |
24 | #include "symcat.h" | |
25 | #include "opcodes/bpf-desc.h" | |
26 | #include "opcodes/bpf-opc.h" | |
27 | #include "cgen.h" | |
28 | #include "elf/common.h" | |
29 | #include "elf/bpf.h" | |
30 | #include "dwarf2dbg.h" | |
31 | ||
32 | const char comment_chars[] = ";"; | |
33 | const char line_comment_chars[] = "#"; | |
34 | const char line_separator_chars[] = "`"; | |
35 | const char EXP_CHARS[] = "eE"; | |
36 | const char FLT_CHARS[] = "fFdD"; | |
37 | ||
1802aae8 JM |
38 | /* Like s_lcomm_internal in gas/read.c but the alignment string |
39 | is allowed to be optional. */ | |
40 | ||
41 | static symbolS * | |
42 | pe_lcomm_internal (int needs_align, symbolS *symbolP, addressT size) | |
43 | { | |
44 | addressT align = 0; | |
45 | ||
46 | SKIP_WHITESPACE (); | |
47 | ||
48 | if (needs_align | |
49 | && *input_line_pointer == ',') | |
50 | { | |
51 | align = parse_align (needs_align - 1); | |
52 | ||
53 | if (align == (addressT) -1) | |
54 | return NULL; | |
55 | } | |
56 | else | |
57 | { | |
58 | if (size >= 8) | |
59 | align = 3; | |
60 | else if (size >= 4) | |
61 | align = 2; | |
62 | else if (size >= 2) | |
63 | align = 1; | |
64 | else | |
65 | align = 0; | |
66 | } | |
67 | ||
68 | bss_alloc (symbolP, size, align); | |
69 | return symbolP; | |
70 | } | |
71 | ||
72 | static void | |
73 | pe_lcomm (int needs_align) | |
74 | { | |
75 | s_comm_internal (needs_align * 2, pe_lcomm_internal); | |
76 | } | |
77 | ||
f8861f5d JM |
78 | /* The target specific pseudo-ops which we support. */ |
79 | const pseudo_typeS md_pseudo_table[] = | |
80 | { | |
e0b989a6 JM |
81 | { "half", cons, 2 }, |
82 | { "word", cons, 4 }, | |
83 | { "dword", cons, 8 }, | |
1802aae8 | 84 | { "lcomm", pe_lcomm, 1 }, |
d0044bac | 85 | { NULL, NULL, 0 } |
f8861f5d JM |
86 | }; |
87 | ||
1802aae8 JM |
88 | \f |
89 | ||
f8861f5d JM |
90 | /* ISA handling. */ |
91 | static CGEN_BITSET *bpf_isa; | |
92 | ||
93 | \f | |
94 | ||
95 | /* Command-line options processing. */ | |
96 | ||
97 | enum options | |
98 | { | |
99 | OPTION_LITTLE_ENDIAN = OPTION_MD_BASE, | |
4449c81a DF |
100 | OPTION_BIG_ENDIAN, |
101 | OPTION_XBPF | |
f8861f5d JM |
102 | }; |
103 | ||
104 | struct option md_longopts[] = | |
105 | { | |
106 | { "EL", no_argument, NULL, OPTION_LITTLE_ENDIAN }, | |
107 | { "EB", no_argument, NULL, OPTION_BIG_ENDIAN }, | |
4449c81a | 108 | { "mxbpf", no_argument, NULL, OPTION_XBPF }, |
f8861f5d JM |
109 | { NULL, no_argument, NULL, 0 }, |
110 | }; | |
111 | ||
112 | size_t md_longopts_size = sizeof (md_longopts); | |
113 | ||
114 | const char * md_shortopts = ""; | |
115 | ||
116 | extern int target_big_endian; | |
117 | ||
118 | /* Whether target_big_endian has been set while parsing command-line | |
119 | arguments. */ | |
120 | static int set_target_endian = 0; | |
121 | ||
4449c81a DF |
122 | static int target_xbpf = 0; |
123 | ||
124 | static int set_xbpf = 0; | |
125 | ||
f8861f5d JM |
126 | int |
127 | md_parse_option (int c, const char * arg ATTRIBUTE_UNUSED) | |
128 | { | |
129 | switch (c) | |
130 | { | |
131 | case OPTION_BIG_ENDIAN: | |
132 | set_target_endian = 1; | |
133 | target_big_endian = 1; | |
134 | break; | |
135 | case OPTION_LITTLE_ENDIAN: | |
136 | set_target_endian = 1; | |
137 | target_big_endian = 0; | |
138 | break; | |
4449c81a DF |
139 | case OPTION_XBPF: |
140 | set_xbpf = 1; | |
141 | target_xbpf = 1; | |
142 | break; | |
f8861f5d JM |
143 | default: |
144 | return 0; | |
145 | } | |
146 | ||
147 | return 1; | |
148 | } | |
149 | ||
150 | void | |
151 | md_show_usage (FILE * stream) | |
152 | { | |
153 | fprintf (stream, _("\nBPF options:\n")); | |
154 | fprintf (stream, _("\ | |
155 | --EL generate code for a little endian machine\n\ | |
4449c81a DF |
156 | --EB generate code for a big endian machine\n\ |
157 | -mxbpf generate xBPF instructions\n")); | |
f8861f5d JM |
158 | } |
159 | ||
160 | \f | |
161 | void | |
162 | md_begin (void) | |
163 | { | |
164 | /* Initialize the `cgen' interface. */ | |
165 | ||
166 | /* If not specified in the command line, use the host | |
167 | endianness. */ | |
168 | if (!set_target_endian) | |
169 | { | |
170 | #ifdef WORDS_BIGENDIAN | |
171 | target_big_endian = 1; | |
172 | #else | |
173 | target_big_endian = 0; | |
174 | #endif | |
175 | } | |
176 | ||
4449c81a DF |
177 | /* If not specified in the command line, use eBPF rather |
178 | than xBPF. */ | |
179 | if (!set_xbpf) | |
180 | target_xbpf = 0; | |
181 | ||
f8861f5d JM |
182 | /* Set the ISA, which depends on the target endianness. */ |
183 | bpf_isa = cgen_bitset_create (ISA_MAX); | |
184 | if (target_big_endian) | |
4449c81a DF |
185 | { |
186 | if (target_xbpf) | |
187 | cgen_bitset_set (bpf_isa, ISA_XBPFBE); | |
188 | else | |
189 | cgen_bitset_set (bpf_isa, ISA_EBPFBE); | |
190 | } | |
f8861f5d | 191 | else |
4449c81a DF |
192 | { |
193 | if (target_xbpf) | |
194 | cgen_bitset_set (bpf_isa, ISA_XBPFLE); | |
195 | else | |
196 | cgen_bitset_set (bpf_isa, ISA_EBPFLE); | |
197 | } | |
f8861f5d JM |
198 | |
199 | /* Set the machine number and endian. */ | |
200 | gas_cgen_cpu_desc = bpf_cgen_cpu_open (CGEN_CPU_OPEN_ENDIAN, | |
201 | target_big_endian ? | |
202 | CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE, | |
d8740be1 JM |
203 | CGEN_CPU_OPEN_INSN_ENDIAN, |
204 | CGEN_ENDIAN_LITTLE, | |
f8861f5d JM |
205 | CGEN_CPU_OPEN_ISAS, |
206 | bpf_isa, | |
207 | CGEN_CPU_OPEN_END); | |
208 | bpf_cgen_init_asm (gas_cgen_cpu_desc); | |
209 | ||
210 | /* This is a callback from cgen to gas to parse operands. */ | |
211 | cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand); | |
212 | ||
213 | /* Set the machine type. */ | |
214 | bfd_default_set_arch_mach (stdoutput, bfd_arch_bpf, bfd_mach_bpf); | |
215 | } | |
216 | ||
217 | valueT | |
218 | md_section_align (segT segment, valueT size) | |
219 | { | |
fd361982 | 220 | int align = bfd_section_alignment (segment); |
f8861f5d JM |
221 | |
222 | return ((size + (1 << align) - 1) & -(1 << align)); | |
223 | } | |
224 | ||
225 | \f | |
226 | /* Functions concerning relocs. */ | |
227 | ||
228 | /* The location from which a PC relative jump should be calculated, | |
229 | given a PC relative reloc. */ | |
230 | ||
231 | long | |
232 | md_pcrel_from_section (fixS *fixP, segT sec) | |
233 | { | |
234 | if (fixP->fx_addsy != (symbolS *) NULL | |
235 | && (! S_IS_DEFINED (fixP->fx_addsy) | |
236 | || (S_GET_SEGMENT (fixP->fx_addsy) != sec) | |
237 | || S_IS_EXTERNAL (fixP->fx_addsy) | |
238 | || S_IS_WEAK (fixP->fx_addsy))) | |
239 | { | |
240 | /* The symbol is undefined (or is defined but not in this section). | |
241 | Let the linker figure it out. */ | |
242 | return 0; | |
243 | } | |
244 | ||
245 | return fixP->fx_where + fixP->fx_frag->fr_address; | |
246 | } | |
247 | ||
248 | /* Write a value out to the object file, using the appropriate endianness. */ | |
249 | ||
250 | void | |
251 | md_number_to_chars (char * buf, valueT val, int n) | |
252 | { | |
253 | if (target_big_endian) | |
254 | number_to_chars_bigendian (buf, val, n); | |
255 | else | |
256 | number_to_chars_littleendian (buf, val, n); | |
257 | } | |
258 | ||
259 | arelent * | |
260 | tc_gen_reloc (asection *sec, fixS *fix) | |
261 | { | |
262 | return gas_cgen_tc_gen_reloc (sec, fix); | |
263 | } | |
264 | ||
265 | /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP. This | |
266 | is called when the operand is an expression that couldn't be fully | |
267 | resolved. Returns BFD_RELOC_NONE if no reloc type can be found. | |
268 | *FIXP may be modified if desired. */ | |
269 | ||
270 | bfd_reloc_code_real_type | |
271 | md_cgen_lookup_reloc (const CGEN_INSN *insn ATTRIBUTE_UNUSED, | |
272 | const CGEN_OPERAND *operand, | |
273 | fixS *fixP) | |
274 | { | |
275 | switch (operand->type) | |
276 | { | |
277 | case BPF_OPERAND_OFFSET16: | |
278 | return BFD_RELOC_BPF_16; | |
279 | case BPF_OPERAND_IMM32: | |
280 | return BFD_RELOC_BPF_32; | |
281 | case BPF_OPERAND_IMM64: | |
282 | return BFD_RELOC_BPF_64; | |
283 | case BPF_OPERAND_DISP16: | |
284 | fixP->fx_pcrel = 1; | |
285 | return BFD_RELOC_BPF_DISP16; | |
286 | case BPF_OPERAND_DISP32: | |
287 | fixP->fx_pcrel = 1; | |
288 | return BFD_RELOC_BPF_DISP32; | |
289 | default: | |
290 | break; | |
291 | } | |
292 | return BFD_RELOC_NONE; | |
293 | } | |
294 | \f | |
295 | /* *FRAGP has been relaxed to its final size, and now needs to have | |
296 | the bytes inside it modified to conform to the new size. | |
297 | ||
298 | Called after relaxation is finished. | |
299 | fragP->fr_type == rs_machine_dependent. | |
300 | fragP->fr_subtype is the subtype of what the address relaxed to. */ | |
301 | ||
302 | void | |
303 | md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, | |
304 | segT sec ATTRIBUTE_UNUSED, | |
305 | fragS *fragP ATTRIBUTE_UNUSED) | |
306 | { | |
307 | as_fatal (_("convert_frag called")); | |
308 | } | |
309 | ||
310 | int | |
311 | md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED, | |
312 | segT segment ATTRIBUTE_UNUSED) | |
313 | { | |
314 | as_fatal (_("estimate_size_before_relax called")); | |
315 | return 0; | |
316 | } | |
317 | ||
318 | \f | |
319 | void | |
320 | md_apply_fix (fixS *fixP, valueT *valP, segT seg) | |
321 | { | |
322 | /* Some fixups for instructions require special attention. This is | |
323 | handled in the code block below. */ | |
324 | if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) | |
325 | { | |
326 | int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED; | |
327 | const CGEN_OPERAND *operand = cgen_operand_lookup_by_num (gas_cgen_cpu_desc, | |
328 | opindex); | |
329 | char *where; | |
330 | ||
331 | switch (operand->type) | |
332 | { | |
333 | case BPF_OPERAND_DISP32: | |
334 | /* eBPF supports two kind of CALL instructions: the so | |
335 | called pseudo calls ("bpf to bpf") and external calls | |
336 | ("bpf to kernel"). | |
337 | ||
338 | Both kind of calls use the same instruction (CALL). | |
339 | However, external calls are constructed by passing a | |
340 | constant argument to the instruction, whereas pseudo | |
341 | calls result from expressions involving symbols. In | |
342 | practice, instructions requiring a fixup are interpreted | |
343 | as pseudo-calls. If we are executing this code, this is | |
344 | a pseudo call. | |
345 | ||
346 | The kernel expects for pseudo-calls to be annotated by | |
347 | having BPF_PSEUDO_CALL in the SRC field of the | |
348 | instruction. But beware the infamous nibble-swapping of | |
349 | eBPF and take endianness into account here. | |
350 | ||
351 | Note that the CALL instruction has only one operand, so | |
352 | this code is executed only once per instruction. */ | |
f1919c56 JM |
353 | where = fixP->fx_frag->fr_literal + fixP->fx_where + 1; |
354 | where[0] = target_big_endian ? 0x01 : 0x10; | |
f8861f5d JM |
355 | /* Fallthrough. */ |
356 | case BPF_OPERAND_DISP16: | |
357 | /* The PC-relative displacement fields in jump instructions | |
358 | shouldn't be in bytes. Instead, they hold the number of | |
359 | 64-bit words to the target, _minus one_. */ | |
360 | *valP = (((long) (*valP)) - 8) / 8; | |
361 | break; | |
362 | default: | |
363 | break; | |
364 | } | |
365 | } | |
366 | ||
367 | /* And now invoke CGEN's handler, which will eventually install | |
368 | *valP into the corresponding operand. */ | |
369 | gas_cgen_md_apply_fix (fixP, valP, seg); | |
370 | } | |
371 | ||
372 | void | |
373 | md_assemble (char *str) | |
374 | { | |
375 | const CGEN_INSN *insn; | |
376 | char *errmsg; | |
377 | CGEN_FIELDS fields; | |
378 | ||
379 | #if CGEN_INT_INSN_P | |
380 | CGEN_INSN_INT buffer[CGEN_MAX_INSN_SIZE / sizeof (CGEN_INT_INSN_P)]; | |
381 | #else | |
382 | unsigned char buffer[CGEN_MAX_INSN_SIZE]; | |
f8861f5d JM |
383 | #endif |
384 | ||
385 | gas_cgen_init_parse (); | |
386 | insn = bpf_cgen_assemble_insn (gas_cgen_cpu_desc, str, &fields, | |
387 | buffer, &errmsg); | |
388 | ||
389 | if (insn == NULL) | |
390 | { | |
391 | as_bad ("%s", errmsg); | |
392 | return; | |
393 | } | |
394 | ||
395 | gas_cgen_finish_insn (insn, buffer, CGEN_FIELDS_BITSIZE (&fields), | |
396 | 0, /* zero to ban relaxable insns. */ | |
397 | NULL); /* NULL so results not returned here. */ | |
398 | } | |
399 | ||
400 | void | |
401 | md_operand (expressionS *expressionP) | |
402 | { | |
403 | gas_cgen_md_operand (expressionP); | |
404 | } | |
405 | ||
406 | ||
407 | symbolS * | |
408 | md_undefined_symbol (char *name ATTRIBUTE_UNUSED) | |
409 | { | |
410 | return NULL; | |
411 | } | |
412 | ||
413 | \f | |
414 | /* Turn a string in input_line_pointer into a floating point constant | |
415 | of type TYPE, and store the appropriate bytes in *LITP. The number | |
416 | of LITTLENUMS emitted is stored in *SIZEP. An error message is | |
417 | returned, or NULL on OK. */ | |
418 | ||
419 | const char * | |
420 | md_atof (int type, char *litP, int *sizeP) | |
421 | { | |
422 | return ieee_md_atof (type, litP, sizeP, FALSE); | |
423 | } |