binutils-gdb/gas/config/tc-wasm32.c
Alan Modra fd3619828e bfd_section_* macros
This large patch removes the unnecessary bfd parameter from various
bfd section macros and functions.  The bfd is hardly ever used and if
needed for the bfd_set_section_* or bfd_rename_section functions can
be found via section->owner except for the com, und, abs, and ind
std_section special sections.  Those sections shouldn't be modified
anyway.

The patch also removes various bfd_get_section_<field> macros,
replacing their use with bfd_section_<field>, and adds
bfd_set_section_lma.  I've also fixed a minor bug in gas where
compressed section renaming was done directly rather than calling
bfd_rename_section.  This would have broken bfd_get_section_by_name
and similar functions, but that hardly mattered at such a late stage
in gas processing.

bfd/
	* bfd-in.h (bfd_get_section_name, bfd_get_section_vma),
	(bfd_get_section_lma, bfd_get_section_alignment),
	(bfd_get_section_size, bfd_get_section_flags),
	(bfd_get_section_userdata): Delete.
	(bfd_section_name, bfd_section_size, bfd_section_vma),
	(bfd_section_lma, bfd_section_alignment): Lose bfd parameter.
	(bfd_section_flags, bfd_section_userdata): New.
	(bfd_is_com_section): Rename parameter.
	* section.c (bfd_set_section_userdata, bfd_set_section_vma),
	(bfd_set_section_alignment, bfd_set_section_flags, bfd_rename_section),
	(bfd_set_section_size): Delete bfd parameter, rename section parameter.
	(bfd_set_section_lma): New.
	* bfd-in2.h: Regenerate.
	* mach-o.c (bfd_mach_o_init_section_from_mach_o): Delete bfd param,
	update callers.
	* aoutx.h, * bfd.c, * coff-alpha.c, * coff-arm.c, * coff-mips.c,
	* coff64-rs6000.c, * coffcode.h, * coffgen.c, * cofflink.c,
	* compress.c, * ecoff.c, * elf-eh-frame.c, * elf-hppa.h,
	* elf-ifunc.c, * elf-m10200.c, * elf-m10300.c, * elf-properties.c,
	* elf-s390-common.c, * elf-vxworks.c, * elf.c, * elf32-arc.c,
	* elf32-arm.c, * elf32-avr.c, * elf32-bfin.c, * elf32-cr16.c,
	* elf32-cr16c.c, * elf32-cris.c, * elf32-crx.c, * elf32-csky.c,
	* elf32-d10v.c, * elf32-epiphany.c, * elf32-fr30.c, * elf32-frv.c,
	* elf32-ft32.c, * elf32-h8300.c, * elf32-hppa.c, * elf32-i386.c,
	* elf32-ip2k.c, * elf32-iq2000.c, * elf32-lm32.c, * elf32-m32c.c,
	* elf32-m32r.c, * elf32-m68hc1x.c, * elf32-m68k.c, * elf32-mcore.c,
	* elf32-mep.c, * elf32-metag.c, * elf32-microblaze.c,
	* elf32-moxie.c, * elf32-msp430.c, * elf32-mt.c, * elf32-nds32.c,
	* elf32-nios2.c, * elf32-or1k.c, * elf32-ppc.c, * elf32-pru.c,
	* elf32-rl78.c, * elf32-rx.c, * elf32-s390.c, * elf32-score.c,
	* elf32-score7.c, * elf32-sh.c, * elf32-spu.c, * elf32-tic6x.c,
	* elf32-tilepro.c, * elf32-v850.c, * elf32-vax.c, * elf32-visium.c,
	* elf32-xstormy16.c, * elf32-xtensa.c, * elf64-alpha.c,
	* elf64-bpf.c, * elf64-hppa.c, * elf64-ia64-vms.c, * elf64-mmix.c,
	* elf64-ppc.c, * elf64-s390.c, * elf64-sparc.c, * elf64-x86-64.c,
	* elflink.c, * elfnn-aarch64.c, * elfnn-ia64.c, * elfnn-riscv.c,
	* elfxx-aarch64.c, * elfxx-mips.c, * elfxx-sparc.c,
	* elfxx-tilegx.c, * elfxx-x86.c, * i386msdos.c, * linker.c,
	* mach-o.c, * mmo.c, * opncls.c, * pdp11.c, * pei-x86_64.c,
	* peicode.h, * reloc.c, * section.c, * syms.c, * vms-alpha.c,
	* xcofflink.c: Update throughout for bfd section macro and function
	changes.
