tc-loongarch.c revision 1.1 1 1.1 christos /* tc-loongarch.c -- Assemble for the LoongArch ISA
2 1.1 christos
3 1.1 christos Copyright (C) 2021-2022 Free Software Foundation, Inc.
4 1.1 christos Contributed by Loongson Ltd.
5 1.1 christos
6 1.1 christos This file is part of GAS.
7 1.1 christos
8 1.1 christos GAS is free software; you can redistribute it and/or modify
9 1.1 christos it under the terms of the GNU General Public License as published by
10 1.1 christos the Free Software Foundation; either version 3 of the license, or
11 1.1 christos (at your option) any later version.
12 1.1 christos
13 1.1 christos GAS is distributed in the hope that it will be useful,
14 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
15 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 1.1 christos GNU General Public License for more details.
17 1.1 christos
18 1.1 christos You should have received a copy of the GNU General Public License
19 1.1 christos along with this program; see the file COPYING3. If not,
20 1.1 christos see <http://www.gnu.org/licenses/>. */
21 1.1 christos
22 1.1 christos #include "as.h"
23 1.1 christos #include "dw2gencfi.h"
24 1.1 christos #include "loongarch-lex.h"
25 1.1 christos #include "elf/loongarch.h"
26 1.1 christos #include "opcode/loongarch.h"
27 1.1 christos #include "obj-elf.h"
28 1.1 christos #include "bfd/elfxx-loongarch.h"
29 1.1 christos #include <stdlib.h>
30 1.1 christos #include <string.h>
31 1.1 christos #include <stdio.h>
32 1.1 christos #include <assert.h>
33 1.1 christos
34 1.1 christos /* All information about an instruction during assemble. */
35 1.1 christos struct loongarch_cl_insn
36 1.1 christos {
37 1.1 christos /* First split string. */
38 1.1 christos const char *name;
39 1.1 christos const char *arg_strs[MAX_ARG_NUM_PLUS_2];
40 1.1 christos size_t arg_num;
41 1.1 christos
42 1.1 christos /* Second analyze name_str and each actual args string to match the insn
43 1.1 christos in 'loongarch-opc.c'. And actual args may need be relocated.
44 1.1 christos We get length of insn. If 'insn_length == 0 && insn_mo->macro != NULL',
45 1.1 christos it's a macro insntruction and we call 'md_assemble' recursively
46 1.1 christos after expanding it. */
47 1.1 christos int match_now;
48 1.1 christos int all_match;
49 1.1 christos
50 1.1 christos const struct loongarch_opcode *insn;
51 1.1 christos size_t insn_length;
52 1.1 christos
53 1.1 christos offsetT args[MAX_ARG_NUM_PLUS_2];
54 1.1 christos struct reloc_info reloc_info[MAX_RELOC_NUMBER_A_INSN];
55 1.1 christos size_t reloc_num;
56 1.1 christos
57 1.1 christos /* For relax reserved. We not support relax now.
58 1.1 christos 'insn_length < relax_max_length' means need to relax.
59 1.1 christos And 'insn_length == relax_max_length' means no need to relax. */
60 1.1 christos size_t relax_max_length;
61 1.1 christos relax_substateT subtype;
62 1.1 christos
63 1.1 christos /* Then we get the binary representation of insn
64 1.1 christos and write it in to section. */
65 1.1 christos insn_t insn_bin;
66 1.1 christos
67 1.1 christos /* The frag that contains the instruction. */
68 1.1 christos struct frag *frag;
69 1.1 christos /* The offset into FRAG of the first instruction byte. */
70 1.1 christos long where;
71 1.1 christos /* The relocs associated with the instruction, if any. */
72 1.1 christos fixS *fixp[MAX_RELOC_NUMBER_A_INSN];
73 1.1 christos };
74 1.1 christos
75 1.1 christos #ifndef DEFAULT_ARCH
76 1.1 christos #define DEFAULT_ARCH "loongarch64"
77 1.1 christos #endif
78 1.1 christos
79 1.1 christos /* This array holds the chars that always start a comment. If the
80 1.1 christos pre-processor is disabled, these aren't very useful. */
81 1.1 christos const char comment_chars[] = "#";
82 1.1 christos
83 1.1 christos /* This array holds the chars that only start a comment at the beginning of
84 1.1 christos a line. If the line seems to have the form '# 123 filename'
85 1.1 christos .line and .file directives will appear in the pre-processed output. */
86 1.1 christos /* Note that input_file.c hand checks for '#' at the beginning of the
87 1.1 christos first line of the input file. This is because the compiler outputs
88 1.1 christos #NO_APP at the beginning of its output. */
89 1.1 christos /* Also note that C style comments are always supported. */
90 1.1 christos const char line_comment_chars[] = "#";
91 1.1 christos
92 1.1 christos /* This array holds machine specific line separator characters. */
93 1.1 christos const char line_separator_chars[] = ";";
94 1.1 christos
95 1.1 christos /* Chars that can be used to separate mant from exp in floating point nums. */
96 1.1 christos const char EXP_CHARS[] = "eE";
97 1.1 christos
98 1.1 christos /* Chars that mean this number is a floating point constant. */
99 1.1 christos /* As in 0f12.456. */
100 1.1 christos /* or 0d1.2345e12. */
101 1.1 christos const char FLT_CHARS[] = "rRsSfFdDxXpP";
102 1.1 christos
103 1.1 christos const char *md_shortopts = "O::g::G:";
104 1.1 christos
105 1.1 christos static const char default_arch[] = DEFAULT_ARCH;
106 1.1 christos
107 1.1 christos enum options
108 1.1 christos {
109 1.1 christos OPTION_IGNORE = OPTION_MD_BASE,
110 1.1 christos
111 1.1 christos OPTION_ABI,
112 1.1 christos OPTION_FLOAT_ABI,
113 1.1 christos
114 1.1 christos OPTION_FLOAT_ISA,
115 1.1 christos
116 1.1 christos OPTION_LA_LOCAL_WITH_ABS,
117 1.1 christos OPTION_LA_GLOBAL_WITH_PCREL,
118 1.1 christos OPTION_LA_GLOBAL_WITH_ABS,
119 1.1 christos
120 1.1 christos OPTION_END_OF_ENUM,
121 1.1 christos };
122 1.1 christos
123 1.1 christos struct option md_longopts[] =
124 1.1 christos {
125 1.1 christos { "mabi", required_argument, NULL, OPTION_ABI },
126 1.1 christos
127 1.1 christos { "mfpu", required_argument, NULL, OPTION_FLOAT_ISA },
128 1.1 christos
129 1.1 christos { "mla-local-with-abs", no_argument, NULL, OPTION_LA_LOCAL_WITH_ABS },
130 1.1 christos { "mla-global-with-pcrel", no_argument, NULL, OPTION_LA_GLOBAL_WITH_PCREL },
131 1.1 christos { "mla-global-with-abs", no_argument, NULL, OPTION_LA_GLOBAL_WITH_ABS },
132 1.1 christos
133 1.1 christos { NULL, no_argument, NULL, 0 }
134 1.1 christos };
135 1.1 christos
136 1.1 christos size_t md_longopts_size = sizeof (md_longopts);
137 1.1 christos
138 1.1 christos int
139 1.1 christos md_parse_option (int c, const char *arg)
140 1.1 christos {
141 1.1 christos int ret = 1;
142 1.1 christos char lp64[256] = "";
143 1.1 christos char ilp32[256] = "";
144 1.1 christos unsigned char *suf = (unsigned char *)arg;
145 1.1 christos
146 1.1 christos lp64['s'] = lp64['S'] = EF_LOONGARCH_ABI_LP64_SOFT_FLOAT;
147 1.1 christos lp64['f'] = lp64['F'] = EF_LOONGARCH_ABI_LP64_SINGLE_FLOAT;
148 1.1 christos lp64['d'] = lp64['D'] = EF_LOONGARCH_ABI_LP64_DOUBLE_FLOAT;
149 1.1 christos
150 1.1 christos ilp32['s'] = ilp32['S'] = EF_LOONGARCH_ABI_ILP32_SOFT_FLOAT;
151 1.1 christos ilp32['f'] = ilp32['F'] = EF_LOONGARCH_ABI_ILP32_SINGLE_FLOAT;
152 1.1 christos ilp32['d'] = ilp32['D'] = EF_LOONGARCH_ABI_ILP32_DOUBLE_FLOAT;
153 1.1 christos
154 1.1 christos switch (c)
155 1.1 christos {
156 1.1 christos case OPTION_ABI:
157 1.1 christos if (strncasecmp (arg, "lp64", 4) == 0 && lp64[suf[4]] != 0)
158 1.1 christos {
159 1.1 christos LARCH_opts.ase_ilp32 = 1;
160 1.1 christos LARCH_opts.ase_lp64 = 1;
161 1.1 christos LARCH_opts.ase_abi = lp64[suf[4]];
162 1.1 christos }
163 1.1 christos else if (strncasecmp (arg, "ilp32", 5) == 0 && ilp32[suf[5]] != 0)
164 1.1 christos {
165 1.1 christos LARCH_opts.ase_abi = ilp32[suf[5]];
166 1.1 christos LARCH_opts.ase_ilp32 = 1;
167 1.1 christos }
168 1.1 christos else
169 1.1 christos ret = 0;
170 1.1 christos break;
171 1.1 christos
172 1.1 christos case OPTION_FLOAT_ISA:
173 1.1 christos if (strcasecmp (arg, "soft") == 0)
174 1.1 christos LARCH_opts.ase_nf = 1;
175 1.1 christos else if (strcasecmp (arg, "single") == 0)
176 1.1 christos LARCH_opts.ase_sf = 1;
177 1.1 christos else if (strcasecmp (arg, "double") == 0)
178 1.1 christos {
179 1.1 christos LARCH_opts.ase_sf = 1;
180 1.1 christos LARCH_opts.ase_df = 1;
181 1.1 christos }
182 1.1 christos else
183 1.1 christos ret = 0;
184 1.1 christos break;
185 1.1 christos
186 1.1 christos case OPTION_LA_LOCAL_WITH_ABS:
187 1.1 christos LARCH_opts.ase_labs = 1;
188 1.1 christos break;
189 1.1 christos
190 1.1 christos case OPTION_LA_GLOBAL_WITH_PCREL:
191 1.1 christos LARCH_opts.ase_gpcr = 1;
192 1.1 christos break;
193 1.1 christos
194 1.1 christos case OPTION_LA_GLOBAL_WITH_ABS:
195 1.1 christos LARCH_opts.ase_gabs = 1;
196 1.1 christos break;
197 1.1 christos
198 1.1 christos case OPTION_IGNORE:
199 1.1 christos break;
200 1.1 christos
201 1.1 christos default:
202 1.1 christos ret = 0;
203 1.1 christos break;
204 1.1 christos }
205 1.1 christos return ret;
206 1.1 christos }
207 1.1 christos
208 1.1 christos static struct htab *r_htab = NULL;
209 1.1 christos static struct htab *f_htab = NULL;
210 1.1 christos static struct htab *c_htab = NULL;
211 1.1 christos static struct htab *cr_htab = NULL;
212 1.1 christos static struct htab *v_htab = NULL;
213 1.1 christos static struct htab *x_htab = NULL;
214 1.1 christos
215 1.1 christos void
216 1.1 christos loongarch_after_parse_args ()
217 1.1 christos {
218 1.1 christos /* Set default ABI/ISA LP64D. */
219 1.1 christos if (!EF_LOONGARCH_IS_LP64(LARCH_opts.ase_abi)
220 1.1 christos && !EF_LOONGARCH_IS_ILP32(LARCH_opts.ase_abi))
221 1.1 christos {
222 1.1 christos if (strcmp (default_arch, "loongarch64") == 0)
223 1.1 christos {
224 1.1 christos LARCH_opts.ase_abi = EF_LOONGARCH_ABI_LP64_DOUBLE_FLOAT;
225 1.1 christos LARCH_opts.ase_ilp32 = 1;
226 1.1 christos LARCH_opts.ase_lp64 = 1;
227 1.1 christos }
228 1.1 christos else if (strcmp (default_arch, "loongarch32") == 0)
229 1.1 christos {
230 1.1 christos LARCH_opts.ase_abi = EF_LOONGARCH_ABI_ILP32_DOUBLE_FLOAT;
231 1.1 christos LARCH_opts.ase_ilp32 = 1;
232 1.1 christos }
233 1.1 christos else
234 1.1 christos as_bad ("unknown default architecture `%s'", default_arch);
235 1.1 christos }
236 1.1 christos
237 1.1 christos /* Set default ISA double-float. */
238 1.1 christos if (!LARCH_opts.ase_nf
239 1.1 christos && !LARCH_opts.ase_sf
240 1.1 christos && !LARCH_opts.ase_df)
241 1.1 christos {
242 1.1 christos LARCH_opts.ase_sf = 1;
243 1.1 christos LARCH_opts.ase_df = 1;
244 1.1 christos }
245 1.1 christos
246 1.1 christos size_t i;
247 1.1 christos
248 1.1 christos assert(LARCH_opts.ase_ilp32);
249 1.1 christos
250 1.1 christos /* Init ilp32/lp64 registers names. */
251 1.1 christos if (!r_htab)
252 1.1 christos r_htab = str_htab_create (), str_hash_insert (r_htab, "", 0, 0);
253 1.1 christos
254 1.1 christos for (i = 0; i < ARRAY_SIZE (loongarch_r_normal_name); i++)
255 1.1 christos str_hash_insert (r_htab, loongarch_r_normal_name[i], (void *) (i + 1), 0);
256 1.1 christos
257 1.1 christos if (!cr_htab)
258 1.1 christos cr_htab = str_htab_create (), str_hash_insert (cr_htab, "", 0, 0);
259 1.1 christos
260 1.1 christos for (i = 0; i < ARRAY_SIZE (loongarch_cr_normal_name); i++)
261 1.1 christos str_hash_insert (cr_htab, loongarch_cr_normal_name[i], (void *) (i + 1), 0);
262 1.1 christos
263 1.1 christos /* Init single/double float registers names. */
264 1.1 christos if (LARCH_opts.ase_sf || LARCH_opts.ase_df)
265 1.1 christos {
266 1.1 christos if (!f_htab)
267 1.1 christos f_htab = str_htab_create (), str_hash_insert (f_htab, "", 0, 0);
268 1.1 christos
269 1.1 christos for (i = 0; i < ARRAY_SIZE (loongarch_f_normal_name); i++)
270 1.1 christos str_hash_insert (f_htab, loongarch_f_normal_name[i], (void *) (i + 1),
271 1.1 christos 0);
272 1.1 christos
273 1.1 christos if (!c_htab)
274 1.1 christos c_htab = str_htab_create (), str_hash_insert (c_htab, "", 0, 0);
275 1.1 christos
276 1.1 christos for (i = 0; i < ARRAY_SIZE (loongarch_c_normal_name); i++)
277 1.1 christos str_hash_insert (c_htab, loongarch_c_normal_name[i], (void *) (i + 1),
278 1.1 christos 0);
279 1.1 christos
280 1.1 christos }
281 1.1 christos
282 1.1 christos /* Init lsx registers names. */
283 1.1 christos if (LARCH_opts.ase_lsx)
284 1.1 christos {
285 1.1 christos if (!v_htab)
286 1.1 christos v_htab = str_htab_create (), str_hash_insert (v_htab, "", 0, 0);
287 1.1 christos for (i = 0; i < ARRAY_SIZE (loongarch_v_normal_name); i++)
288 1.1 christos str_hash_insert (v_htab, loongarch_v_normal_name[i], (void *) (i + 1),
289 1.1 christos 0);
290 1.1 christos }
291 1.1 christos
292 1.1 christos /* Init lasx registers names. */
293 1.1 christos if (LARCH_opts.ase_lasx)
294 1.1 christos {
295 1.1 christos if (!x_htab)
296 1.1 christos x_htab = str_htab_create (), str_hash_insert (x_htab, "", 0, 0);
297 1.1 christos for (i = 0; i < ARRAY_SIZE (loongarch_x_normal_name); i++)
298 1.1 christos str_hash_insert (x_htab, loongarch_x_normal_name[i], (void *) (i + 1),
299 1.1 christos 0);
300 1.1 christos }
301 1.1 christos
302 1.1 christos /* Init lp64 registers alias. */
303 1.1 christos if (LARCH_opts.ase_lp64)
304 1.1 christos {
305 1.1 christos for (i = 0; i < ARRAY_SIZE (loongarch_r_lp64_name); i++)
306 1.1 christos str_hash_insert (r_htab, loongarch_r_lp64_name[i], (void *) (i + 1),
307 1.1 christos 0);
308 1.1 christos for (i = 0; i < ARRAY_SIZE (loongarch_r_lp64_name1); i++)
309 1.1 christos str_hash_insert (r_htab, loongarch_r_lp64_name1[i], (void *) (i + 1),
310 1.1 christos 0);
311 1.1 christos }
312 1.1 christos
313 1.1 christos /* Init float-lp64 registers alias */
314 1.1 christos if ((LARCH_opts.ase_sf || LARCH_opts.ase_df) && LARCH_opts.ase_lp64)
315 1.1 christos {
316 1.1 christos for (i = 0; i < ARRAY_SIZE (loongarch_f_lp64_name); i++)
317 1.1 christos str_hash_insert (f_htab, loongarch_f_lp64_name[i],
318 1.1 christos (void *) (i + 1), 0);
319 1.1 christos for (i = 0; i < ARRAY_SIZE (loongarch_f_lp64_name1); i++)
320 1.1 christos str_hash_insert (f_htab, loongarch_f_lp64_name1[i],
321 1.1 christos (void *) (i + 1), 0);
322 1.1 christos }
323 1.1 christos }
324 1.1 christos
325 1.1 christos const char *
326 1.1 christos loongarch_target_format ()
327 1.1 christos {
328 1.1 christos return LARCH_opts.ase_lp64 ? "elf64-loongarch" : "elf32-loongarch";
329 1.1 christos }
330 1.1 christos
331 1.1 christos void
332 1.1 christos md_begin ()
333 1.1 christos {
334 1.1 christos const struct loongarch_opcode *it;
335 1.1 christos struct loongarch_ase *ase;
336 1.1 christos for (ase = loongarch_ASEs; ase->enabled; ase++)
337 1.1 christos for (it = ase->opcodes; it->name; it++)
338 1.1 christos {
339 1.1 christos if (loongarch_check_format (it->format) != 0)
340 1.1 christos as_fatal (_("insn name: %s\tformat: %s\tsyntax error"),
341 1.1 christos it->name, it->format);
342 1.1 christos if (it->mask == 0 && it->macro == 0)
343 1.1 christos as_fatal (_("insn name: %s\nformat: %s\nwe want macro but "
344 1.1 christos "macro is NULL"),
345 1.1 christos it->name, it->format);
346 1.1 christos if (it->macro
347 1.1 christos && loongarch_check_macro (it->format, it->macro) != 0)
348 1.1 christos as_fatal (_("insn name: %s\nformat: %s\nmacro: %s\tsyntax error"),
349 1.1 christos it->name, it->format, it->macro);
350 1.1 christos }
351 1.1 christos
352 1.1 christos /* FIXME: expressionS use 'offsetT' as constant,
353 1.1 christos * we want this is 64-bit type. */
354 1.1 christos assert (8 <= sizeof (offsetT));
355 1.1 christos }
356 1.1 christos
357 1.1 christos unsigned long
358 1.1 christos loongarch_mach (void)
359 1.1 christos {
360 1.1 christos return LARCH_opts.ase_lp64 ? bfd_mach_loongarch64 : bfd_mach_loongarch32;
361 1.1 christos }
362 1.1 christos
363 1.1 christos static const expressionS const_0 = { .X_op = O_constant, .X_add_number = 0 };
364 1.1 christos
365 1.1 christos static const char *
366 1.1 christos my_getExpression (expressionS *ep, const char *str)
367 1.1 christos {
368 1.1 christos char *save_in, *ret;
369 1.1 christos save_in = input_line_pointer;
370 1.1 christos input_line_pointer = (char *) str;
371 1.1 christos expression (ep);
372 1.1 christos ret = input_line_pointer;
373 1.1 christos input_line_pointer = save_in;
374 1.1 christos return ret;
375 1.1 christos }
376 1.1 christos
377 1.1 christos static void
378 1.1 christos s_loongarch_align (int arg)
379 1.1 christos {
380 1.1 christos const char *t = input_line_pointer;
381 1.1 christos while (!is_end_of_line[(unsigned char) *t] && *t != ',')
382 1.1 christos ++t;
383 1.1 christos if (*t == ',')
384 1.1 christos s_align_ptwo (arg);
385 1.1 christos else
386 1.1 christos s_align_ptwo (0);
387 1.1 christos }
388 1.1 christos
389 1.1 christos /* Handle the .dtprelword and .dtpreldword pseudo-ops. They generate
390 1.1 christos a 32-bit or 64-bit DTP-relative relocation (BYTES says which) for
391 1.1 christos use in DWARF debug information. */
392 1.1 christos
393 1.1 christos static void
394 1.1 christos s_dtprel (int bytes)
395 1.1 christos {
396 1.1 christos expressionS ex;
397 1.1 christos char *p;
398 1.1 christos
399 1.1 christos expression (&ex);
400 1.1 christos
401 1.1 christos if (ex.X_op != O_symbol)
402 1.1 christos {
403 1.1 christos as_bad (_("Unsupported use of %s"),
404 1.1 christos (bytes == 8 ? ".dtpreldword" : ".dtprelword"));
405 1.1 christos ignore_rest_of_line ();
406 1.1 christos }
407 1.1 christos
408 1.1 christos p = frag_more (bytes);
409 1.1 christos md_number_to_chars (p, 0, bytes);
410 1.1 christos fix_new_exp (frag_now, p - frag_now->fr_literal, bytes, &ex, FALSE,
411 1.1 christos (bytes == 8
412 1.1 christos ? BFD_RELOC_LARCH_TLS_DTPREL64
413 1.1 christos : BFD_RELOC_LARCH_TLS_DTPREL32));
414 1.1 christos
415 1.1 christos demand_empty_rest_of_line ();
416 1.1 christos }
417 1.1 christos
418 1.1 christos static const pseudo_typeS loongarch_pseudo_table[] =
419 1.1 christos {
420 1.1 christos { "align", s_loongarch_align, -4 },
421 1.1 christos { "dword", cons, 8 },
422 1.1 christos { "word", cons, 4 },
423 1.1 christos { "half", cons, 2 },
424 1.1 christos { "dtprelword", s_dtprel, 4 },
425 1.1 christos { "dtpreldword", s_dtprel, 8 },
426 1.1 christos { NULL, NULL, 0 },
427 1.1 christos };
428 1.1 christos
429 1.1 christos void
430 1.1 christos loongarch_pop_insert (void)
431 1.1 christos {
432 1.1 christos pop_insert (loongarch_pseudo_table);
433 1.1 christos }
434 1.1 christos
435 1.1 christos #define INTERNAL_LABEL_SPECIAL 10
436 1.1 christos static unsigned long internal_label_count[INTERNAL_LABEL_SPECIAL] = { 0 };
437 1.1 christos
438 1.1 christos static const char *
439 1.1 christos loongarch_internal_label_name (unsigned long label, int augend)
440 1.1 christos {
441 1.1 christos static char symbol_name_build[24];
442 1.1 christos unsigned long want_label;
443 1.1 christos char *p;
444 1.1 christos
445 1.1 christos want_label = internal_label_count[label] + augend;
446 1.1 christos
447 1.1 christos p = symbol_name_build;
448 1.1 christos #ifdef LOCAL_LABEL_PREFIX
449 1.1 christos *p++ = LOCAL_LABEL_PREFIX;
450 1.1 christos #endif
451 1.1 christos *p++ = 'L';
452 1.1 christos for (; label; label /= 10)
453 1.1 christos *p++ = label % 10 + '0';
454 1.1 christos /* Make sure internal label never belong to normal label namespace. */
455 1.1 christos *p++ = ':';
456 1.1 christos for (; want_label; want_label /= 10)
457 1.1 christos *p++ = want_label % 10 + '0';
458 1.1 christos *p++ = '\0';
459 1.1 christos return symbol_name_build;
460 1.1 christos }
461 1.1 christos
462 1.1 christos static void
463 1.1 christos setup_internal_label_here (unsigned long label)
464 1.1 christos {
465 1.1 christos assert (label < INTERNAL_LABEL_SPECIAL);
466 1.1 christos internal_label_count[label]++;
467 1.1 christos colon (loongarch_internal_label_name (label, 0));
468 1.1 christos }
469 1.1 christos
470 1.1 christos void
471 1.1 christos get_internal_label (expressionS *label_expr, unsigned long label,
472 1.1 christos int augend /* 0 for previous, 1 for next. */)
473 1.1 christos {
474 1.1 christos assert (label < INTERNAL_LABEL_SPECIAL);
475 1.1 christos if (augend == 0 && internal_label_count[label] == 0)
476 1.1 christos as_fatal (_("internal error: we have no internal label yet"));
477 1.1 christos label_expr->X_op = O_symbol;
478 1.1 christos label_expr->X_add_symbol =
479 1.1 christos symbol_find_or_make (loongarch_internal_label_name (label, augend));
480 1.1 christos label_expr->X_add_number = 0;
481 1.1 christos }
482 1.1 christos
483 1.1 christos extern int loongarch_parse_expr (const char *expr,
484 1.1 christos struct reloc_info *reloc_stack_top,
485 1.1 christos size_t max_reloc_num, size_t *reloc_num,
486 1.1 christos offsetT *imm_if_no_reloc);
487 1.1 christos
488 1.1 christos static int
489 1.1 christos is_internal_label (const char *c_str)
490 1.1 christos {
491 1.1 christos do
492 1.1 christos {
493 1.1 christos if (*c_str != ':')
494 1.1 christos break;
495 1.1 christos c_str++;
496 1.1 christos if (!('0' <= *c_str && *c_str <= '9'))
497 1.1 christos break;
498 1.1 christos while ('0' <= *c_str && *c_str <= '9')
499 1.1 christos c_str++;
500 1.1 christos if (*c_str != 'b' && *c_str != 'f')
501 1.1 christos break;
502 1.1 christos c_str++;
503 1.1 christos return *c_str == '\0';
504 1.1 christos }
505 1.1 christos while (0);
506 1.1 christos return 0;
507 1.1 christos }
508 1.1 christos
509 1.1 christos static int
510 1.1 christos is_label (const char *c_str)
511 1.1 christos {
512 1.1 christos if (is_internal_label (c_str))
513 1.1 christos return 1;
514 1.1 christos else if ('0' <= *c_str && *c_str <= '9')
515 1.1 christos {
516 1.1 christos /* [0-9]+[bf] */
517 1.1 christos while ('0' <= *c_str && *c_str <= '9')
518 1.1 christos c_str++;
519 1.1 christos return *c_str == 'b' || *c_str == 'f';
520 1.1 christos }
521 1.1 christos else if (is_name_beginner (*c_str))
522 1.1 christos {
523 1.1 christos /* [a-zA-Z\._\$][0-9a-zA-Z\._\$]* */
524 1.1 christos c_str++;
525 1.1 christos while (is_part_of_name (*c_str))
526 1.1 christos c_str++;
527 1.1 christos return *c_str == '\0';
528 1.1 christos }
529 1.1 christos else
530 1.1 christos return 0;
531 1.1 christos }
532 1.1 christos
533 1.1 christos static int
534 1.1 christos is_label_with_addend (const char *c_str)
535 1.1 christos {
536 1.1 christos if (is_internal_label (c_str))
537 1.1 christos return 1;
538 1.1 christos else if ('0' <= *c_str && *c_str <= '9')
539 1.1 christos {
540 1.1 christos /* [0-9]+[bf] */
541 1.1 christos while ('0' <= *c_str && *c_str <= '9')
542 1.1 christos c_str++;
543 1.1 christos if (*c_str == 'b' || *c_str == 'f')
544 1.1 christos c_str++;
545 1.1 christos else
546 1.1 christos return 0;
547 1.1 christos return *c_str == '\0'
548 1.1 christos || ((*c_str == '-' || *c_str == '+')
549 1.1 christos && is_unsigned (c_str + 1));
550 1.1 christos }
551 1.1 christos else if (is_name_beginner (*c_str))
552 1.1 christos {
553 1.1 christos /* [a-zA-Z\._\$][0-9a-zA-Z\._\$]* */
554 1.1 christos c_str++;
555 1.1 christos while (is_part_of_name (*c_str))
556 1.1 christos c_str++;
557 1.1 christos return *c_str == '\0'
558 1.1 christos || ((*c_str == '-' || *c_str == '+')
559 1.1 christos && is_unsigned (c_str + 1));
560 1.1 christos }
561 1.1 christos else
562 1.1 christos return 0;
563 1.1 christos }
564 1.1 christos
565 1.1 christos static int32_t
566 1.1 christos loongarch_args_parser_can_match_arg_helper (char esc_ch1, char esc_ch2,
567 1.1 christos const char *bit_field,
568 1.1 christos const char *arg, void *context)
569 1.1 christos {
570 1.1 christos struct loongarch_cl_insn *ip = context;
571 1.1 christos offsetT imm, ret = 0;
572 1.1 christos size_t reloc_num_we_have = MAX_RELOC_NUMBER_A_INSN - ip->reloc_num;
573 1.1 christos size_t reloc_num = 0;
574 1.1 christos
575 1.1 christos if (!ip->match_now)
576 1.1 christos return 0;
577 1.1 christos
578 1.1 christos switch (esc_ch1)
579 1.1 christos {
580 1.1 christos case 'l':
581 1.1 christos switch (esc_ch2)
582 1.1 christos {
583 1.1 christos default:
584 1.1 christos ip->match_now = is_label (arg);
585 1.1 christos if (!ip->match_now && is_label_with_addend (arg))
586 1.1 christos as_fatal (_("This label shouldn't be with addend."));
587 1.1 christos break;
588 1.1 christos case 'a':
589 1.1 christos ip->match_now = is_label_with_addend (arg);
590 1.1 christos break;
591 1.1 christos }
592 1.1 christos break;
593 1.1 christos case 's':
594 1.1 christos case 'u':
595 1.1 christos ip->match_now =
596 1.1 christos loongarch_parse_expr (arg, ip->reloc_info + ip->reloc_num,
597 1.1 christos reloc_num_we_have, &reloc_num, &imm) == 0;
598 1.1 christos
599 1.1 christos if (!ip->match_now)
600 1.1 christos break;
601 1.1 christos
602 1.1 christos if (esc_ch1 == 's')
603 1.1 christos switch (esc_ch2)
604 1.1 christos {
605 1.1 christos case 'c':
606 1.1 christos ip->match_now = reloc_num == 0;
607 1.1 christos break;
608 1.1 christos }
609 1.1 christos else
610 1.1 christos switch (esc_ch2)
611 1.1 christos {
612 1.1 christos case 'c':
613 1.1 christos ip->match_now = reloc_num == 0 && 0 <= imm;
614 1.1 christos break;
615 1.1 christos }
616 1.1 christos
617 1.1 christos if (!ip->match_now)
618 1.1 christos break;
619 1.1 christos
620 1.1 christos ret = imm;
621 1.1 christos if (reloc_num)
622 1.1 christos {
623 1.1 christos bfd_reloc_code_real_type reloc_type = BFD_RELOC_NONE;
624 1.1 christos reloc_num_we_have -= reloc_num;
625 1.1 christos if (reloc_num_we_have == 0)
626 1.1 christos as_fatal (_("expr too huge") /* Want one more reloc. */);
627 1.1 christos if (esc_ch1 == 'u')
628 1.1 christos {
629 1.1 christos if (strncmp (bit_field, "10:12", strlen ("10:12")) == 0)
630 1.1 christos reloc_type = BFD_RELOC_LARCH_SOP_POP_32_U_10_12;
631 1.1 christos }
632 1.1 christos else if (esc_ch1 == 's')
633 1.1 christos {
634 1.1 christos if (strncmp (bit_field, "10:16<<2", strlen ("10:16<<2")) == 0)
635 1.1 christos reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2;
636 1.1 christos else if (strncmp (bit_field, "0:5|10:16<<2",
637 1.1 christos strlen ("0:5|10:16<<2")) == 0)
638 1.1 christos reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_0_5_10_16_S2;
639 1.1 christos else if (strncmp (bit_field, "0:10|10:16<<2",
640 1.1 christos strlen ("0:10|10:16<<2")) == 0)
641 1.1 christos reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_0_10_10_16_S2;
642 1.1 christos else if (strncmp (bit_field, "10:12", strlen ("10:12")) == 0)
643 1.1 christos reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_10_12;
644 1.1 christos else if (strncmp (bit_field, "5:20", strlen ("5:20")) == 0)
645 1.1 christos reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_5_20;
646 1.1 christos else if (strncmp (bit_field, "10:16", strlen ("10:16")) == 0)
647 1.1 christos reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_10_16;
648 1.1 christos else if (strncmp (bit_field, "10:5", strlen ("10:5")) == 0)
649 1.1 christos reloc_type = BFD_RELOC_LARCH_SOP_POP_32_S_10_5;
650 1.1 christos }
651 1.1 christos if (reloc_type == BFD_RELOC_NONE)
652 1.1 christos as_fatal (
653 1.1 christos _("not support reloc bit-field\nfmt: %c%c %s\nargs: %s"),
654 1.1 christos esc_ch1, esc_ch2, bit_field, arg);
655 1.1 christos reloc_num++;
656 1.1 christos ip->reloc_num += reloc_num;
657 1.1 christos ip->reloc_info[ip->reloc_num - 1].type = reloc_type;
658 1.1 christos ip->reloc_info[ip->reloc_num - 1].value = const_0;
659 1.1 christos }
660 1.1 christos break;
661 1.1 christos case 'r':
662 1.1 christos imm = (intptr_t) str_hash_find (r_htab, arg);
663 1.1 christos ip->match_now = 0 < imm;
664 1.1 christos ret = imm - 1;
665 1.1 christos break;
666 1.1 christos case 'f':
667 1.1 christos imm = (intptr_t) str_hash_find (f_htab, arg);
668 1.1 christos ip->match_now = 0 < imm;
669 1.1 christos ret = imm - 1;
670 1.1 christos break;
671 1.1 christos case 'c':
672 1.1 christos switch (esc_ch2)
673 1.1 christos {
674 1.1 christos case 'r':
675 1.1 christos imm = (intptr_t) str_hash_find (cr_htab, arg);
676 1.1 christos break;
677 1.1 christos default:
678 1.1 christos imm = (intptr_t) str_hash_find (c_htab, arg);
679 1.1 christos }
680 1.1 christos ip->match_now = 0 < imm;
681 1.1 christos ret = imm - 1;
682 1.1 christos break;
683 1.1 christos case 'v':
684 1.1 christos imm = (intptr_t) str_hash_find (v_htab, arg);
685 1.1 christos ip->match_now = 0 < imm;
686 1.1 christos ret = imm - 1;
687 1.1 christos break;
688 1.1 christos case 'x':
689 1.1 christos imm = (intptr_t) str_hash_find (x_htab, arg);
690 1.1 christos ip->match_now = 0 < imm;
691 1.1 christos ret = imm - 1;
692 1.1 christos break;
693 1.1 christos case '\0':
694 1.1 christos ip->all_match = ip->match_now;
695 1.1 christos ip->insn_length =
696 1.1 christos ip->insn->mask ? loongarch_insn_length (ip->insn->match) : 0;
697 1.1 christos /* FIXME: now we have no relax insn. */
698 1.1 christos ip->relax_max_length = ip->insn_length;
699 1.1 christos break;
700 1.1 christos default:
701 1.1 christos as_fatal (_("unknown escape"));
702 1.1 christos }
703 1.1 christos
704 1.1 christos do
705 1.1 christos {
706 1.1 christos /* Check imm overflow. */
707 1.1 christos int bit_width, bits_needed_s, bits_needed_u;
708 1.1 christos char *t;
709 1.1 christos
710 1.1 christos if (!ip->match_now)
711 1.1 christos break;
712 1.1 christos
713 1.1 christos if (0 < reloc_num)
714 1.1 christos break;
715 1.1 christos
716 1.1 christos bit_width = loongarch_get_bit_field_width (bit_field, &t);
717 1.1 christos
718 1.1 christos if (bit_width == -1)
719 1.1 christos /* No specify bit width. */
720 1.1 christos break;
721 1.1 christos
722 1.1 christos imm = ret;
723 1.1 christos if (t[0] == '<' && t[1] == '<')
724 1.1 christos {
725 1.1 christos int i = strtol (t += 2, &t, 10), j;
726 1.1 christos for (j = i; 0 < j; j--, imm >>= 1)
727 1.1 christos if (imm & 1)
728 1.1 christos as_fatal (_("require imm low %d bit is 0."), i);
729 1.1 christos }
730 1.1 christos
731 1.1 christos if (*t == '+')
732 1.1 christos imm -= strtol (t, &t, 10);
733 1.1 christos
734 1.1 christos bits_needed_s = loongarch_bits_imm_needed (imm, 1);
735 1.1 christos bits_needed_u = loongarch_bits_imm_needed (imm, 0);
736 1.1 christos
737 1.1 christos if ((esc_ch1 == 's' && bit_width < bits_needed_s)
738 1.1 christos || (esc_ch1 != 's' && bit_width < bits_needed_u))
739 1.1 christos /* How to do after we detect overflow. */
740 1.1 christos as_fatal (_("Immediate overflow.\n"
741 1.1 christos "format: %c%c%s\n"
742 1.1 christos "arg: %s"),
743 1.1 christos esc_ch1, esc_ch2, bit_field, arg);
744 1.1 christos }
745 1.1 christos while (0);
746 1.1 christos
747 1.1 christos if (esc_ch1 != '\0')
748 1.1 christos {
749 1.1 christos ip->args[ip->arg_num] = ret;
750 1.1 christos ip->arg_num++;
751 1.1 christos }
752 1.1 christos return ret;
753 1.1 christos }
754 1.1 christos
755 1.1 christos static void
756 1.1 christos get_loongarch_opcode (struct loongarch_cl_insn *insn)
757 1.1 christos {
758 1.1 christos const struct loongarch_opcode *it;
759 1.1 christos struct loongarch_ase *ase;
760 1.1 christos for (ase = loongarch_ASEs; ase->enabled; ase++)
761 1.1 christos {
762 1.1 christos if (!*ase->enabled || (ase->include && !*ase->include)
763 1.1 christos || (ase->exclude && *ase->exclude))
764 1.1 christos continue;
765 1.1 christos
766 1.1 christos if (!ase->name_hash_entry)
767 1.1 christos {
768 1.1 christos ase->name_hash_entry = str_htab_create ();
769 1.1 christos for (it = ase->opcodes; it->name; it++)
770 1.1 christos str_hash_insert (ase->name_hash_entry, it->name, (void *) it, 0);
771 1.1 christos }
772 1.1 christos
773 1.1 christos if ((it = str_hash_find (ase->name_hash_entry, insn->name)) == NULL)
774 1.1 christos continue;
775 1.1 christos
776 1.1 christos do
777 1.1 christos {
778 1.1 christos insn->insn = it;
779 1.1 christos insn->match_now = 1;
780 1.1 christos insn->all_match = 0;
781 1.1 christos insn->arg_num = 0;
782 1.1 christos insn->reloc_num = 0;
783 1.1 christos insn->insn_bin = (loongarch_foreach_args
784 1.1 christos (it->format, insn->arg_strs,
785 1.1 christos loongarch_args_parser_can_match_arg_helper,
786 1.1 christos insn));
787 1.1 christos if (insn->all_match && !(it->include && !*it->include)
788 1.1 christos && !(it->exclude && *it->exclude))
789 1.1 christos {
790 1.1 christos insn->insn_bin |= it->match;
791 1.1 christos return;
792 1.1 christos }
793 1.1 christos it++;
794 1.1 christos }
795 1.1 christos while (it->name && strcasecmp (it->name, insn->name) == 0);
796 1.1 christos }
797 1.1 christos }
798 1.1 christos
799 1.1 christos static int
800 1.1 christos check_this_insn_before_appending (struct loongarch_cl_insn *ip)
801 1.1 christos {
802 1.1 christos int ret = 0;
803 1.1 christos if (strcmp (ip->name, "la.abs") == 0)
804 1.1 christos {
805 1.1 christos ip->reloc_info[ip->reloc_num].type = BFD_RELOC_LARCH_MARK_LA;
806 1.1 christos my_getExpression (&ip->reloc_info[ip->reloc_num].value, ip->arg_strs[1]);
807 1.1 christos ip->reloc_num++;
808 1.1 christos }
809 1.1 christos else if (ip->insn->mask == 0xffff8000
810 1.1 christos /* amswap.w rd, rk, rj */
811 1.1 christos && ((ip->insn_bin & 0xfff00000) == 0x38600000
812 1.1 christos /* ammax_db.wu rd, rk, rj */
813 1.1 christos || (ip->insn_bin & 0xffff0000) == 0x38700000
814 1.1 christos /* ammin_db.wu rd, rk, rj */
815 1.1 christos || (ip->insn_bin & 0xffff0000) == 0x38710000))
816 1.1 christos {
817 1.1 christos /* For AMO insn amswap.[wd], amadd.[wd], etc. */
818 1.1 christos if (ip->args[0] != 0
819 1.1 christos && (ip->args[0] == ip->args[1] || ip->args[0] == ip->args[2]))
820 1.1 christos as_fatal (_("AMO insns require rd != base && rd != rt"
821 1.1 christos " when rd isn't $r0"));
822 1.1 christos }
823 1.1 christos else if ((ip->insn->mask == 0xffe08000
824 1.1 christos /* bstrins.w rd, rj, msbw, lsbw */
825 1.1 christos && (ip->insn_bin & 0xffe00000) == 0x00600000)
826 1.1 christos || (ip->insn->mask == 0xffc00000
827 1.1 christos /* bstrins.d rd, rj, msbd, lsbd */
828 1.1 christos && (ip->insn_bin & 0xff800000) == 0x00800000))
829 1.1 christos {
830 1.1 christos /* For bstr(ins|pick).[wd]. */
831 1.1 christos if (ip->args[2] < ip->args[3])
832 1.1 christos as_fatal (_("bstr(ins|pick).[wd] require msbd >= lsbd"));
833 1.1 christos }
834 1.1 christos else if (ip->insn->mask != 0 && (ip->insn_bin & 0xfe0003c0) == 0x04000000
835 1.1 christos /* csrxchg rd, rj, csr_num */
836 1.1 christos && (strcmp ("csrxchg", ip->name) == 0))
837 1.1 christos as_fatal (_("csrxchg require rj != $r0 && rj != $r1"));
838 1.1 christos
839 1.1 christos return ret;
840 1.1 christos }
841 1.1 christos
842 1.1 christos static void
843 1.1 christos install_insn (const struct loongarch_cl_insn *insn)
844 1.1 christos {
845 1.1 christos char *f = insn->frag->fr_literal + insn->where;
846 1.1 christos if (0 < insn->insn_length)
847 1.1 christos md_number_to_chars (f, insn->insn_bin, insn->insn_length);
848 1.1 christos }
849 1.1 christos
850 1.1 christos static void
851 1.1 christos move_insn (struct loongarch_cl_insn *insn, fragS *frag, long where)
852 1.1 christos {
853 1.1 christos size_t i;
854 1.1 christos insn->frag = frag;
855 1.1 christos insn->where = where;
856 1.1 christos for (i = 0; i < insn->reloc_num; i++)
857 1.1 christos {
858 1.1 christos insn->fixp[i]->fx_frag = frag;
859 1.1 christos insn->fixp[i]->fx_where = where;
860 1.1 christos }
861 1.1 christos install_insn (insn);
862 1.1 christos }
863 1.1 christos
864 1.1 christos /* Add INSN to the end of the output. */
865 1.1 christos static void
866 1.1 christos append_fixed_insn (struct loongarch_cl_insn *insn)
867 1.1 christos {
868 1.1 christos char *f = frag_more (insn->insn_length);
869 1.1 christos move_insn (insn, frag_now, f - frag_now->fr_literal);
870 1.1 christos }
871 1.1 christos
872 1.1 christos static void
873 1.1 christos append_fixp_and_insn (struct loongarch_cl_insn *ip)
874 1.1 christos {
875 1.1 christos reloc_howto_type *howto;
876 1.1 christos bfd_reloc_code_real_type reloc_type;
877 1.1 christos struct reloc_info *reloc_info = ip->reloc_info;
878 1.1 christos size_t i;
879 1.1 christos
880 1.1 christos dwarf2_emit_insn (0);
881 1.1 christos
882 1.1 christos for (i = 0; i < ip->reloc_num; i++)
883 1.1 christos {
884 1.1 christos reloc_type = reloc_info[i].type;
885 1.1 christos howto = bfd_reloc_type_lookup (stdoutput, reloc_type);
886 1.1 christos if (howto == NULL)
887 1.1 christos as_fatal (_("no HOWTO loong relocation number %d"), reloc_type);
888 1.1 christos
889 1.1 christos ip->fixp[i] =
890 1.1 christos fix_new_exp (ip->frag, ip->where, bfd_get_reloc_size (howto),
891 1.1 christos &reloc_info[i].value, FALSE, reloc_type);
892 1.1 christos }
893 1.1 christos
894 1.1 christos if (ip->insn_length < ip->relax_max_length)
895 1.1 christos as_fatal (_("Internal error: not support relax now"));
896 1.1 christos else
897 1.1 christos append_fixed_insn (ip);
898 1.1 christos }
899 1.1 christos
900 1.1 christos /* Ask helper for returning a malloced c_str or NULL. */
901 1.1 christos static char *
902 1.1 christos assember_macro_helper (const char *const args[], void *context_ptr)
903 1.1 christos {
904 1.1 christos struct loongarch_cl_insn *insn = context_ptr;
905 1.1 christos char *ret = NULL;
906 1.1 christos if ( strcmp (insn->name, "li.w") == 0 || strcmp (insn->name, "li.d") == 0)
907 1.1 christos {
908 1.1 christos char args_buf[50], insns_buf[200];
909 1.1 christos const char *arg_strs[6];
910 1.1 christos uint32_t hi32, lo32;
911 1.1 christos
912 1.1 christos /* We pay attention to sign extend beacause it is chance of reduce insn.
913 1.1 christos The exception is 12-bit and hi-12-bit unsigned,
914 1.1 christos we need a 'ori' or a 'lu52i.d' accordingly. */
915 1.1 christos char all0_bit_vec, sign_bit_vec, allf_bit_vec, paritial_is_sext_of_prev;
916 1.1 christos
917 1.1 christos lo32 = insn->args[1] & 0xffffffff;
918 1.1 christos hi32 = insn->args[1] >> 32;
919 1.1 christos
920 1.1 christos if (strcmp (insn->name, "li.w") == 0)
921 1.1 christos {
922 1.1 christos if (hi32 != 0 && hi32 != 0xffffffff)
923 1.1 christos as_fatal (_("li overflow: hi32:0x%x lo32:0x%x"), hi32, lo32);
924 1.1 christos hi32 = lo32 & 0x80000000 ? 0xffffffff : 0;
925 1.1 christos }
926 1.1 christos
927 1.1 christos if (strcmp (insn->name, "li.d") == 0 && !LARCH_opts.ase_lp64)
928 1.1 christos as_fatal (_("we can't li.d on 32bit-arch"));
929 1.1 christos
930 1.1 christos snprintf (args_buf, sizeof (args_buf), "0x%x,0x%x,0x%x,0x%x,%s",
931 1.1 christos (hi32 >> 20) & 0xfff, hi32 & 0xfffff, (lo32 >> 12) & 0xfffff,
932 1.1 christos lo32 & 0xfff, args[0]);
933 1.1 christos loongarch_split_args_by_comma (args_buf, arg_strs);
934 1.1 christos
935 1.1 christos all0_bit_vec =
936 1.1 christos ((((hi32 & 0xfff00000) == 0) << 3) | (((hi32 & 0x000fffff) == 0) << 2)
937 1.1 christos | (((lo32 & 0xfffff000) == 0) << 1) | ((lo32 & 0x00000fff) == 0));
938 1.1 christos sign_bit_vec =
939 1.1 christos ((((hi32 & 0x80000000) != 0) << 3) | (((hi32 & 0x00080000) != 0) << 2)
940 1.1 christos | (((lo32 & 0x80000000) != 0) << 1) | ((lo32 & 0x00000800) != 0));
941 1.1 christos allf_bit_vec =
942 1.1 christos ((((hi32 & 0xfff00000) == 0xfff00000) << 3)
943 1.1 christos | (((hi32 & 0x000fffff) == 0x000fffff) << 2)
944 1.1 christos | (((lo32 & 0xfffff000) == 0xfffff000) << 1)
945 1.1 christos | ((lo32 & 0x00000fff) == 0x00000fff));
946 1.1 christos paritial_is_sext_of_prev =
947 1.1 christos (all0_bit_vec ^ allf_bit_vec) & (all0_bit_vec ^ (sign_bit_vec << 1));
948 1.1 christos
949 1.1 christos static const char *const li_32bit[] =
950 1.1 christos {
951 1.1 christos "lu12i.w %5,%3&0x80000?%3-0x100000:%3;ori %5,%5,%4;",
952 1.1 christos "lu12i.w %5,%3&0x80000?%3-0x100000:%3;",
953 1.1 christos "addi.w %5,$r0,%4&0x800?%4-0x1000:%4;",
954 1.1 christos "or %5,$r0,$r0;",
955 1.1 christos };
956 1.1 christos static const char *const li_hi_32bit[] =
957 1.1 christos {
958 1.1 christos "lu32i.d %5,%2&0x80000?%2-0x100000:%2;"
959 1.1 christos "lu52i.d %5,%5,%1&0x800?%1-0x1000:%1;",
960 1.1 christos "lu52i.d %5,%5,%1&0x800?%1-0x1000:%1;",
961 1.1 christos "lu32i.d %5,%2&0x80000?%2-0x100000:%2;",
962 1.1 christos "",
963 1.1 christos };
964 1.1 christos do
965 1.1 christos {
966 1.1 christos insns_buf[0] = '\0';
967 1.1 christos if (paritial_is_sext_of_prev == 0x7)
968 1.1 christos {
969 1.1 christos strcat (insns_buf, "lu52i.d %5,$r0,%1&0x800?%1-0x1000:%1;");
970 1.1 christos break;
971 1.1 christos }
972 1.1 christos if ((all0_bit_vec & 0x3) == 0x2)
973 1.1 christos strcat (insns_buf, "ori %5,$r0,%4;");
974 1.1 christos else
975 1.1 christos strcat (insns_buf, li_32bit[paritial_is_sext_of_prev & 0x3]);
976 1.1 christos strcat (insns_buf, li_hi_32bit[paritial_is_sext_of_prev >> 2]);
977 1.1 christos }
978 1.1 christos while (0);
979 1.1 christos
980 1.1 christos ret = loongarch_expand_macro (insns_buf, arg_strs, NULL, NULL,
981 1.1 christos sizeof (args_buf));
982 1.1 christos }
983 1.1 christos return ret;
984 1.1 christos }
985 1.1 christos
986 1.1 christos /* Accept instructions separated by ';'
987 1.1 christos * assuming 'not starting with space and not ending with space' or pass in
988 1.1 christos * empty c_str. */
989 1.1 christos static void
990 1.1 christos loongarch_assemble_INSNs (char *str)
991 1.1 christos {
992 1.1 christos char *rest;
993 1.1 christos size_t len_str = strlen(str);
994 1.1 christos
995 1.1 christos for (rest = str; *rest != ';' && *rest != '\0'; rest++);
996 1.1 christos if (*rest == ';')
997 1.1 christos *rest++ = '\0';
998 1.1 christos
999 1.1 christos if (*str == ':')
1000 1.1 christos {
1001 1.1 christos str++;
1002 1.1 christos setup_internal_label_here (strtol (str, &str, 10));
1003 1.1 christos str++;
1004 1.1 christos }
1005 1.1 christos
1006 1.1 christos do
1007 1.1 christos {
1008 1.1 christos if (*str == '\0')
1009 1.1 christos break;
1010 1.1 christos
1011 1.1 christos struct loongarch_cl_insn the_one = { 0 };
1012 1.1 christos the_one.name = str;
1013 1.1 christos
1014 1.1 christos for (; *str && *str != ' '; str++)
1015 1.1 christos ;
1016 1.1 christos if (*str == ' ')
1017 1.1 christos *str++ = '\0';
1018 1.1 christos
1019 1.1 christos loongarch_split_args_by_comma (str, the_one.arg_strs);
1020 1.1 christos get_loongarch_opcode (&the_one);
1021 1.1 christos
1022 1.1 christos if (!the_one.all_match)
1023 1.1 christos {
1024 1.1 christos char *ss = loongarch_cat_splited_strs (the_one.arg_strs);
1025 1.1 christos as_bad (_("no match insn: %s\t%s"), the_one.name, ss ? ss : "");
1026 1.1 christos free(ss);
1027 1.1 christos return;
1028 1.1 christos }
1029 1.1 christos
1030 1.1 christos if (check_this_insn_before_appending (&the_one) != 0)
1031 1.1 christos break;
1032 1.1 christos
1033 1.1 christos append_fixp_and_insn (&the_one);
1034 1.1 christos if (the_one.insn_length == 0 && the_one.insn->macro)
1035 1.1 christos {
1036 1.1 christos char *c_str = loongarch_expand_macro (the_one.insn->macro,
1037 1.1 christos the_one.arg_strs,
1038 1.1 christos assember_macro_helper,
1039 1.1 christos &the_one, len_str);
1040 1.1 christos loongarch_assemble_INSNs (c_str);
1041 1.1 christos free (c_str);
1042 1.1 christos }
1043 1.1 christos }
1044 1.1 christos while (0);
1045 1.1 christos
1046 1.1 christos if (*rest != '\0')
1047 1.1 christos loongarch_assemble_INSNs (rest);
1048 1.1 christos }
1049 1.1 christos
1050 1.1 christos void
1051 1.1 christos md_assemble (char *str)
1052 1.1 christos {
1053 1.1 christos loongarch_assemble_INSNs (str);
1054 1.1 christos }
1055 1.1 christos
1056 1.1 christos const char *
1057 1.1 christos md_atof (int type, char *litP, int *sizeP)
1058 1.1 christos {
1059 1.1 christos return ieee_md_atof (type, litP, sizeP, FALSE);
1060 1.1 christos }
1061 1.1 christos
1062 1.1 christos void
1063 1.1 christos md_number_to_chars (char *buf, valueT val, int n)
1064 1.1 christos {
1065 1.1 christos number_to_chars_littleendian (buf, val, n);
1066 1.1 christos }
1067 1.1 christos
1068 1.1 christos /* The location from which a PC relative jump should be calculated,
1069 1.1 christos given a PC relative reloc. */
1070 1.1 christos long
1071 1.1 christos md_pcrel_from (fixS *fixP ATTRIBUTE_UNUSED)
1072 1.1 christos {
1073 1.1 christos return 0;
1074 1.1 christos }
1075 1.1 christos
1076 1.1 christos static void fix_reloc_insn (fixS *fixP, bfd_vma reloc_val, char *buf)
1077 1.1 christos {
1078 1.1 christos reloc_howto_type *howto;
1079 1.1 christos insn_t insn;
1080 1.1 christos howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
1081 1.1 christos
1082 1.1 christos insn = bfd_getl32 (buf);
1083 1.1 christos
1084 1.1 christos if (!loongarch_adjust_reloc_bitsfield(howto, &reloc_val))
1085 1.1 christos as_warn_where (fixP->fx_file, fixP->fx_line, "Reloc overflow");
1086 1.1 christos
1087 1.1 christos insn = (insn & (insn_t)howto->src_mask)
1088 1.1 christos | ((insn & (~(insn_t)howto->dst_mask)) | reloc_val);
1089 1.1 christos
1090 1.1 christos bfd_putl32 (insn, buf);
1091 1.1 christos }
1092 1.1 christos
1093 1.1 christos void
1094 1.1 christos md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
1095 1.1 christos {
1096 1.1 christos static int64_t stack_top;
1097 1.1 christos static int last_reloc_is_sop_push_pcrel_1 = 0;
1098 1.1 christos int last_reloc_is_sop_push_pcrel = last_reloc_is_sop_push_pcrel_1;
1099 1.1 christos last_reloc_is_sop_push_pcrel_1 = 0;
1100 1.1 christos
1101 1.1 christos char *buf = fixP->fx_frag->fr_literal + fixP->fx_where;
1102 1.1 christos switch (fixP->fx_r_type)
1103 1.1 christos {
1104 1.1 christos case BFD_RELOC_LARCH_SOP_PUSH_TLS_TPREL:
1105 1.1 christos case BFD_RELOC_LARCH_SOP_PUSH_TLS_GD:
1106 1.1 christos case BFD_RELOC_LARCH_SOP_PUSH_TLS_GOT:
1107 1.1 christos case BFD_RELOC_LARCH_SOP_PUSH_PCREL:
1108 1.1 christos case BFD_RELOC_LARCH_SOP_PUSH_PLT_PCREL:
1109 1.1 christos if (fixP->fx_addsy == NULL)
1110 1.1 christos as_bad_where (fixP->fx_file, fixP->fx_line,
1111 1.1 christos _("Relocation against a constant"));
1112 1.1 christos
1113 1.1 christos if (fixP->fx_r_type == BFD_RELOC_LARCH_SOP_PUSH_TLS_TPREL
1114 1.1 christos || fixP->fx_r_type == BFD_RELOC_LARCH_SOP_PUSH_TLS_GD
1115 1.1 christos || fixP->fx_r_type == BFD_RELOC_LARCH_SOP_PUSH_TLS_GOT)
1116 1.1 christos S_SET_THREAD_LOCAL (fixP->fx_addsy);
1117 1.1 christos
1118 1.1 christos if (fixP->fx_r_type == BFD_RELOC_LARCH_SOP_PUSH_PCREL)
1119 1.1 christos {
1120 1.1 christos last_reloc_is_sop_push_pcrel_1 = 1;
1121 1.1 christos if (S_GET_SEGMENT (fixP->fx_addsy) == seg)
1122 1.1 christos stack_top = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
1123 1.1 christos - (fixP->fx_where + fixP->fx_frag->fr_address));
1124 1.1 christos else
1125 1.1 christos stack_top = 0;
1126 1.1 christos }
1127 1.1 christos break;
1128 1.1 christos
1129 1.1 christos case BFD_RELOC_LARCH_SOP_POP_32_S_10_5:
1130 1.1 christos case BFD_RELOC_LARCH_SOP_POP_32_S_10_12:
1131 1.1 christos case BFD_RELOC_LARCH_SOP_POP_32_U_10_12:
1132 1.1 christos case BFD_RELOC_LARCH_SOP_POP_32_S_10_16:
1133 1.1 christos case BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2:
1134 1.1 christos case BFD_RELOC_LARCH_SOP_POP_32_S_5_20:
1135 1.1 christos case BFD_RELOC_LARCH_SOP_POP_32_U:
1136 1.1 christos case BFD_RELOC_LARCH_SOP_POP_32_S_0_5_10_16_S2:
1137 1.1 christos case BFD_RELOC_LARCH_SOP_POP_32_S_0_10_10_16_S2:
1138 1.1 christos if (!last_reloc_is_sop_push_pcrel)
1139 1.1 christos break;
1140 1.1 christos
1141 1.1 christos fix_reloc_insn (fixP, (bfd_vma)stack_top, buf);
1142 1.1 christos break;
1143 1.1 christos
1144 1.1 christos case BFD_RELOC_64:
1145 1.1 christos case BFD_RELOC_32:
1146 1.1 christos if (fixP->fx_subsy)
1147 1.1 christos {
1148 1.1 christos case BFD_RELOC_24:
1149 1.1 christos case BFD_RELOC_16:
1150 1.1 christos case BFD_RELOC_8:
1151 1.1 christos fixP->fx_next = xmemdup (fixP, sizeof (*fixP), sizeof (*fixP));
1152 1.1 christos fixP->fx_next->fx_addsy = fixP->fx_subsy;
1153 1.1 christos fixP->fx_next->fx_subsy = NULL;
1154 1.1 christos fixP->fx_next->fx_offset = 0;
1155 1.1 christos fixP->fx_subsy = NULL;
1156 1.1 christos
1157 1.1 christos switch (fixP->fx_r_type)
1158 1.1 christos {
1159 1.1 christos case BFD_RELOC_64:
1160 1.1 christos fixP->fx_r_type = BFD_RELOC_LARCH_ADD64;
1161 1.1 christos fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB64;
1162 1.1 christos break;
1163 1.1 christos case BFD_RELOC_32:
1164 1.1 christos fixP->fx_r_type = BFD_RELOC_LARCH_ADD32;
1165 1.1 christos fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB32;
1166 1.1 christos break;
1167 1.1 christos case BFD_RELOC_24:
1168 1.1 christos fixP->fx_r_type = BFD_RELOC_LARCH_ADD24;
1169 1.1 christos fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB24;
1170 1.1 christos break;
1171 1.1 christos case BFD_RELOC_16:
1172 1.1 christos fixP->fx_r_type = BFD_RELOC_LARCH_ADD16;
1173 1.1 christos fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB16;
1174 1.1 christos break;
1175 1.1 christos case BFD_RELOC_8:
1176 1.1 christos fixP->fx_r_type = BFD_RELOC_LARCH_ADD8;
1177 1.1 christos fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB8;
1178 1.1 christos break;
1179 1.1 christos default:
1180 1.1 christos break;
1181 1.1 christos }
1182 1.1 christos md_number_to_chars (buf, 0, fixP->fx_size);
1183 1.1 christos if (fixP->fx_next->fx_addsy == NULL)
1184 1.1 christos fixP->fx_next->fx_done = 1;
1185 1.1 christos }
1186 1.1 christos if (fixP->fx_addsy == NULL)
1187 1.1 christos {
1188 1.1 christos fixP->fx_done = 1;
1189 1.1 christos md_number_to_chars (buf, *valP, fixP->fx_size);
1190 1.1 christos }
1191 1.1 christos break;
1192 1.1 christos
1193 1.1 christos default:
1194 1.1 christos break;
1195 1.1 christos }
1196 1.1 christos }
1197 1.1 christos
1198 1.1 christos int
1199 1.1 christos loongarch_relax_frag (asection *sec ATTRIBUTE_UNUSED,
1200 1.1 christos fragS *fragp ATTRIBUTE_UNUSED,
1201 1.1 christos long stretch ATTRIBUTE_UNUSED)
1202 1.1 christos {
1203 1.1 christos return 0;
1204 1.1 christos }
1205 1.1 christos
1206 1.1 christos int
1207 1.1 christos md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED,
1208 1.1 christos asection *segtype ATTRIBUTE_UNUSED)
1209 1.1 christos {
1210 1.1 christos return 0;
1211 1.1 christos }
1212 1.1 christos
1213 1.1 christos /* Translate internal representation of relocation info to BFD target
1214 1.1 christos format. */
1215 1.1 christos arelent *
1216 1.1 christos tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
1217 1.1 christos {
1218 1.1 christos arelent *reloc = (arelent *) xmalloc (sizeof (arelent));
1219 1.1 christos
1220 1.1 christos reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
1221 1.1 christos *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
1222 1.1 christos reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
1223 1.1 christos reloc->addend = fixp->fx_offset;
1224 1.1 christos
1225 1.1 christos reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
1226 1.1 christos if (reloc->howto == NULL)
1227 1.1 christos {
1228 1.1 christos as_bad_where (fixp->fx_file, fixp->fx_line,
1229 1.1 christos _("cannot represent %s relocation in object file"),
1230 1.1 christos bfd_get_reloc_code_name (fixp->fx_r_type));
1231 1.1 christos return NULL;
1232 1.1 christos }
1233 1.1 christos
1234 1.1 christos return reloc;
1235 1.1 christos }
1236 1.1 christos
1237 1.1 christos /* Convert a machine dependent frag. */
1238 1.1 christos void
1239 1.1 christos md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec ATTRIBUTE_UNUSED,
1240 1.1 christos fragS *fragp ATTRIBUTE_UNUSED)
1241 1.1 christos {
1242 1.1 christos /* fragp->fr_fix += 8; */
1243 1.1 christos }
1244 1.1 christos
1245 1.1 christos /* Standard calling conventions leave the CFA at SP on entry. */
1246 1.1 christos void
1247 1.1 christos loongarch_cfi_frame_initial_instructions (void)
1248 1.1 christos {
1249 1.1 christos cfi_add_CFA_def_cfa_register (3 /* $sp */);
1250 1.1 christos }
1251 1.1 christos
1252 1.1 christos int
1253 1.1 christos loongarch_dwarf2_addr_size (void)
1254 1.1 christos {
1255 1.1 christos return LARCH_opts.ase_lp64 ? 8 : 4;
1256 1.1 christos }
1257 1.1 christos
1258 1.1 christos void
1259 1.1 christos tc_loongarch_parse_to_dw2regnum (expressionS *exp)
1260 1.1 christos {
1261 1.1 christos expression_and_evaluate (exp);
1262 1.1 christos }
1263 1.1 christos
1264 1.1 christos void
1265 1.1 christos md_show_usage (FILE *stream)
1266 1.1 christos {
1267 1.1 christos fprintf (stream, _("LARCH options:\n"));
1268 1.1 christos /* FIXME */
1269 1.1 christos }
1270 1.1 christos
1271 1.1 christos /* Fill in an rs_align_code fragment. We want to fill 'andi $r0,$r0,0'. */
1272 1.1 christos void
1273 1.1 christos loongarch_handle_align (fragS *fragp)
1274 1.1 christos {
1275 1.1 christos /* char nop_opcode; */
1276 1.1 christos char *p;
1277 1.1 christos int bytes, size, excess;
1278 1.1 christos valueT opcode;
1279 1.1 christos
1280 1.1 christos if (fragp->fr_type != rs_align_code)
1281 1.1 christos return;
1282 1.1 christos
1283 1.1 christos struct loongarch_cl_insn nop =
1284 1.1 christos { .name = "andi", .arg_strs = { "$r0", "$r0", "0", NULL } };
1285 1.1 christos
1286 1.1 christos get_loongarch_opcode (&nop);
1287 1.1 christos gas_assert (nop.all_match);
1288 1.1 christos
1289 1.1 christos p = fragp->fr_literal + fragp->fr_fix;
1290 1.1 christos opcode = nop.insn_bin;
1291 1.1 christos size = 4;
1292 1.1 christos
1293 1.1 christos bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix;
1294 1.1 christos excess = bytes % size;
1295 1.1 christos
1296 1.1 christos gas_assert (excess < 4);
1297 1.1 christos fragp->fr_fix += excess;
1298 1.1 christos
1299 1.1 christos while (excess-- != 0)
1300 1.1 christos *p++ = 0;
1301 1.1 christos
1302 1.1 christos md_number_to_chars (p, opcode, size);
1303 1.1 christos fragp->fr_var = size;
1304 1.1 christos }
1305 1.1 christos
1306 1.1 christos void
1307 1.1 christos loongarch_elf_final_processing (void)
1308 1.1 christos {
1309 1.1 christos elf_elfheader (stdoutput)->e_flags = LARCH_opts.ase_abi;
1310 1.1 christos }
1311