binutils/
	* addr2line.c, * bucomm.c, * coffgrok.c, * dlltool.c, * nm.c,
	* objcopy.c, * objdump.c, * od-elf32_avr.c, * od-macho.c,
	* od-xcoff.c, * prdbg.c, * rdcoff.c, * rddbg.c, * rescoff.c,
	* resres.c, * size.c, * srconv.c, * strings.c, * windmc.c: Update
	throughout for bfd section macro and function changes.
gas/
	* as.c, * as.h, * dw2gencfi.c, * dwarf2dbg.c, * ecoff.c,
	* read.c, * stabs.c, * subsegs.c, * subsegs.h, * write.c,
	* config/obj-coff-seh.c, * config/obj-coff.c, * config/obj-ecoff.c,
	* config/obj-elf.c, * config/obj-macho.c, * config/obj-som.c,
	* config/tc-aarch64.c, * config/tc-alpha.c, * config/tc-arc.c,
	* config/tc-arm.c, * config/tc-avr.c, * config/tc-bfin.c,
	* config/tc-bpf.c, * config/tc-d10v.c, * config/tc-d30v.c,
	* config/tc-epiphany.c, * config/tc-fr30.c, * config/tc-frv.c,
	* config/tc-h8300.c, * config/tc-hppa.c, * config/tc-i386.c,
	* config/tc-ia64.c, * config/tc-ip2k.c, * config/tc-iq2000.c,
	* config/tc-lm32.c, * config/tc-m32c.c, * config/tc-m32r.c,
	* config/tc-m68hc11.c, * config/tc-mep.c, * config/tc-microblaze.c,
	* config/tc-mips.c, * config/tc-mmix.c, * config/tc-mn10200.c,
	* config/tc-mn10300.c, * config/tc-msp430.c, * config/tc-mt.c,
	* config/tc-nds32.c, * config/tc-or1k.c, * config/tc-ppc.c,
	* config/tc-pru.c, * config/tc-rl78.c, * config/tc-rx.c,
	* config/tc-s12z.c, * config/tc-s390.c, * config/tc-score.c,
	* config/tc-score7.c, * config/tc-sh.c, * config/tc-sparc.c,
	* config/tc-spu.c, * config/tc-tic4x.c, * config/tc-tic54x.c,
	* config/tc-tic6x.c, * config/tc-tilegx.c, * config/tc-tilepro.c,
	* config/tc-v850.c, * config/tc-visium.c, * config/tc-wasm32.c,
	* config/tc-xc16x.c, * config/tc-xgate.c, * config/tc-xstormy16.c,
	* config/tc-xtensa.c, * config/tc-z8k.c: Update throughout for
	bfd section macro and function changes.
	* write.c (compress_debug): Use bfd_rename_section.
gdb/
	* aarch64-linux-tdep.c, * arm-tdep.c, * auto-load.c,
	* coff-pe-read.c, * coffread.c, * corelow.c, * dbxread.c,
	* dicos-tdep.c, * dwarf2-frame.c, * dwarf2read.c, * elfread.c,
	* exec.c, * fbsd-tdep.c, * gcore.c, * gdb_bfd.c, * gdb_bfd.h,
	* hppa-tdep.c, * i386-cygwin-tdep.c, * i386-fbsd-tdep.c,
	* i386-linux-tdep.c, * jit.c, * linux-tdep.c, * machoread.c,
	* maint.c, * mdebugread.c, * minidebug.c, * mips-linux-tdep.c,
	* mips-sde-tdep.c, * mips-tdep.c, * mipsread.c, * nto-tdep.c,
	* objfiles.c, * objfiles.h, * osabi.c, * ppc-linux-tdep.c,
	* ppc64-tdep.c, * record-btrace.c, * record-full.c, * remote.c,
	* rs6000-aix-tdep.c, * rs6000-tdep.c, * s390-linux-tdep.c,
	* s390-tdep.c, * solib-aix.c, * solib-dsbt.c, * solib-frv.c,
	* solib-spu.c, * solib-svr4.c, * solib-target.c,
	* spu-linux-nat.c, * spu-tdep.c, * symfile-mem.c, * symfile.c,
	* symmisc.c, * symtab.c, * target.c, * windows-nat.c,
	* xcoffread.c, * cli/cli-dump.c, * compile/compile-object-load.c,
	* mi/mi-interp.c: Update throughout for bfd section macro and
	function changes.
	* gcore (gcore_create_callback): Use bfd_set_section_lma.
	* spu-tdep.c (spu_overlay_new_objfile): Likewise.
gprof/
	* corefile.c, * symtab.c: Update throughout for bfd section
	macro and function changes.
ld/
	* ldcref.c, * ldctor.c, * ldelf.c, * ldlang.c, * pe-dll.c,
	* emultempl/aarch64elf.em, * emultempl/aix.em,
	* emultempl/armcoff.em, * emultempl/armelf.em,
	* emultempl/cr16elf.em, * emultempl/cskyelf.em,
	* emultempl/m68hc1xelf.em, * emultempl/m68kelf.em,
	* emultempl/mipself.em, * emultempl/mmix-elfnmmo.em,
	* emultempl/mmo.em, * emultempl/msp430.em,
	* emultempl/nios2elf.em, * emultempl/pe.em, * emultempl/pep.em,
	* emultempl/ppc64elf.em, * emultempl/xtensaelf.em: Update
	throughout for bfd section macro and function changes.
libctf/
	* ctf-open-bfd.c: Update throughout for bfd section macro changes.
opcodes/
	* arc-ext.c: Update throughout for bfd section macro changes.
sim/
	* common/sim-load.c, * common/sim-utils.c, * cris/sim-if.c,
	* erc32/func.c, * lm32/sim-if.c, * m32c/load.c, * m32c/trace.c,
	* m68hc11/interp.c, * ppc/hw_htab.c, * ppc/hw_init.c,
	* rl78/load.c, * rl78/trace.c, * rx/gdb-if.c, * rx/load.c,
	* rx/trace.c: Update throughout for bfd section macro changes.
2019-09-19 09:40:13 +09:30

822 lines
18 KiB
C

/* tc-wasm32.c -- Assembler code for the wasm32 target.
Copyright (C) 2017-2019 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "as.h"
#include "safe-ctype.h"
#include "subsegs.h"
#include "dwarf2dbg.h"
#include "dw2gencfi.h"
#include "elf/wasm32.h"
#include <float.h>
enum wasm_class
{
wasm_typed, /* a typed opcode: block, loop, or if */
wasm_special, /* a special opcode: unreachable, nop, else,
or end */
wasm_break, /* "br" */
wasm_break_if, /* "br_if" opcode */
wasm_break_table, /* "br_table" opcode */
wasm_return, /* "return" opcode */
wasm_call, /* "call" opcode */
wasm_call_indirect, /* "call_indirect" opcode */
wasm_get_local, /* "get_local" and "get_global" */
wasm_set_local, /* "set_local" and "set_global" */
wasm_tee_local, /* "tee_local" */
wasm_drop, /* "drop" */
wasm_constant_i32, /* "i32.const" */
wasm_constant_i64, /* "i64.const" */
wasm_constant_f32, /* "f32.const" */
wasm_constant_f64, /* "f64.const" */
wasm_unary, /* unary operators */
wasm_binary, /* binary operators */
wasm_conv, /* conversion operators */
wasm_load, /* load operators */
wasm_store, /* store operators */
wasm_select, /* "select" */
wasm_relational, /* comparison operators, except for "eqz" */
wasm_eqz, /* "eqz" */
wasm_current_memory, /* "current_memory" */
wasm_grow_memory, /* "grow_memory" */
wasm_signature /* "signature", which isn't an opcode */
};
#define WASM_OPCODE(opcode, name, intype, outtype, class, signedness) \
{ name, wasm_ ## class, opcode },
struct wasm32_opcode_s
{
const char *name;
enum wasm_class clas;
unsigned char opcode;
} wasm32_opcodes[] =
{
#include "opcode/wasm.h"
{
NULL, 0, 0}
};
const char comment_chars[] = ";#";
const char line_comment_chars[] = ";#";
const char line_separator_chars[] = "";
const char *md_shortopts = "m:";
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "dD";
/* The target specific pseudo-ops which we support. */
const pseudo_typeS md_pseudo_table[] =
{
{NULL, NULL, 0}
};
/* Opcode hash table. */
static struct hash_control *wasm32_hash;
struct option md_longopts[] =
{
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
/* No relaxation/no machine-dependent frags. */
int
md_estimate_size_before_relax (fragS * fragp ATTRIBUTE_UNUSED,
asection * seg ATTRIBUTE_UNUSED)
{
abort ();
return 0;
}
void
md_show_usage (FILE * stream)
{
fprintf (stream, _("wasm32 assembler options:\n"));
}
/* No machine-dependent options. */
int
md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
{
return 0;
}
/* No machine-dependent symbols. */
symbolS *
md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
{
return NULL;
}
/* IEEE little-endian floats. */
const char *
md_atof (int type, char *litP, int *sizeP)
{
return ieee_md_atof (type, litP, sizeP, FALSE);
}
/* No machine-dependent frags. */
void
md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
asection * sec ATTRIBUTE_UNUSED,
fragS * fragP ATTRIBUTE_UNUSED)
{
abort ();
}
/* Build opcode hash table, set some flags. */
void
md_begin (void)
{
struct wasm32_opcode_s *opcode;
wasm32_hash = hash_new ();
/* Insert unique names into hash table. This hash table then
provides a quick index to the first opcode with a particular name
in the opcode table. */
for (opcode = wasm32_opcodes; opcode->name; opcode++)
hash_insert (wasm32_hash, opcode->name, (char *) opcode);
linkrelax = 0;
flag_sectname_subst = 1;
flag_no_comments = 0;
flag_keep_locals = 1;
}
/* Do the normal thing for md_section_align. */
valueT
md_section_align (asection * seg, valueT addr)
{
int align = bfd_section_alignment (seg);
return ((addr + (1 << align) - 1) & -(1 << align));
}
/* Apply a fixup, return TRUE if done (and no relocation is
needed). */
static bfd_boolean
apply_full_field_fix (fixS * fixP, char *buf, bfd_vma val, int size)
{
if (fixP->fx_addsy != NULL || fixP->fx_pcrel)
{
fixP->fx_addnumber = val;
return FALSE;
}
number_to_chars_littleendian (buf, val, size);
return TRUE;
}
/* Apply a fixup (potentially PC-relative), set the fx_done flag if
done. */
void
md_apply_fix (fixS * fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED)
{
char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
long val = (long) *valP;
if (fixP->fx_pcrel)
{
switch (fixP->fx_r_type)
{
default:
bfd_set_error (bfd_error_bad_value);
return;
case BFD_RELOC_32:
fixP->fx_r_type = BFD_RELOC_32_PCREL;
return;
}
}
if (apply_full_field_fix (fixP, buf, val, fixP->fx_size))
fixP->fx_done = 1;
}
/* Skip whitespace. */
static inline char *
skip_space (char *s)
{
while (*s == ' ' || *s == '\t')
++s;
return s;
}
/* Allow '/' in opcodes. */
static inline bfd_boolean
is_part_of_opcode (char c)
{
return is_part_of_name (c) || (c == '/');
}
/* Extract an opcode. */
static char *
extract_opcode (char *from, char *to, int limit)
{
char *op_end;
int size = 0;
/* Drop leading whitespace. */
from = skip_space (from);
*to = 0;
/* Find the op code end. */
for (op_end = from; *op_end != 0 && is_part_of_opcode (*op_end);)
{
to[size++] = *op_end++;
if (size + 1 >= limit)
break;
}
to[size] = 0;
return op_end;
}
/* Produce an unsigned LEB128 integer padded to the right number of
bytes to store BITS bits, of value VALUE. Uses FRAG_APPEND_1_CHAR
to write. */
static void
wasm32_put_long_uleb128 (int bits, unsigned long value)
{
unsigned char c;
int i = 0;
do
{
c = value & 0x7f;
value >>= 7;
if (i < (bits - 1) / 7)
c |= 0x80;
FRAG_APPEND_1_CHAR (c);
}
while (++i < (bits + 6) / 7);
}
/* Produce a signed LEB128 integer, using FRAG_APPEND_1_CHAR to
write. */
static void
wasm32_put_sleb128 (long value)
{
unsigned char c;
int more;
do
{
c = (value & 0x7f);
value >>= 7;
more = !((((value == 0) && ((c & 0x40) == 0))
|| ((value == -1) && ((c & 0x40) != 0))));
if (more)
c |= 0x80;
FRAG_APPEND_1_CHAR (c);
}
while (more);
}
/* Produce an unsigned LEB128 integer, using FRAG_APPEND_1_CHAR to
write. */
static void
wasm32_put_uleb128 (unsigned long value)
{
unsigned char c;
do
{
c = value & 0x7f;
value >>= 7;
if (value)
c |= 0x80;
FRAG_APPEND_1_CHAR (c);
}
while (value);
}
/* Read an integer expression. Produce an LEB128-encoded integer if
it's a constant, a padded LEB128 plus a relocation if it's a
symbol, or a special relocation for <expr>@got, <expr>@gotcode, and
<expr>@plt{__sigchar_<signature>}. */
static bfd_boolean
wasm32_leb128 (char **line, int bits, int sign)
{
char *t = input_line_pointer;
char *str = *line;
char *str0 = str;
struct reloc_list *reloc;
expressionS ex;
int gotrel = 0;
int pltrel = 0;
int code = 0;
const char *relname;
input_line_pointer = str;
expression (&ex);
if (ex.X_op == O_constant && *input_line_pointer != '@')
{
long value = ex.X_add_number;
str = input_line_pointer;
str = skip_space (str);
*line = str;
if (sign)
wasm32_put_sleb128 (value);
else
{
if (value < 0)
as_bad (_("unexpected negative constant"));
wasm32_put_uleb128 (value);
}
input_line_pointer = t;
return str != str0;
}
reloc = XNEW (struct reloc_list);
reloc->u.a.offset_sym = expr_build_dot ();
if (ex.X_op == O_symbol)
{
reloc->u.a.sym = ex.X_add_symbol;
reloc->u.a.addend = ex.X_add_number;
}
else
{
reloc->u.a.sym = make_expr_symbol (&ex);
reloc->u.a.addend = 0;
}
/* i32.const fpointer@gotcode */
if (strncmp (input_line_pointer, "@gotcode", 8) == 0)
{
gotrel = 1;
code = 1;
input_line_pointer += 8;
}
/* i32.const data@got */
else if (strncmp (input_line_pointer, "@got", 4) == 0)
{
gotrel = 1;
input_line_pointer += 4;
}
/* call f@plt{__sigchar_FiiiiE} */
else if (strncmp (input_line_pointer, "@plt", 4) == 0)
{
char *end_of_sig;
pltrel = 1;
code = 1;
input_line_pointer += 4;
if (strncmp (input_line_pointer, "{", 1) == 0
&& (end_of_sig = strchr (input_line_pointer, '}')))
{
char *signature;
struct reloc_list *reloc2;
size_t siglength = end_of_sig - (input_line_pointer + 1);
signature = strndup (input_line_pointer + 1, siglength);
reloc2 = XNEW (struct reloc_list);
reloc2->u.a.offset_sym = expr_build_dot ();
reloc2->u.a.sym = symbol_find_or_make (signature);
reloc2->u.a.addend = 0;
reloc2->u.a.howto = bfd_reloc_name_lookup
(stdoutput, "R_WASM32_PLT_SIG");
reloc2->next = reloc_list;
reloc_list = reloc2;
input_line_pointer = end_of_sig + 1;
}
else
{
as_bad (_("no function type on PLT reloc"));
}
}
if (gotrel && code)
relname = "R_WASM32_LEB128_GOT_CODE";
else if (gotrel)
relname = "R_WASM32_LEB128_GOT";
else if (pltrel)
relname = "R_WASM32_LEB128_PLT";
else
relname = "R_WASM32_LEB128";
reloc->u.a.howto = bfd_reloc_name_lookup (stdoutput, relname);
if (!reloc->u.a.howto)
as_bad (_("couldn't find relocation to use"));
reloc->file = as_where (&reloc->line);
reloc->next = reloc_list;
reloc_list = reloc;
str = input_line_pointer;
str = skip_space (str);
*line = str;
wasm32_put_long_uleb128 (bits, 0);
input_line_pointer = t;
return str != str0;
}
/* Read an integer expression and produce an unsigned LEB128 integer,
or a relocation for it. */
static bfd_boolean
wasm32_uleb128 (char **line, int bits)
{
return wasm32_leb128 (line, bits, 0);
}
/* Read an integer expression and produce a signed LEB128 integer, or
a relocation for it. */
static bfd_boolean
wasm32_sleb128 (char **line, int bits)
{
return wasm32_leb128 (line, bits, 1);
}
/* Read an f32. (Like float_cons ('f')). */
static void
wasm32_f32 (char **line)
{
char *t = input_line_pointer;
input_line_pointer = *line;
float_cons ('f');
*line = input_line_pointer;
input_line_pointer = t;
}
/* Read an f64. (Like float_cons ('d')). */
static void
wasm32_f64 (char **line)
{
char *t = input_line_pointer;
input_line_pointer = *line;
float_cons ('d');
*line = input_line_pointer;
input_line_pointer = t;
}
/* Assemble a signature from LINE, replacing it with the new input
pointer. Signatures are simple expressions matching the regexp
F[ilfd]*v?E, and interpreted as though they were C++-mangled
function types on a 64-bit machine. */
static void
wasm32_signature (char **line)
{
unsigned long count = 0;
char *str = *line;
char *ostr;
char *result;
if (*str++ != 'F')
as_bad (_("Not a function type"));
result = str;
ostr = str + 1;
str++;
while (*str != 'E')
{
switch (*str++)
{
case 'i':
case 'l':
case 'f':
case 'd':
count++;
break;
default:
as_bad (_("Unknown type %c\n"), str[-1]);
}
}
wasm32_put_uleb128 (count);
str = ostr;
while (*str != 'E')
{
switch (*str++)
{
case 'i':
FRAG_APPEND_1_CHAR (BLOCK_TYPE_I32);
break;
case 'l':
FRAG_APPEND_1_CHAR (BLOCK_TYPE_I64);
break;
case 'f':
FRAG_APPEND_1_CHAR (BLOCK_TYPE_F32);
break;
case 'd':
FRAG_APPEND_1_CHAR (BLOCK_TYPE_F64);
break;
default:
as_bad (_("Unknown type"));
}
}
str++;
switch (*result)
{
case 'v':
FRAG_APPEND_1_CHAR (0x00); /* no return value */
break;
case 'i':
FRAG_APPEND_1_CHAR (0x01); /* one return value */
FRAG_APPEND_1_CHAR (BLOCK_TYPE_I32);
break;
case 'l':
FRAG_APPEND_1_CHAR (0x01); /* one return value */
FRAG_APPEND_1_CHAR (BLOCK_TYPE_I64);
break;
case 'f':
FRAG_APPEND_1_CHAR (0x01); /* one return value */
FRAG_APPEND_1_CHAR (BLOCK_TYPE_F32);
break;
case 'd':
FRAG_APPEND_1_CHAR (0x01); /* one return value */
FRAG_APPEND_1_CHAR (BLOCK_TYPE_F64);
break;
default:
as_bad (_("Unknown type"));
}
*line = str;
}
/* Main operands function. Read the operands for OPCODE from LINE,
replacing it with the new input pointer. */
static void
wasm32_operands (struct wasm32_opcode_s *opcode, char **line)
{
char *str = *line;
unsigned long block_type = 0;
FRAG_APPEND_1_CHAR (opcode->opcode);
str = skip_space (str);
if (str[0] == '[')
{
if (opcode->clas == wasm_typed)
{
str++;
block_type = BLOCK_TYPE_NONE;
if (str[0] != ']')
{
str = skip_space (str);
switch (str[0])
{
case 'i':
block_type = BLOCK_TYPE_I32;
str++;
break;
case 'l':
block_type = BLOCK_TYPE_I64;
str++;
break;
case 'f':
block_type = BLOCK_TYPE_F32;
str++;
break;
case 'd':
block_type = BLOCK_TYPE_F64;
str++;
break;
}
str = skip_space (str);
if (str[0] == ']')
str++;
else
as_bad (_("only single block types allowed"));
str = skip_space (str);
}
else
{
str++;
str = skip_space (str);
}
}
else
as_bad (_("instruction does not take a block type"));
}
switch (opcode->clas)
{
case wasm_drop:
case wasm_special:
case wasm_binary:
case wasm_unary:
case wasm_relational:
case wasm_select:
case wasm_eqz:
case wasm_conv:
case wasm_return:
break;
case wasm_typed:
if (block_type == 0)
as_bad (_("missing block type"));
FRAG_APPEND_1_CHAR (block_type);
break;
case wasm_store:
case wasm_load:
if (str[0] == 'a' && str[1] == '=')
{
str += 2;
if (!wasm32_uleb128 (&str, 32))
as_bad (_("missing alignment hint"));
}
else
{
as_bad (_("missing alignment hint"));
}
str = skip_space (str);
if (!wasm32_uleb128 (&str, 32))
as_bad (_("missing offset"));
break;
case wasm_set_local:
case wasm_get_local:
case wasm_tee_local:
if (!wasm32_uleb128 (&str, 32))
as_bad (_("missing local index"));
break;
case wasm_break:
case wasm_break_if:
if (!wasm32_uleb128 (&str, 32))
as_bad (_("missing break count"));
break;
case wasm_current_memory:
case wasm_grow_memory:
if (!wasm32_uleb128 (&str, 32))
as_bad (_("missing reserved current_memory/grow_memory argument"));
break;
case wasm_call:
if (!wasm32_uleb128 (&str, 32))
as_bad (_("missing call argument"));
break;
case wasm_call_indirect:
if (!wasm32_uleb128 (&str, 32))
as_bad (_("missing call signature"));
if (!wasm32_uleb128 (&str, 32))
as_bad (_("missing table index"));
break;
case wasm_constant_i32:
wasm32_sleb128 (&str, 32);
break;
case wasm_constant_i64:
wasm32_sleb128 (&str, 64);
break;
case wasm_constant_f32:
wasm32_f32 (&str);
return;
case wasm_constant_f64:
wasm32_f64 (&str);
return;
case wasm_break_table:
{
do
{
wasm32_uleb128 (&str, 32);
str = skip_space (str);
}
while (str[0]);
break;
}
case wasm_signature:
wasm32_signature (&str);
}
str = skip_space (str);
if (*str)
as_bad (_("junk at end of line, first unrecognized character is `%c'"),
*str);
*line = str;
return;
}
/* Main assembly function. Find the opcode and call
wasm32_operands(). */
void
md_assemble (char *str)
{
char op[32];
char *t;
struct wasm32_opcode_s *opcode;
str = skip_space (extract_opcode (str, op, sizeof (op)));
if (!op[0])
as_bad (_("can't find opcode "));
opcode = (struct wasm32_opcode_s *) hash_find (wasm32_hash, op);
if (opcode == NULL)
{
as_bad (_("unknown opcode `%s'"), op);
return;
}
dwarf2_emit_insn (0);
t = input_line_pointer;
wasm32_operands (opcode, &str);
input_line_pointer = t;
}
/* Don't replace PLT/GOT relocations with section symbols, so they
don't get an addend. */
int
wasm32_force_relocation (fixS * f)
{
if (f->fx_r_type == BFD_RELOC_WASM32_LEB128_PLT
|| f->fx_r_type == BFD_RELOC_WASM32_LEB128_GOT)
return 1;
return 0;
}
/* Don't replace PLT/GOT relocations with section symbols, so they
don't get an addend. */
bfd_boolean
wasm32_fix_adjustable (fixS * fixP)
{
if (fixP->fx_addsy == NULL)
return TRUE;
if (fixP->fx_r_type == BFD_RELOC_WASM32_LEB128_PLT
|| fixP->fx_r_type == BFD_RELOC_WASM32_LEB128_GOT)
return FALSE;
return TRUE;
}
/* Generate a reloc for FIXP. */
arelent *
tc_gen_reloc (asection * sec ATTRIBUTE_UNUSED, fixS * fixp)
{
arelent *reloc;
reloc = (arelent *) xmalloc (sizeof (*reloc));
reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
/* Make sure none of our internal relocations make it this far.
They'd better have been fully resolved by this point. */
gas_assert ((int) fixp->fx_r_type > 0);
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
if (reloc->howto == NULL)
{
as_bad_where (fixp->fx_file, fixp->fx_line,
_("cannot represent `%s' relocation in object file"),
bfd_get_reloc_code_name (fixp->fx_r_type));
return NULL;
}
reloc->addend = fixp->fx_offset;
return reloc;
}