]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-bpf.c
2.41 Release sources
[thirdparty/binutils-gdb.git] / gas / config / tc-bpf.c
index b4566d89ddf8c5e15bf209bf55e4efedfc953ae7..3b86f9c89cb68857db27bdce15aaedbf84f1a2d1 100644 (file)
 #include "as.h"
 #include "subsegs.h"
 #include "symcat.h"
-#include "opcode/bpf.h"
+#include "opcodes/bpf-desc.h"
+#include "opcodes/bpf-opc.h"
+#include "cgen.h"
 #include "elf/common.h"
 #include "elf/bpf.h"
 #include "dwarf2dbg.h"
-#include "libiberty.h"
 #include <ctype.h>
 
-/* Data structure representing a parsed BPF instruction.  */
-
-struct bpf_insn
-{
-  enum bpf_insn_id id;
-  int size; /* Instruction size in bytes.  */
-  bpf_insn_word opcode;
-  uint8_t dst;
-  uint8_t src;
-  expressionS offset16;
-  expressionS imm32;
-  expressionS imm64;
-  expressionS disp16;
-  expressionS disp32;
-
-  unsigned int has_dst : 1;
-  unsigned int has_src : 1;
-  unsigned int has_offset16 : 1;
-  unsigned int has_disp16 : 1;
-  unsigned int has_disp32 : 1;
-  unsigned int has_imm32 : 1;
-  unsigned int has_imm64 : 1;
-
-  unsigned int is_relaxable : 1;
-  expressionS *relaxed_exp;
-};
-
-const char comment_chars[]        = ";#";
+const char comment_chars[]        = ";";
 const char line_comment_chars[]   = "#";
 const char line_separator_chars[] = "`";
 const char EXP_CHARS[]            = "eE";
 const char FLT_CHARS[]            = "fFdD";
 
+static const char *invalid_expression;
+static char pseudoc_lex[256];
+static const char symbol_chars[] =
+"_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+static const char arithm_op[] = "+-/<>%&|^";
+
+static void init_pseudoc_lex (void);
+
+#define LEX_IS_SYMBOL_COMPONENT  1
+#define LEX_IS_WHITESPACE        2
+#define LEX_IS_NEWLINE           3
+#define LEX_IS_ARITHM_OP         4
+#define LEX_IS_STAR              6
+#define LEX_IS_CLSE_BR           7
+#define LEX_IS_OPEN_BR           8
+#define LEX_IS_EQUAL             9
+#define LEX_IS_EXCLA             10
+
+#define ST_EOI        100
+#define MAX_TOKEN_SZ  100
+
 /* Like s_lcomm_internal in gas/read.c but the alignment string
    is allowed to be optional.  */
 
@@ -114,16 +110,18 @@ const pseudo_typeS md_pseudo_table[] =
 
 \f
 
+/* ISA handling.  */
+static CGEN_BITSET *bpf_isa;
+
+\f
+
 /* Command-line options processing.  */
 
 enum options
 {
   OPTION_LITTLE_ENDIAN = OPTION_MD_BASE,
   OPTION_BIG_ENDIAN,
-  OPTION_XBPF,
-  OPTION_DIALECT,
-  OPTION_ISA_SPEC,
-  OPTION_NO_RELAX,
+  OPTION_XBPF
 };
 
 struct option md_longopts[] =
@@ -131,9 +129,6 @@ struct option md_longopts[] =
   { "EL", no_argument, NULL, OPTION_LITTLE_ENDIAN },
   { "EB", no_argument, NULL, OPTION_BIG_ENDIAN },
   { "mxbpf", no_argument, NULL, OPTION_XBPF },
-  { "mdialect", required_argument, NULL, OPTION_DIALECT},
-  { "misa-spec", required_argument, NULL, OPTION_ISA_SPEC},
-  { "mno-relax", no_argument, NULL, OPTION_NO_RELAX},
   { NULL,          no_argument, NULL, 0 },
 };
 
@@ -141,39 +136,18 @@ size_t md_longopts_size = sizeof (md_longopts);
 
 const char * md_shortopts = "";
 
-/* BPF supports little-endian and big-endian variants.  The following
-   global records what endianness to use.  It can be configured using
-   command-line options.  It defaults to the host endianness
-   initialized in md_begin.  */
-
-static int set_target_endian = 0;
 extern int target_big_endian;
 
-/* Whether to relax branch instructions.  Default is yes.  Can be
-   changed using the -mno-relax command line option.  */
-
-static int do_relax = 1;
-
-/* The ISA specification can be one of BPF_V1, BPF_V2, BPF_V3, BPF_V4
-   or BPF_XPBF.  The ISA spec to use can be configured using
-   command-line options.  It defaults to the latest BPF spec.  */
-
-static int isa_spec = BPF_V4;
-
-/* The assembler supports two different dialects: "normal" syntax and
-   "pseudoc" syntax.  The dialect to use can be configured using
-   command-line options.  */
+/* Whether target_big_endian has been set while parsing command-line
+   arguments.  */
+static int set_target_endian = 0;
 
-enum target_asm_dialect
-{
-  DIALECT_NORMAL,
-  DIALECT_PSEUDOC
-};
+static int target_xbpf = 0;
 
-static int asm_dialect = DIALECT_NORMAL;
+static int set_xbpf = 0;
 
 int
-md_parse_option (int c, const char * arg)
+md_parse_option (int c, const char * arg ATTRIBUTE_UNUSED)
 {
   switch (c)
     {
@@ -182,39 +156,12 @@ md_parse_option (int c, const char * arg)
       target_big_endian = 1;
       break;
     case OPTION_LITTLE_ENDIAN:
-      set_target_endian = 0;
+      set_target_endian = 1;
       target_big_endian = 0;
       break;
-    case OPTION_DIALECT:
-      if (strcmp (arg, "normal") == 0)
-        asm_dialect = DIALECT_NORMAL;
-      else if (strcmp (arg, "pseudoc") == 0)
-        asm_dialect = DIALECT_PSEUDOC;
-      else
-        as_fatal (_("-mdialect=%s is not valid.  Expected normal or pseudoc"),
-                  arg);
-      break;
-    case OPTION_ISA_SPEC:
-      if (strcmp (arg, "v1") == 0)
-        isa_spec = BPF_V1;
-      else if (strcmp (arg, "v2") == 0)
-        isa_spec = BPF_V2;
-      else if (strcmp (arg, "v3") == 0)
-        isa_spec = BPF_V3;
-      else if (strcmp (arg, "v4") == 0)
-        isa_spec = BPF_V4;
-      else if (strcmp (arg, "xbpf") == 0)
-        isa_spec = BPF_XBPF;
-      else
-        as_fatal (_("-misa-spec=%s is not valid.  Expected v1, v2, v3, v4 o xbpf"),
-                  arg);
-      break;
     case OPTION_XBPF:
-      /* This is an alias for -misa-spec=xbpf.  */
-      isa_spec = BPF_XBPF;
-      break;
-    case OPTION_NO_RELAX:
-      do_relax = 0;
+      set_xbpf = 1;
+      target_xbpf = 1;
       break;
     default:
       return 0;
@@ -228,22 +175,43 @@ md_show_usage (FILE * stream)
 {
   fprintf (stream, _("\nBPF options:\n"));
   fprintf (stream, _("\
-BPF options:\n\
-  -EL                         generate code for a little endian machine\n\
-  -EB                         generate code for a big endian machine\n\
-  -mdialect=DIALECT           set the assembly dialect (normal, pseudoc)\n\
-  -misa-spec                  set the BPF ISA spec (v1, v2, v3, v4, xbpf)\n\
-  -mxbpf                      alias for -misa-spec=xbpf\n"));
+  --EL                 generate code for a little endian machine\n\
+  --EB                 generate code for a big endian machine\n\
+  -mxbpf                generate xBPF instructions\n"));
 }
 
 \f
-/* This function is called once, at assembler startup time.  This
-   should set up all the tables, etc that the MD part of the assembler
-   needs.  */
+
+static void
+init_pseudoc_lex (void)
+{
+  const char *p;
+
+  for (p = symbol_chars; *p; ++p)
+    pseudoc_lex[(unsigned char) *p] = LEX_IS_SYMBOL_COMPONENT;
+
+  pseudoc_lex[' '] = LEX_IS_WHITESPACE;
+  pseudoc_lex['\t'] = LEX_IS_WHITESPACE;
+  pseudoc_lex['\r'] = LEX_IS_WHITESPACE;
+  pseudoc_lex['\n'] = LEX_IS_NEWLINE;
+  pseudoc_lex['*'] = LEX_IS_STAR;
+  pseudoc_lex[')'] = LEX_IS_CLSE_BR;
+  pseudoc_lex['('] = LEX_IS_OPEN_BR;
+  pseudoc_lex[']'] = LEX_IS_CLSE_BR;
+  pseudoc_lex['['] = LEX_IS_OPEN_BR;
+
+  for (p = arithm_op; *p; ++p)
+    pseudoc_lex[(unsigned char) *p] = LEX_IS_ARITHM_OP;
+
+  pseudoc_lex['='] = LEX_IS_EQUAL;
+  pseudoc_lex['!'] = LEX_IS_EXCLA;
+}
 
 void
 md_begin (void)
 {
+  /* Initialize the `cgen' interface.  */
+
   /* If not specified in the command line, use the host
      endianness.  */
   if (!set_target_endian)
@@ -255,15 +223,50 @@ md_begin (void)
 #endif
     }
 
+  /* If not specified in the command line, use eBPF rather
+     than xBPF.  */
+  if (!set_xbpf)
+      target_xbpf = 0;
+
+  /* Set the ISA, which depends on the target endianness. */
+  bpf_isa = cgen_bitset_create (ISA_MAX);
+  if (target_big_endian)
+    {
+      if (target_xbpf)
+       cgen_bitset_set (bpf_isa, ISA_XBPFBE);
+      else
+       cgen_bitset_set (bpf_isa, ISA_EBPFBE);
+    }
+  else
+    {
+      if (target_xbpf)
+       cgen_bitset_set (bpf_isa, ISA_XBPFLE);
+      else
+       cgen_bitset_set (bpf_isa, ISA_EBPFLE);
+    }
+
   /* Ensure that lines can begin with '*' in BPF store pseudoc instruction.  */
   lex_type['*'] |= LEX_BEGIN_NAME;
 
+  /* Set the machine number and endian.  */
+  gas_cgen_cpu_desc = bpf_cgen_cpu_open (CGEN_CPU_OPEN_ENDIAN,
+                                         target_big_endian ?
+                                         CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE,
+                                         CGEN_CPU_OPEN_INSN_ENDIAN,
+                                         CGEN_ENDIAN_LITTLE,
+                                         CGEN_CPU_OPEN_ISAS,
+                                         bpf_isa,
+                                         CGEN_CPU_OPEN_END);
+  bpf_cgen_init_asm (gas_cgen_cpu_desc);
+
+  /* This is a callback from cgen to gas to parse operands.  */
+  cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
+
   /* Set the machine type. */
   bfd_default_set_arch_mach (stdoutput, bfd_arch_bpf, bfd_mach_bpf);
+  init_pseudoc_lex();
 }
 
-/* Round up a section size to the appropriate boundary.  */
-
 valueT
 md_section_align (segT segment, valueT size)
 {
@@ -272,20 +275,6 @@ md_section_align (segT segment, valueT size)
   return ((size + (1 << align) - 1) & -(1 << align));
 }
 
-/* Return non-zero if the indicated VALUE has overflowed the maximum
-   range expressible by an signed number with the indicated number of
-   BITS.  */
-
-static bool
-signed_overflow (offsetT value, unsigned bits)
-{
-  offsetT lim;
-  if (bits >= sizeof (offsetT) * 8)
-    return false;
-  lim = (offsetT) 1 << (bits - 1);
-  return (value < -lim || value >= lim);
-}
-
 \f
 /* Functions concerning relocs.  */
 
@@ -321,194 +310,34 @@ md_number_to_chars (char * buf, valueT val, int n)
 }
 
 arelent *
-tc_gen_reloc (asection *sec ATTRIBUTE_UNUSED, fixS *fixP)
+tc_gen_reloc (asection *sec, fixS *fix)
 {
-  bfd_reloc_code_real_type r_type = fixP->fx_r_type;
-  arelent *reloc;
-
-  reloc = XNEW (arelent);
-
-  if (fixP->fx_pcrel)
-   {
-      r_type = (r_type == BFD_RELOC_8 ? BFD_RELOC_8_PCREL
-                : r_type == BFD_RELOC_16 ? BFD_RELOC_16_PCREL
-                : r_type == BFD_RELOC_24 ? BFD_RELOC_24_PCREL
-                : r_type == BFD_RELOC_32 ? BFD_RELOC_32_PCREL
-                : r_type == BFD_RELOC_64 ? BFD_RELOC_64_PCREL
-                : r_type);
-   }
-
-  reloc->howto = bfd_reloc_type_lookup (stdoutput, r_type);
-
-  if (reloc->howto == (reloc_howto_type *) NULL)
-    {
-      as_bad_where (fixP->fx_file, fixP->fx_line,
-                   _("relocation is not supported"));
-      return NULL;
-    }
-
-  //XXX  gas_assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
-
-  reloc->sym_ptr_ptr = XNEW (asymbol *);
-  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
-
-  /* Use fx_offset for these cases.  */
-  if (fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
-      || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT)
-    reloc->addend = fixP->fx_offset;
-  else
-    reloc->addend = fixP->fx_addnumber;
-
-  reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
-  return reloc;
+  return gas_cgen_tc_gen_reloc (sec, fix);
 }
 
-\f
-/* Relaxations supported by this assembler.  */
-
-#define RELAX_BRANCH_ENCODE(uncond, constant, length)    \
-  ((relax_substateT)                                     \
-   (0xc0000000                                           \
-    | ((uncond) ? 1 : 0)                                 \
-    | ((constant) ? 2 : 0)                               \
-    | ((length) << 2)))
-
-#define RELAX_BRANCH_P(i) (((i) & 0xf0000000) == 0xc0000000)
-#define RELAX_BRANCH_LENGTH(i) (((i) >> 2) & 0xff)
-#define RELAX_BRANCH_CONST(i) (((i) & 2) != 0)
-#define RELAX_BRANCH_UNCOND(i) (((i) & 1) != 0)
+/* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.  This
+   is called when the operand is an expression that couldn't be fully
+   resolved.  Returns BFD_RELOC_NONE if no reloc type can be found.
+   *FIXP may be modified if desired.  */
 
-
-/* Compute the length of a branch seuqence, and adjust the stored
-   length accordingly.  If FRAG is NULL, the worst-case length is
-   returned.  */
-
-static unsigned
-relaxed_branch_length (fragS *fragp, asection *sec, int update)
+bfd_reloc_code_real_type
+md_cgen_lookup_reloc (const CGEN_INSN *insn ATTRIBUTE_UNUSED,
+                     const CGEN_OPERAND *operand,
+                     fixS *fixP)
 {
-  int length, uncond;
-
-  if (!fragp)
-    return 8 * 3;
-
-  uncond = RELAX_BRANCH_UNCOND (fragp->fr_subtype);
-  length = RELAX_BRANCH_LENGTH (fragp->fr_subtype);
-
-  if (uncond)
-    /* Length is the same for both JA and JAL.  */
-    length = 8;
-  else
+  switch (operand->type)
     {
-      if (RELAX_BRANCH_CONST (fragp->fr_subtype))
-        {
-          int64_t val = fragp->fr_offset;
-
-          if (val < -32768 || val > 32767)
-            length =  8 * 3;
-          else
-            length = 8;
-        }
-      else if (fragp->fr_symbol != NULL
-          && S_IS_DEFINED (fragp->fr_symbol)
-          && !S_IS_WEAK (fragp->fr_symbol)
-          && sec == S_GET_SEGMENT (fragp->fr_symbol))
-        {
-          offsetT val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
-
-          /* Convert to 64-bit words, minus one.  */
-          val = (val - 8) / 8;
-
-          /* See if it fits in the signed 16-bits field.  */
-          if (val < -32768 || val > 32767)
-            length = 8 * 3;
-          else
-            length = 8;
-        }
-      else
-        /* Use short version, and let the linker relax instead, if
-           appropriate and if supported.  */
-        length = 8;
-    }
-
-  if (update)
-    fragp->fr_subtype = RELAX_BRANCH_ENCODE (uncond,
-                                             RELAX_BRANCH_CONST (fragp->fr_subtype),
-                                             length);
-
-  return length;
-}
-
-/* Estimate the size of a variant frag before relaxing.  */
-
-int
-md_estimate_size_before_relax (fragS *fragp, asection *sec)
-{
-  return (fragp->fr_var = relaxed_branch_length (fragp, sec, true));
-}
-
-/* Read a BPF instruction word from BUF.  */
-
-static uint64_t
-read_insn_word (bfd_byte *buf)
-{
-  return bfd_getb64 (buf);
-}
-
-/* Write the given signed 16-bit value in the given BUFFER using the
-   target endianness.  */
-
-static void
-encode_int16 (int16_t value, char *buffer)
-{
-  uint16_t val = value;
-
-  if (target_big_endian)
-    {
-      buffer[0] = (val >> 8) & 0xff;
-      buffer[1] = val & 0xff;
-    }
-  else
-    {
-      buffer[1] = (val >> 8) & 0xff;
-      buffer[0] = val & 0xff;
-    }
-}
-
-/* Write the given signed 32-bit value in the given BUFFER using the
-   target endianness.  */
-
-static void
-encode_int32 (int32_t value, char *buffer)
-{
-  uint32_t val = value;
-
-  if (target_big_endian)
-    {
-      buffer[0] = (val >> 24) & 0xff;
-      buffer[1] = (val >> 16) & 0xff;
-      buffer[2] = (val >> 8) & 0xff;
-      buffer[3] = val & 0xff;
-    }
-  else
-    {
-      buffer[3] = (val >> 24) & 0xff;
-      buffer[2] = (val >> 16) & 0xff;
-      buffer[1] = (val >> 8) & 0xff;
-      buffer[0] = value & 0xff;
+    case BPF_OPERAND_IMM64:
+      return BFD_RELOC_BPF_64;
+    case BPF_OPERAND_DISP32:
+      fixP->fx_pcrel = 1;
+      return BFD_RELOC_BPF_DISP32;
+    default:
+      break;
     }
+  return BFD_RELOC_NONE;
 }
-
-/* Write a BPF instruction to BUF.  */
-
-static void
-write_insn_bytes (bfd_byte *buf, char *bytes)
-{
-  int i;
-
-  for (i = 0; i < 8; ++i)
-    md_number_to_chars ((char *) buf + i, (valueT) bytes[i], 1);
-}
-
+\f
 /* *FRAGP has been relaxed to its final size, and now needs to have
    the bytes inside it modified to conform to the new size.
 
@@ -519,258 +348,35 @@ write_insn_bytes (bfd_byte *buf, char *bytes)
 void
 md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
                 segT sec ATTRIBUTE_UNUSED,
-                fragS *fragp ATTRIBUTE_UNUSED)
+                fragS *fragP ATTRIBUTE_UNUSED)
 {
-  bfd_byte *buf = (bfd_byte *) fragp->fr_literal + fragp->fr_fix;
-  expressionS exp;
-  fixS *fixp;
-  bpf_insn_word word;
-  int disp_is_known = 0;
-  int64_t disp_to_target = 0;
-
-  uint64_t code;
-
-  gas_assert (RELAX_BRANCH_P (fragp->fr_subtype));
-
-  /* Expression to be used in any resulting relocation in the relaxed
-     instructions.  */
-  exp.X_op = O_symbol;
-  exp.X_add_symbol = fragp->fr_symbol;
-  exp.X_add_number = fragp->fr_offset;
-
-  gas_assert (fragp->fr_var == RELAX_BRANCH_LENGTH (fragp->fr_subtype));
-
-  /* Read an instruction word from the instruction to be relaxed, and
-     get the code.  */
-  word = read_insn_word (buf);
-  code = (word >> 60) & 0xf;
-
-  /* Determine whether the 16-bit displacement to the target is known
-     at this point.  */
-  if (RELAX_BRANCH_CONST (fragp->fr_subtype))
-    {
-      disp_to_target = fragp->fr_offset;
-      disp_is_known = 1;
-    }
-  else if (fragp->fr_symbol != NULL
-           && S_IS_DEFINED (fragp->fr_symbol)
-           && !S_IS_WEAK (fragp->fr_symbol)
-           && sec == S_GET_SEGMENT (fragp->fr_symbol))
-    {
-      offsetT val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
-      /* Convert to 64-bit blocks minus one.  */
-      disp_to_target = (val - 8) / 8;
-      disp_is_known = 1;
-    }
-
-  /* The displacement should fit in a signed 32-bit number.  */
-  if (disp_is_known && signed_overflow (disp_to_target, 32))
-    as_bad_where (fragp->fr_file, fragp->fr_line,
-                  _("signed instruction operand out of range, shall fit in 32 bits"));
-
-  /* Now relax particular jump instructions.  */
-  if (code == BPF_CODE_JA)
-    {
-      /* Unconditional jump.
-         JA d16 -> JAL d32  */
-
-      gas_assert (RELAX_BRANCH_UNCOND (fragp->fr_subtype));
-
-      if (disp_is_known)
-        {
-          if (disp_to_target >= -32768 && disp_to_target <= 32767)
-            {
-              /* 16-bit disp is known and in range.  Install a fixup
-                 for the disp16 if the branch value is not constant.
-                 This will be resolved by the assembler and units
-                 converted.  */
-
-              if (!RELAX_BRANCH_CONST (fragp->fr_subtype))
-                {
-                  /* Install fixup for the JA.  */
-                  reloc_howto_type *reloc_howto
-                    = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_DISP16);
-                  if (!reloc_howto)
-                    abort();
-
-                  fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
-                                      bfd_get_reloc_size (reloc_howto),
-                                      &exp,
-                                      reloc_howto->pc_relative,
-                                      BFD_RELOC_BPF_DISP16);
-                  fixp->fx_file = fragp->fr_file;
-                  fixp->fx_line = fragp->fr_line;
-                }
-            }
-          else
-            {
-              /* 16-bit disp is known and not in range.  Turn the JA
-                 into a JAL with a 32-bit displacement.  */
-              char bytes[8];
-
-              bytes[0] = ((BPF_CLASS_JMP32|BPF_CODE_JA|BPF_SRC_K) >> 56) & 0xff;
-              bytes[1] = (word >> 48) & 0xff;
-              bytes[2] = 0; /* disp16 high */
-              bytes[3] = 0; /* disp16 lo */
-              encode_int32 ((int32_t) disp_to_target, bytes + 4);
-
-              write_insn_bytes (buf, bytes);
-            }
-        }
-      else
-        {
-          /* The displacement to the target is not known.  Do not
-             relax.  The linker will maybe do it if it chooses to.  */
-
-          reloc_howto_type *reloc_howto = NULL;
-
-          gas_assert (!RELAX_BRANCH_CONST (fragp->fr_subtype));
-
-          /* Install fixup for the JA.  */
-          reloc_howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_DISP16);
-          if (!reloc_howto)
-            abort ();
-
-          fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
-                              bfd_get_reloc_size (reloc_howto),
-                              &exp,
-                              reloc_howto->pc_relative,
-                              BFD_RELOC_BPF_DISP16);
-          fixp->fx_file = fragp->fr_file;
-          fixp->fx_line = fragp->fr_line;
-        }
-
-      buf += 8;
-    }
-  else
-    {
-      /* Conditional jump.
-         JXX d16 -> JXX +1; JA +1; JAL d32 */
-
-      gas_assert (!RELAX_BRANCH_UNCOND (fragp->fr_subtype));
-
-      if (disp_is_known)
-        {
-          if (disp_to_target >= -32768 && disp_to_target <= 32767)
-            {
-              /* 16-bit disp is known and in range.  Install a fixup
-                 for the disp16 if the branch value is not constant.
-                 This will be resolved by the assembler and units
-                 converted.  */
-
-              if (!RELAX_BRANCH_CONST (fragp->fr_subtype))
-                {
-                  /* Install fixup for the branch.  */
-                  reloc_howto_type *reloc_howto
-                    = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_DISP16);
-                  if (!reloc_howto)
-                    abort();
-
-                  fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
-                                      bfd_get_reloc_size (reloc_howto),
-                                      &exp,
-                                      reloc_howto->pc_relative,
-                                      BFD_RELOC_BPF_DISP16);
-                  fixp->fx_file = fragp->fr_file;
-                  fixp->fx_line = fragp->fr_line;
-                }
-
-              buf += 8;
-            }
-          else
-            {
-              /* 16-bit disp is known and not in range.  Turn the JXX
-                 into a sequence JXX +1; JA +1; JAL d32.  */
-
-              char bytes[8];
-
-              /* First, set the 16-bit offset in the current
-                 instruction to 1.  */
-
-              if (target_big_endian)
-                bfd_putb16 (1, buf + 2);
-              else
-                bfd_putl16 (1, buf + 2);
-              buf += 8;
-
-              /* Then, write the JA + 1  */
-
-              bytes[0] = 0x05; /* JA */
-              bytes[1] = 0x0;
-              encode_int16 (1, bytes + 2);
-              bytes[4] = 0x0;
-              bytes[5] = 0x0;
-              bytes[6] = 0x0;
-              bytes[7] = 0x0;
-              write_insn_bytes (buf, bytes);
-              buf += 8;
-
-              /* Finally, write the JAL to the target. */
-
-              bytes[0] = ((BPF_CLASS_JMP32|BPF_CODE_JA|BPF_SRC_K) >> 56) & 0xff;
-              bytes[1] = 0;
-              bytes[2] = 0;
-              bytes[3] = 0;
-              encode_int32 ((int32_t) disp_to_target, bytes + 4);
-              write_insn_bytes (buf, bytes);
-              buf += 8;
-            }
-        }
-      else
-        {
-          /* The displacement to the target is not known.  Do not
-             relax.  The linker will maybe do it if it chooses to.  */
-
-          reloc_howto_type *reloc_howto = NULL;
-
-          gas_assert (!RELAX_BRANCH_CONST (fragp->fr_subtype));
-
-          /* Install fixup for the conditional jump.  */
-          reloc_howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_DISP16);
-          if (!reloc_howto)
-            abort ();
-
-          fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal,
-                              bfd_get_reloc_size (reloc_howto),
-                              &exp,
-                              reloc_howto->pc_relative,
-                              BFD_RELOC_BPF_DISP16);
-          fixp->fx_file = fragp->fr_file;
-          fixp->fx_line = fragp->fr_line;
-          buf += 8;
-        }
-    }
-
-  gas_assert (buf == (bfd_byte *)fragp->fr_literal
-              + fragp->fr_fix + fragp->fr_var);
+  as_fatal (_("convert_frag called"));
+}
 
-  fragp->fr_fix += fragp->fr_var;
+int
+md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
+                               segT segment ATTRIBUTE_UNUSED)
+{
+  as_fatal (_("estimate_size_before_relax called"));
+  return 0;
 }
 
 \f
-/* Apply a fixS (fixup of an instruction or data that we didn't have
-   enough info to complete immediately) to the data in a frag.  */
-
 void
-md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 {
-  char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
-
-  switch (fixP->fx_r_type)
+  /* Some fixups for instructions require special attention.  This is
+     handled in the code block below.  */
+  if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
     {
-    case BFD_RELOC_BPF_DISP16:
-      /* Convert from bytes to number of 64-bit words to the target,
-         minus one.  */
-      *valP = (((long) (*valP)) - 8) / 8;
-      break;
-    case BFD_RELOC_BPF_DISPCALL32:
-    case BFD_RELOC_BPF_DISP32:
-      /* Convert from bytes to number of 64-bit words to the target,
-         minus one.  */
-      *valP = (((long) (*valP)) - 8) / 8;
+      int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
+      const CGEN_OPERAND *operand = cgen_operand_lookup_by_num (gas_cgen_cpu_desc,
+                                                                opindex);
+      char *where;
 
-      if (fixP->fx_r_type == BFD_RELOC_BPF_DISPCALL32)
+      switch (operand->type)
         {
+        case BPF_OPERAND_DISP32:
           /* eBPF supports two kind of CALL instructions: the so
              called pseudo calls ("bpf to bpf") and external calls
              ("bpf to kernel").
@@ -790,852 +396,1522 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 
              Note that the CALL instruction has only one operand, so
              this code is executed only once per instruction.  */
-          md_number_to_chars (where + 1, target_big_endian ? 0x01 : 0x10, 1);
-        }
-      break;
-    case BFD_RELOC_16_PCREL:
-      /* Convert from bytes to number of 64-bit words to the target,
-         minus one.  */
-      *valP = (((long) (*valP)) - 8) / 8;
-      break;
-    default:
-      break;
-    }
-
-  if (fixP->fx_addsy == (symbolS *) NULL)
-    fixP->fx_done = 1;
-
-  if (fixP->fx_done)
-    {
-      /* We're finished with this fixup.  Install it because
-        bfd_install_relocation won't be called to do it.  */
-      switch (fixP->fx_r_type)
-       {
-       case BFD_RELOC_8:
-         md_number_to_chars (where, *valP, 1);
-         break;
-       case BFD_RELOC_16:
-         md_number_to_chars (where, *valP, 2);
-         break;
-       case BFD_RELOC_32:
-         md_number_to_chars (where, *valP, 4);
-         break;
-       case BFD_RELOC_64:
-         md_number_to_chars (where, *valP, 8);
-         break;
-        case BFD_RELOC_BPF_DISP16:
-          md_number_to_chars (where + 2, (uint16_t) *valP, 2);
+          where = fixP->fx_frag->fr_literal + fixP->fx_where + 1;
+          where[0] = target_big_endian ? 0x01 : 0x10;
+          /* Fallthrough.  */
+        case BPF_OPERAND_DISP16:
+          /* The PC-relative displacement fields in jump instructions
+             shouldn't be in bytes.  Instead, they hold the number of
+             64-bit words to the target, _minus one_.  */ 
+          *valP = (((long) (*valP)) - 8) / 8;
           break;
-        case BFD_RELOC_BPF_DISP32:
-        case BFD_RELOC_BPF_DISPCALL32:
-          md_number_to_chars (where + 4, (uint32_t) *valP, 4);
-          break;
-        case BFD_RELOC_16_PCREL:
-          md_number_to_chars (where + 2, (uint32_t) *valP, 2);
+        default:
           break;
-       default:
-         as_bad_where (fixP->fx_file, fixP->fx_line,
-                       _("internal error: can't install fix for reloc type %d (`%s')"),
-                       fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type));
-         break;
-       }
+        }
     }
 
-  /* Tuck `value' away for use by tc_gen_reloc.
-     See the comment describing fx_addnumber in write.h.
-     This field is misnamed (or misused :-).  */
-  fixP->fx_addnumber = *valP;
+  /* And now invoke CGEN's handler, which will eventually install
+     *valP into the corresponding operand.  */
+  gas_cgen_md_apply_fix (fixP, valP, seg);
 }
 
-\f
-/* Instruction writing routines.  */
+/*
+  The BPF pseudo grammar:
+
+       instruction  : bpf_alu_insn
+                    | bpf_alu32_insn
+                    | bpf_jump_insn
+                    | bpf_load_store_insn
+                    | bpf_load_store32_insn
+                    | bpf_non_generic_load
+                    | bpf_endianness_conv_insn
+                    | bpf_64_imm_load_insn
+                    | bpf_atomic_insn
+                    ;
+
+       bpf_alu_insn : BPF_REG bpf_alu_operator register_or_imm32
+                    ;
+
+       bpf_alu32_insn : BPF_REG32 bpf_alu_operator register32_or_imm32
+                      ;
+
+       bpf_jump_insn  : BPF_JA offset
+                      | IF BPF_REG bpf_jump_operator register_or_imm32 BPF_JA offset
+                      | IF BPF_REG32 bpf_jump_operator register_or_imm32 BPF_JA offset
+                      | BPF_CALL offset
+                      | BPF_EXIT
+                      ;
+
+       bpf_load_store_insn  : BPF_REG CHR_EQUAL bpf_size_cast BPF_CHR_OPEN_BR \
+                              register_and_offset BPF_CHR_CLSE_BR
+                            | bpf_size_cast register_and_offset CHR_EQUAL BPF_REG
+                            ;
+
+       bpf_load_store32_insn  : BPF_REG CHR_EQUAL bpf_size_cast BPF_CHR_OPEN_BR \
+                                register32_and_offset BPF_CHR_CLSE_BR
+                              | bpf_size_cast register_and_offset CHR_EQUAL BPF_REG32
+                            ;
+
+       bpf_non_generic_load : BPF_REG_R0 CHR_EQUAL bpf_size_cast BPF_LD BPF_CHR_OPEN_BR \
+                              imm32 BPF_CHR_CLSE_BR
+                            ;
+
+       bpf_endianness_conv_insn : BPF_REG_N bpf_endianness_mnem BPF_REG_N
+                                ;
+
+       bpf_64_imm_load_insn : BPF_REG imm64 BPF_LL
+                            ;
+
+       bpf_atomic_insn : BPF_LOCK bpf_size_cast_32_64 register_and_offset BPF_ADD BPF_REG
+
+       register_and_offset : BPF_CHR_OPEN_BR BPF_REG offset BPF_CHR_CLSE_BR
+                           ;
+
+       register32_and_offset : BPF_CHR_OPEN_BR BPF_REG32 offset BPF_CHR_CLSE_BR
+                             ;
+
+       bpf_size_cast : CHR_START BPF_CHR_OPEN_BR bpf_size CHR_START BPF_CHR_CLSE_BR
+                     ;
+
+       bpf_size_cast_32_64 : CHR_START BPF_CHR_OPEN_BR bpf_size_cast_32_64 CHR_STAR BPF_CHR_CLSE_BR
+                           ;
+
+       bpf_size_32_64 : BPF_CAST_U32
+                      | BPF_CAST_U64
+                      ;
+
+       bpf_size  : BPF_CAST_U8
+                 | BPF_CAST_U16
+                 | BPF_CAST_U32
+                 | BPF_CAST_U64
+                 ;
+
+       bpf_jump_operator : BPF_JEQ
+                         | BPF_JGT
+                         | BPF_JGE
+                         | BPF_JNE
+                         | BPF_JSGT
+                         | BPF_JSGE
+                         | BPF_JLT
+                         | BPF_JLE
+                         | BPF_JSLT
+                         | BPF_JSLE
+                         ;
+
+       bpf_alu_operator : BPF_ADD
+                        | BPF_SUB
+                        | BPF_MUL
+                        | BPF_DIV
+                        | BPF_OR
+                        | BPF_AND
+                        | BPF_LSH
+                        | BPF_RSH
+                        | BPF_NEG
+                        | BPF_MOD
+                        | BPF_XOR
+                        | BPF_ARSH
+                        | CHR_EQUAL
+                        ;
+
+       bpf_endianness_mnem : BPF_LE16
+                           | BPF_LE32
+                           | BPF_LE64
+                           | BPF_BE16
+                           | BPF_BE32
+                           | BPF_BE64
+                           ;
+
+       offset : BPF_EXPR
+              | BPF_SYMBOL
+              ;
+
+       register_or_imm32 : BPF_REG
+                         | expression
+                         ;
+
+       register32_or_imm32 : BPF_REG32
+                           | expression
+                           ;
+
+       imm32 : BPF_EXPR
+             | BPF_SYMBOL
+             ;
+
+       imm64 : BPF_EXPR
+             | BPF_SYMBOL
+             ;
+
+       register_or_expression : BPF_EXPR
+                              | BPF_REG
+                              ;
+
+       BPF_EXPR : GAS_EXPR
+
+*/
+
+enum bpf_token_type
+  {
+    /* Keep grouped to quickly access. */
+    BPF_ADD,
+    BPF_SUB,
+    BPF_MUL,
+    BPF_DIV,
+    BPF_OR,
+    BPF_AND,
+    BPF_LSH,
+    BPF_RSH,
+    BPF_MOD,
+    BPF_XOR,
+    BPF_MOV,
+    BPF_ARSH,
+    BPF_NEG,
+
+    BPF_REG,
+
+    BPF_IF,
+    BPF_GOTO,
+
+    /* Keep grouped to quickly access.  */
+    BPF_JEQ,
+    BPF_JGT,
+    BPF_JGE,
+    BPF_JLT,
+    BPF_JLE,
+    BPF_JSET,
+    BPF_JNE,
+    BPF_JSGT,
+    BPF_JSGE,
+    BPF_JSLT,
+    BPF_JSLE,
+
+    BPF_SYMBOL,
+    BPF_CHR_CLSE_BR,
+    BPF_CHR_OPEN_BR,
+
+    /* Keep grouped to quickly access.  */
+    BPF_CAST_U8,
+    BPF_CAST_U16,
+    BPF_CAST_U32,
+    BPF_CAST_U64,
+
+    /* Keep grouped to quickly access.  */
+    BPF_LE16,
+    BPF_LE32,
+    BPF_LE64,
+    BPF_BE16,
+    BPF_BE32,
+    BPF_BE64,
+
+    BPF_LOCK,
+
+    BPF_IND_CALL,
+    BPF_LD,
+    BPF_LL,
+    BPF_EXPR,
+    BPF_UNKNOWN,
+  };
+
+static int
+valid_expr (const char *e, const char **end_expr)
+{
+  invalid_expression = NULL;
+  char *hold = input_line_pointer;
+  expressionS exp;
 
-/* Encode a BPF instruction in the given buffer BYTES.  Non-constant
-   immediates are encoded as zeroes.  */
+  input_line_pointer = (char *) e;
+  deferred_expression  (&exp);
+  *end_expr = input_line_pointer;
+  input_line_pointer = hold;
 
-static void
-encode_insn (struct bpf_insn *insn, char *bytes, int relaxed)
+  return invalid_expression == NULL;
+}
+
+static char *
+build_bpf_non_generic_load (char *src, enum bpf_token_type cast,
+                           const char *imm32)
 {
-  uint8_t src, dst;
+  char *bpf_insn;
+  static const char *cast_rw[] = {"b", "h", "w", "dw"};
+
+  bpf_insn = xasprintf ("%s%s%s %s%s%s%s",
+                       "ld",
+                       src ? "ind" : "abs",
+                       cast_rw[cast - BPF_CAST_U8],
+                       src ? "%" : "",
+                       src ? src : "",
+                       src ? "," : "",
+                       imm32);
+  return bpf_insn;
+}
 
-  /* Zero all the bytes.  */
-  memset (bytes, 0, 16);
+static char *
+build_bpf_atomic_insn (char *dst, char *src,
+                      enum bpf_token_type atomic_insn,
+                      enum bpf_token_type cast,
+                      const char *offset)
+{
+  char *bpf_insn;
+  static const char *cast_rw[] = {"w", "dw"};
+  static const char *mnem[] = {"xadd"};
+
+  bpf_insn = xasprintf ("%s%s [%%%s%s%s],%%%s", mnem[atomic_insn - BPF_ADD],
+                       cast_rw[cast - BPF_CAST_U32], dst,
+                       *offset != '+' ? "+" : "",
+                       offset, src);
+  return bpf_insn;
+}
 
-  /* First encode the opcodes.  Note that we have to handle the
-     endianness groups of the BPF instructions: 8 | 4 | 4 | 16 |
-     32. */
-  if (target_big_endian)
-    {
-      /* code */
-      bytes[0] = (insn->opcode >> 56) & 0xff;
-      /* regs */
-      bytes[1] = (insn->opcode >> 48) & 0xff;
-      /* offset16 */
-      bytes[2] = (insn->opcode >> 40) & 0xff;
-      bytes[3] = (insn->opcode >> 32) & 0xff;
-      /* imm32 */
-      bytes[4] = (insn->opcode >> 24) & 0xff;
-      bytes[5] = (insn->opcode >> 16) & 0xff;
-      bytes[6] = (insn->opcode >> 8) & 0xff;
-      bytes[7] = insn->opcode & 0xff;
-    }
-  else
+static char *
+build_bpf_jmp_insn (char *dst, char *src,
+                   char *imm32, enum bpf_token_type op,
+                   const char *sym, const char *offset)
+{
+  char *bpf_insn;
+  static const char *mnem[] =
     {
-      /* code */
-      bytes[0] = (insn->opcode >> 56) & 0xff;
-      /* regs */
-      bytes[1] = (((((insn->opcode >> 48) & 0xff) & 0xf) << 4)
-                  | (((insn->opcode >> 48) & 0xff) & 0xf));
-      /* offset16 */
-      bytes[3] = (insn->opcode >> 40) & 0xff;
-      bytes[2] = (insn->opcode >> 32) & 0xff;
-      /* imm32 */
-      bytes[7] = (insn->opcode >> 24) & 0xff;
-      bytes[6] = (insn->opcode >> 16) & 0xff;
-      bytes[5] = (insn->opcode >> 8) & 0xff;
-      bytes[4] = insn->opcode & 0xff;
-    }
-
-  /* Now the registers.  */
-  src = insn->has_src ? insn->src : 0;
-  dst = insn->has_dst ? insn->dst : 0;
+      "jeq", "jgt", "jge", "jlt",
+      "jle", "jset", "jne", "jsgt",
+      "jsge", "jslt", "jsle"
+    };
+
+  const char *in32 = (*dst == 'w' ? "32" : "");
+
+  *dst = 'r';
+  if (src)
+    *src = 'r';
+
+  bpf_insn = xasprintf ("%s%s %%%s,%s%s,%s",
+                       mnem[op - BPF_JEQ], in32, dst,
+                       src ? "%" : "",
+                       src ? src : imm32,
+                       offset ? offset : sym);
+  return bpf_insn;
+}
 
-  if (target_big_endian)
-    bytes[1] = ((dst & 0xf) << 4) | (src & 0xf);
+static char *
+build_bpf_arithm_insn (char *dst, char *src,
+                      int load64, const char *imm32,
+                      enum bpf_token_type type)
+{
+  char *bpf_insn;
+  static const char *mnem[] =
+    {
+      "add", "sub", "mul", "div",
+      "or", "and", "lsh", "rsh",
+      "mod", "xor", "mov", "arsh",
+      "neg",
+    };
+  const char *in32 = (*dst == 'w' ? "32" : "");
+
+  *dst = 'r';
+  if (src)
+    *src = 'r';
+
+  if (type == BPF_NEG)
+    bpf_insn = xasprintf ("%s%s %%%s", mnem[type - BPF_ADD], in32, dst);
+  else if (load64)
+    bpf_insn = xasprintf ("%s %%%s,%s", "lddw", dst, imm32);
   else
-    bytes[1] = ((src & 0xf) << 4) | (dst & 0xf);
+    bpf_insn = xasprintf ("%s%s %%%s,%s%s", mnem[type - BPF_ADD],
+                         in32, dst,
+                         src ? "%" : "",
+                         src ? src: imm32);
+  return bpf_insn;
+}
 
-  /* Now the immediates that are known to be constant.  */
+static char *
+build_bpf_endianness (char *dst, enum bpf_token_type endianness)
+{
+  char *bpf_insn;
+  static const char *size[] = {"16", "32", "64"};
+  int be = 1;
+
+  if (endianness == BPF_LE16
+      || endianness == BPF_LE32
+      || endianness == BPF_LE64)
+    be = 0;
+  else
+    gas_assert (endianness == BPF_BE16 || endianness == BPF_BE32 || endianness == BPF_BE64);
 
-  if (insn->has_imm32 && insn->imm32.X_op == O_constant)
-    {
-      int64_t imm = insn->imm32.X_add_number;
+  bpf_insn = xasprintf ("%s %%%s,%s", be ? "endbe" : "endle",
+                       dst, be ? size[endianness - BPF_BE16] : size[endianness - BPF_LE16]);
+  return bpf_insn;
+}
 
-      if (signed_overflow (imm, 32))
-        as_bad (_("signed immediate out of range, shall fit in 32 bits"));
-      else
-        encode_int32 (insn->imm32.X_add_number, bytes + 4);        
-    }
+static char *
+build_bpf_load_store_insn (char *dst, char *src,
+                          enum bpf_token_type cast,
+                          const char *offset, int isload)
+{
+  char *bpf_insn;
+  static const char *cast_rw[] = {"b", "h", "w", "dw"};
+
+  *dst = *src = 'r';
+  if (isload)
+    bpf_insn = xasprintf ("%s%s %%%s,[%%%s%s%s]", "ldx",
+                         cast_rw[cast - BPF_CAST_U8], dst, src,
+                         *offset != '+' ? "+" : "",
+                         offset);
+  else
+    bpf_insn = xasprintf ("%s%s [%%%s%s%s],%%%s", "stx",
+                         cast_rw[cast - BPF_CAST_U8], dst,
+                         *offset != '+' ? "+" : "",
+                         offset, src);
+  return bpf_insn;
+}
 
-  if (insn->has_disp32 && insn->disp32.X_op == O_constant)
+static int
+look_for_reserved_word (const char *token, enum bpf_token_type *type)
+{
+  int i;
+  static struct
+  {
+    const char *name;
+    enum bpf_token_type type;
+  } reserved_words[] =
     {
-      int64_t disp = insn->disp32.X_add_number;
-
-      if (signed_overflow (disp, 32))
-        as_bad (_("signed pc-relative offset out of range, shall fit in 32 bits"));
-      else
-        encode_int32 (insn->disp32.X_add_number, bytes + 4);
-    }
+      {
+       .name = "if",
+       .type = BPF_IF
+      },
+      {
+       .name = "goto",
+       .type = BPF_GOTO
+      },
+      {
+       .name = "le16",
+       .type = BPF_LE16
+      },
+      {
+       .name = "le32",
+       .type = BPF_LE32
+      },
+      {
+       .name = "le64",
+       .type = BPF_LE64
+      },
+      {
+       .name = "be16",
+       .type = BPF_BE16
+      },
+      {
+       .name = "be32",
+       .type = BPF_BE32
+      },
+      {
+       .name = "be64",
+       .type = BPF_BE64
+       },
+      {
+       .name = "lock",
+       .type = BPF_LOCK
+      },
+      {
+       .name = "callx",
+       .type = BPF_IND_CALL
+      },
+      {
+       .name = "skb",
+       .type = BPF_LD
+      },
+      {
+       .name = "ll",
+       .type = BPF_LL
+      },
+      {
+       .name = NULL,
+      }
+    };
+
+  for (i = 0; reserved_words[i].name; ++i)
+    if (*reserved_words[i].name == *token
+       && !strcmp (reserved_words[i].name, token))
+      {
+       *type = reserved_words[i].type;
+       return 1;
+      }
 
-  if (insn->has_offset16 && insn->offset16.X_op == O_constant)
-    {
-      int64_t offset = insn->offset16.X_add_number;
+  return 0;
+}
 
-      if (signed_overflow (offset, 16))
-        as_bad (_("signed pc-relative offset out of range, shall fit in 16 bits"));
-      else
-        encode_int16 (insn->offset16.X_add_number, bytes + 2);
-    }
+static int
+is_register (const char *token, int len)
+{
+  if (token[0] == 'r' || token[0] == 'w')
+    if ((len == 2 && isdigit (token[1]))
+       || (len == 3 && token[1] == '1' && token[2] == '0'))
+      return 1;
 
-  if (insn->has_disp16 && insn->disp16.X_op == O_constant)
-    {
-      int64_t disp = insn->disp16.X_add_number;
+  return 0;
+}
 
-      if (!relaxed && signed_overflow (disp, 16))
-        as_bad (_("signed pc-relative offset out of range, shall fit in 16 bits"));
-      else
-        encode_int16 (insn->disp16.X_add_number, bytes + 2);
-    }
+static enum bpf_token_type
+is_cast (const char *token)
+{
+  static const char *cast_rw[] = {"u8", "u16", "u32", "u64"};
+  unsigned int i;
 
-  if (insn->has_imm64 && insn->imm64.X_op == O_constant)
-    {
-      uint64_t imm64 = insn->imm64.X_add_number;
+  for (i = 0; i < ARRAY_SIZE (cast_rw); ++i)
+    if (!strcmp (token, cast_rw[i]))
+      return BPF_CAST_U8 + i;
 
-      if (target_big_endian)
-        {
-          bytes[12] = (imm64 >> 56) & 0xff;
-          bytes[13] = (imm64 >> 48) & 0xff;
-          bytes[14] = (imm64 >> 40) & 0xff;
-          bytes[15] = (imm64 >> 32) & 0xff;
-          bytes[4] = (imm64 >> 24) & 0xff;
-          bytes[5] = (imm64 >> 16) & 0xff;
-          bytes[6] = (imm64 >> 8) & 0xff;
-          bytes[7] = imm64 & 0xff;
-        }
-      else
-        {
-          bytes[15] = (imm64 >> 56) & 0xff;
-          bytes[14] = (imm64 >> 48) & 0xff;
-          bytes[13] = (imm64 >> 40) & 0xff;
-          bytes[12] = (imm64 >> 32) & 0xff;
-          bytes[7] = (imm64 >> 24) & 0xff;
-          bytes[6] = (imm64 >> 16) & 0xff;
-          bytes[5] = (imm64 >> 8) & 0xff;
-          bytes[4] = imm64 & 0xff;
-        }
-    }
+  return BPF_UNKNOWN;
 }
 
-/* Install the fixups in INSN in their proper location in the
-   specified FRAG at the location pointed by WHERE.  */
-
-static void
-install_insn_fixups (struct bpf_insn *insn, fragS *frag, long where)
+static enum bpf_token_type
+get_token (const char **insn, char *token, size_t *tlen)
 {
-  if (insn->has_imm64)
+#define GET()                                  \
+  (*str == '\0'                                        \
+   ? EOF                                       \
+   : *(unsigned char *)(str++))
+
+#define UNGET() (--str)
+
+#define START_EXPR()                          \
+  do                                          \
+    {                                         \
+      if (expr == NULL)                               \
+       expr = str - 1;                        \
+    } while (0)
+
+#define SCANNER_SKIP_WHITESPACE()              \
+  do                                           \
+    {                                          \
+      do                                       \
+       ch = GET ();                            \
+      while (ch != EOF                         \
+            && ((ch) == ' ' || (ch) == '\t')); \
+      if (ch != EOF)                           \
+       UNGET ();                               \
+    } while (0)
+
+  const char *str = *insn;
+  int ch, ch2 = 0;
+  enum bpf_token_type ttype = BPF_UNKNOWN;
+  size_t len = 0;
+  const char *expr = NULL;
+  const char *end_expr = NULL;
+  int state = 0;
+  int return_token = 0;
+
+  while (1)
     {
-      switch (insn->imm64.X_op)
-        {
-        case O_symbol:
-        case O_subtract:
-        case O_add:
-          {
-            reloc_howto_type *reloc_howto;
-            int size;
-
-            reloc_howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_64);
-            if (!reloc_howto)
-              abort ();
-
-            size = bfd_get_reloc_size (reloc_howto);
-
-            fix_new_exp (frag, where,
-                         size, &insn->imm64, reloc_howto->pc_relative,
-                         BFD_RELOC_BPF_64);
-            break;
-          }
-        case O_constant:
-          /* Already handled in encode_insn.  */
-          break;
-        default:
-          abort ();
-        }
-    }
+      ch = GET ();
 
-  if (insn->has_imm32)
-    {
-      switch (insn->imm32.X_op)
-        {
-        case O_symbol:
-        case O_subtract:
-        case O_add:
-        case O_uminus:
-          {
-            reloc_howto_type *reloc_howto;
-            int size;
-
-            reloc_howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
-            if (!reloc_howto)
-              abort ();
-
-            size = bfd_get_reloc_size (reloc_howto);
-
-            fix_new_exp (frag, where + 4,
-                         size, &insn->imm32, reloc_howto->pc_relative,
-                         BFD_RELOC_32);
-            break;
-          }
-        case O_constant:
-          /* Already handled in encode_insn.  */
-          break;
-        default:
-          abort ();
-        }
-    }
+      if (ch == EOF || len > MAX_TOKEN_SZ)
+       break;
 
-  if (insn->has_disp32)
-    {
-      switch (insn->disp32.X_op)
-        {
-        case O_symbol:
-        case O_subtract:
-        case O_add:
-          {
-            reloc_howto_type *reloc_howto;
-            int size;
-            unsigned int bfd_reloc
-              = (insn->id == BPF_INSN_CALL
-                 ? BFD_RELOC_BPF_DISPCALL32
-                 : BFD_RELOC_BPF_DISP32);
-
-            reloc_howto = bfd_reloc_type_lookup (stdoutput, bfd_reloc);
-            if (!reloc_howto)
-              abort ();
-
-            size = bfd_get_reloc_size (reloc_howto);
-
-            fix_new_exp (frag, where,
-                         size, &insn->disp32, reloc_howto->pc_relative,
-                         bfd_reloc);
-            break;
-          }
-        case O_constant:
-          /* Already handled in encode_insn.  */
-          break;
-        default:
-          abort ();
-        }
-    }
+      switch (pseudoc_lex[(unsigned char) ch])
+       {
+       case LEX_IS_WHITESPACE:
+         SCANNER_SKIP_WHITESPACE ();
+         return_token = 1;
+
+         switch (state)
+           {
+           case 12: /* >' ' */
+             ttype = BPF_JGT;
+             break;
+
+           case 17: /* ==' ' */
+             ttype = BPF_JEQ;
+             break;
+
+           case 18: /* <' ' */
+             ttype = BPF_JLT;
+             break;
+
+           case 20: /* &' ' */
+             ttype = BPF_JSET;
+             break;
+
+           case 22:  /* s<' '*/
+             ttype = BPF_JSLT;
+             break;
+
+           case 14: /* s> ' ' */
+             ttype = BPF_JSGT;
+             break;
+
+           case 16: /* =' ' */
+             ttype = BPF_MOV;
+             break;
+
+           default:
+             return_token = 0;
+           }
+         break;
 
-  if (insn->has_offset16)
-    {
-      switch (insn->offset16.X_op)
-        {
-        case O_symbol:
-        case O_subtract:
-        case O_add:
-          {
-            reloc_howto_type *reloc_howto;
-            int size;
-
-            /* XXX we really need a new pc-rel offset in bytes
-               relocation for this.  */
-            reloc_howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_DISP16);
-            if (!reloc_howto)
-              abort ();
-
-            size = bfd_get_reloc_size (reloc_howto);
-
-            fix_new_exp (frag, where,
-                         size, &insn->offset16, reloc_howto->pc_relative,
-                         BFD_RELOC_BPF_DISP16);
-            break;
-          }
-        case O_constant:
-          /* Already handled in encode_insn.  */
-          break;
-        default:
-          abort ();
-        }
-    }
+       case LEX_IS_EXCLA:
+         token[len++] = ch;
+         state = 21;
+         break;
 
-  if (insn->has_disp16)
-    {
-      switch (insn->disp16.X_op)
-        {
-        case O_symbol:
-        case O_subtract:
-        case O_add:
-          {
-            reloc_howto_type *reloc_howto;
-            int size;
-
-            reloc_howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_DISP16);
-            if (!reloc_howto)
-              abort ();
-
-            size = bfd_get_reloc_size (reloc_howto);
-
-            fix_new_exp (frag, where,
-                         size, &insn->disp16, reloc_howto->pc_relative,
-                         BFD_RELOC_BPF_DISP16);
-            break;
-          }
-        case O_constant:
-          /* Already handled in encode_insn.  */
-          break;
-        default:
-          abort ();
-        }
-    }
+       case LEX_IS_ARITHM_OP:
+         if (state == 16)
+           {
+             /* ='-' is handle as '=' */
+             UNGET ();
+             ttype = BPF_MOV;
+             return_token = 1;
+             break;
+           }
+
+         START_EXPR();
+         token[len++] = ch;
+         switch (ch)
+           {
+#define BPF_ARITHM_OP(op, type)                        \
+             case (op):                        \
+               state = 6;                      \
+               ttype = (type);                 \
+               break;
+
+             BPF_ARITHM_OP('+', BPF_ADD);
+             BPF_ARITHM_OP('-', BPF_SUB);
+             BPF_ARITHM_OP('*', BPF_MUL);
+             BPF_ARITHM_OP('/', BPF_DIV);
+             BPF_ARITHM_OP('|', BPF_OR);
+             BPF_ARITHM_OP('%', BPF_MOD);
+             BPF_ARITHM_OP('^', BPF_XOR);
+
+           case '&':
+             state = 20; /* '&' */
+             break;
+
+           case '<':
+             switch (state)
+               {
+               case 0:
+                 state = 18; /* '<' */
+                 break;
+
+               case 18:
+                 state = 19; /* <'<' */
+                 break;
+
+               case 8:
+                 state = 22; /* s'<' */
+                 break;
+               }
+             break;
+
+           case '>':
+             switch (state)
+               {
+               case 0:
+                 state = 12; /* '>' */
+                 break;
+
+               case 12:
+                 state = 13; /* >'>' */
+                 break;
+
+               case 8:
+                 state = 14; /* s'>' */
+                 break;
+
+               case 14:
+                 state = 15; /* s>'>' */
+                 break;
+               }
+             break;
+           }
+         break;
 
-}
+       case LEX_IS_STAR:
+         switch (state)
+           {
+           case 0:
+             token[len++] = ch;
+             START_EXPR ();
+             state = 2; /* '*', It could be the fist cast char.  */
+             break;
+
+           case 16: /* ='*' Not valid token.  */
+             ttype = BPF_MOV;
+             return_token = 1;
+             UNGET ();
+             break;
+
+           case 4: /* *(uXX'*' */
+             token[len++] = ch;
+             state = 5;
+             break;
+           }
+         break;
 
-/* Add a new insn to the list of instructions.  */
+       case LEX_IS_OPEN_BR:
+         START_EXPR ();
+         token[len++] = ch;
+         return_token = 1;
+
+         switch (state)
+           {
+           case 2:
+             state = 3; /* *'(' second char of a cast or expr.  */
+             return_token = 0;
+             break;
+
+           case 6:
+             if (valid_expr (expr, &end_expr))
+               {
+                 len = end_expr - expr;
+                 memcpy (token, expr, len);
+                 ttype = BPF_EXPR;
+                 str = end_expr;
+               }
+             else
+               {
+                 len = 0;
+                 while (*invalid_expression)
+                   token[len++] = *invalid_expression++;
+
+                 token[len] = 0;
+                 ttype = BPF_UNKNOWN;
+               }
+             break;
+
+           default:
+             ttype = BPF_CHR_OPEN_BR;
+             SCANNER_SKIP_WHITESPACE ();
+             ch2 = GET ();
+
+             if ((isdigit (ch2) || ch2 == '(')
+                 && valid_expr (expr, &end_expr))
+               {
+                 len = end_expr - expr;
+                 memcpy (token, expr, len);
+                 ttype = BPF_EXPR;
+                 str = end_expr;
+               }
+             else
+               UNGET ();
+           }
+         break;
 
-static void
-add_fixed_insn (struct bpf_insn *insn)
-{
-  char *this_frag = frag_more (insn->size);
-  char bytes[16];
-  int i;
+       case LEX_IS_CLSE_BR:
+         token[len++] = ch;
 
-  /* First encode the known parts of the instruction, including
-     opcodes and constant immediates, and write them to the frag.  */
-  encode_insn (insn, bytes, 0 /* relax */);
-  for (i = 0; i < insn->size; ++i)
-    md_number_to_chars (this_frag + i, (valueT) bytes[i], 1);
+         if (state == 0)
+           {
+             ttype = BPF_CHR_CLSE_BR;
+             return_token = 1;
+           }
+         else if (state == 5) /* *(uXX*')'  */
+           return_token = 1;
+         break;
 
-  /* Now install the instruction fixups.  */
-  install_insn_fixups (insn, frag_now,
-                       this_frag - frag_now->fr_literal);
-}
+       case LEX_IS_EQUAL:
+         token[len++] = ch;
+         return_token = 1;
+
+         switch (state)
+           {
+           case 0:
+             state = 16; /* '=' */
+             return_token = 0;
+             break;
+
+           case 16:
+             state = 17; /* ='=' */
+             return_token = 0;
+             break;
+
+           case 2: /* *'=' */
+             ttype = BPF_MUL;
+             break;
+
+           case 10: /* s>>'=' */
+             ttype = BPF_ARSH;
+             break;
+
+           case 12: /* >'=' */
+             ttype = BPF_JGE;
+             break;
+
+           case 13: /* >>'=' */
+             ttype = BPF_RSH;
+             break;
+
+           case 14: /* s>'=' */
+             ttype = BPF_JSGE;
+             break;
+
+           case 15: /* s>>'=' */
+             ttype = BPF_ARSH;
+             break;
+
+           case 18: /* <'=' */
+             ttype = BPF_JLE;
+             break;
+
+           case 19: /* <<'=' */
+             ttype = BPF_LSH;
+             break;
+
+           case 20: /* &'=' */
+             ttype = BPF_AND;
+             break;
+
+           case 21: /* !'=' */
+             ttype = BPF_JNE;
+             break;
+
+           case 22: /* s<'=' */
+             ttype = BPF_JSLE;
+             break;
+           }
+         break;
+
+       case LEX_IS_SYMBOL_COMPONENT:
+         return_token = 1;
+
+         switch (state)
+           {
+           case 17: /* =='sym' */
+             ttype = BPF_JEQ;
+             break;
+
+           case 12: /* >'sym' */
+             ttype = BPF_JGT;
+             break;
+
+           case 18: /* <'sym' */
+             ttype = BPF_JLT;
+             break;
+
+           case 20: /* &'sym' */
+             ttype = BPF_JSET;
+             break;
+
+           case 14: /*s>'sym' */
+             ttype = BPF_JSGT;
+             break;
+
+           case 22:  /* s<'sym' */
+             ttype = BPF_JSLT;
+             break;
+
+           case 16: /* ='sym' */
+             ttype = BPF_MOV;
+             break;
+
+           default:
+             return_token = 0;
+           }
+
+         if (return_token)
+           {
+             UNGET ();
+             break;
+           }
+
+         START_EXPR ();
+         token[len++] = ch;
+
+         while ((ch2 = GET ()) != EOF)
+           {
+             int type;
+
+             type = pseudoc_lex[(unsigned char) ch2];
+             if (type != LEX_IS_SYMBOL_COMPONENT)
+               break;
+             token[len++] = ch2;
+           }
+
+         if (ch2 != EOF)
+           UNGET ();
+
+         if (state == 0)
+           {
+             if (len == 1 && ch == 's')
+               state = 8; /* signed instructions: 's' */
+             else
+               {
+                 ttype = BPF_SYMBOL;
+                 if (is_register (token, len))
+                   ttype = BPF_REG;
+                 else if (look_for_reserved_word (token, &ttype))
+                   ;
+                 else if ((pseudoc_lex[(unsigned char) *token] == LEX_IS_ARITHM_OP
+                           || *token == '(' || isdigit(*token))
+                          && valid_expr (expr, &end_expr))
+                   {
+                     len = end_expr - expr;
+                     token[len] = '\0';
+                     ttype = BPF_EXPR;
+                     str = end_expr;
+                   }
+
+                 return_token = 1;
+               }
+           }
+         else if (state == 3) /* *('sym' */
+           {
+             if ((ttype = is_cast (&token[2])) != BPF_UNKNOWN)
+               state = 4; /* *('uXX' */
+             else
+               {
+                 ttype = BPF_EXPR;
+                 return_token = 1;
+               }
+           }
+         else if (state == 6)
+           {
+             if (ttype == BPF_SUB) /* neg */
+               {
+                 if (is_register (&token[1], len - 1))
+                   ttype =  BPF_NEG;
+                 else if (valid_expr(expr, &end_expr))
+                   {
+                     len = end_expr - expr;
+                     memcpy(token, expr, len);
+                     ttype = BPF_EXPR;
+                     str = end_expr;
+                   }
+                 else
+                   {
+                     len = 0;
+                     while (*invalid_expression)
+                       token[len++] = *invalid_expression++;
+                     token[len] = 0;
+                     ttype = BPF_UNKNOWN;
+                   }
+               }
+             else if (valid_expr (expr, &end_expr))
+               {
+                 len = end_expr - expr;
+                 memcpy(token, expr, len);
+                 ttype = BPF_EXPR;
+                 str = end_expr;
+               }
+             else
+               ttype = BPF_UNKNOWN;
+
+             return_token = 1;
+           }
+         break;
+       }
 
-/* Add a new relaxable to the list of instructions.  */
+      if (return_token)
+       {
+         *tlen = len;
+         *insn = str;
+         break;
+       }
+    }
 
-static void
-add_relaxed_insn (struct bpf_insn *insn, expressionS *exp)
-{
-  char bytes[16];
-  int i;
-  char *this_frag;
-  unsigned worst_case = relaxed_branch_length (NULL, NULL, 0);
-  unsigned best_case = insn->size;
-
-  /* We only support relaxing branches, for the moment.  */
-  relax_substateT subtype
-    = RELAX_BRANCH_ENCODE (insn->id == BPF_INSN_JAR,
-                           exp->X_op == O_constant,
-                           worst_case);
-
-  frag_grow (worst_case);
-  this_frag = frag_more (0);
-
-  /* First encode the known parts of the instruction, including
-     opcodes and constant immediates, and write them to the frag.  */
-  encode_insn (insn, bytes, 1 /* relax */);
-  for (i = 0; i < insn->size; ++i)
-    md_number_to_chars (this_frag + i, (valueT) bytes[i], 1);
-
-  /* Note that instruction fixups will be applied once the frag is
-     relaxed, in md_convert_frag.  */
-  frag_var (rs_machine_dependent,
-            worst_case, best_case,
-            subtype, exp->X_add_symbol, exp->X_add_number /* offset */,
-            NULL);
+  return ttype;
+
+#undef GET
+#undef UNGET
+#undef START_EXPR
+#undef SCANNER_SKIP_WHITESPACE
+#undef BPF_ARITHM_OP
 }
 
-\f
-/* Parse an operand expression.  Returns the first character that is
-   not part of the expression, or NULL in case of parse error.
+/*
+  The parser represent a FSM for the grammar described above. So for example
+  the following rule:
 
-   See md_operand below to see how exp_parse_failed is used.  */
+     ` bpf_alu_insn : BPF_REG bpf_alu_operator register_or_imm32'
 
-static int exp_parse_failed = 0;
+  Is parser as follows:
 
-static char *
-parse_expression (char *s, expressionS *exp)
-{
-  char *saved_input_line_pointer = input_line_pointer;
-  char *saved_s = s;
+      1. It starts in state 0.
 
-  exp_parse_failed = 0;
-  input_line_pointer = s;
-  expression (exp);
-  s = input_line_pointer;
-  input_line_pointer = saved_input_line_pointer;
+      2. Consumes next token, e.g: `BPF_REG' and set `state' variable to a
+      particular state to helps to identify, in this case, that a register
+      token has been read, a comment surrounded by a single quote in the
+      pseudo-c token is added along with the new `state' value to indicate
+      what the scanner has read, e.g.:
 
-  switch (exp->X_op == O_absent || exp_parse_failed)
-    return NULL;
+          state = 6; // dst_reg = str_cast ( 'src_reg'
 
-  /* The expression parser may consume trailing whitespaces.  We have
-     to undo that since the instruction templates may be expecting
-     these whitespaces.  */
-  {
-    char *p;
-    for (p = s - 1; p >= saved_s && *p == ' '; --p)
-      --s;
-  }
+      So, in `state 6' the scanner has consumed: a destination register
+      (BPF_REG), an equal character (BPF_MOV), a cast token (BPF_CAST), an
+      open parenthesis (BPF_CHR_OPEN_BR) and the source register (BPF_REG).
 
-  return s;
-}
+      3. If the accumulated tokens represent a complete BPF pseudo-c syntax
+      instruction then, a validation of the terms is made, for example: if
+      the registers have the same sizes (32/64 bits), if a specific
+      destination register must be used, etc., after that, a builder:
+      build_bfp_{non_generic_load,atomic_insn,jmp_insn,arithm_insn,endianness,load_store_insn}
+      is invoked, internally, it translates the BPF pseudo-c instruction to
+      a BPF GAS instruction using the previous terms recollected by the
+      scanner.
 
-/* Parse a BPF register name and return the corresponding register
-   number.  Return NULL in case of parse error, or a pointer to the
-   first character in S that is not part of the register name.  */
+      4. If a successful build of BPF GAS instruction was done, a final
+      state is set to `ST_EOI' (End Of Instruction) meaning that is not
+      expecting for more tokens in such instruction.  Otherwise if the
+      conditions to calling builder are not satisfied an error is emitted
+      and `parse_err' is set.
+*/
 
 static char *
-parse_bpf_register (char *s, char rw, uint8_t *regno)
+bpf_pseudoc_to_normal_syntax (const char *str, char **errmsg)
 {
-  if (asm_dialect == DIALECT_NORMAL)
+#define syntax_err(format, ...)                                                \
+  do                                                                   \
+    {                                                                  \
+      if (! parse_err)                                                 \
+       {                                                               \
+         parse_err = 1;                                                \
+         errbuf = xasprintf (format, ##__VA_ARGS__);                   \
+       }                                                               \
+    } while (0)
+
+  enum bpf_token_type ttype;
+  enum bpf_token_type bpf_endianness = BPF_UNKNOWN,
+                     bpf_atomic_insn;
+  enum bpf_token_type bpf_jmp_op = BPF_JEQ; /* Arbitrary.  */
+  enum bpf_token_type bpf_cast = BPF_CAST_U8; /* Arbitrary.  */
+  enum bpf_token_type bpf_arithm_op = BPF_ADD; /* Arbitrary.  */
+  char *bpf_insn = NULL;
+  char *errbuf = NULL;
+  char src_reg[3] = {0};
+  char dst_reg[3] = {0};
+  char str_imm32[40] = {0};
+  char str_offset[40] = {0};
+  char str_symbol[MAX_TOKEN_SZ] = {0};
+  char token[MAX_TOKEN_SZ] = {0};
+  int state = 0;
+  int parse_err = 0;
+  size_t tlen;
+
+  while (*str)
     {
-      rw = 'r';
-      if (*s != '%')
-       return NULL;
-      s += 1;
-
-      if (*s == 'f' && *(s + 1) == 'p')
+      ttype = get_token (&str, token, &tlen);
+      if (ttype == BPF_UNKNOWN || state == ST_EOI)
        {
-         *regno = 10;
-         s += 2;
-         return s;
+         syntax_err ("unexpected token: '%s'", token);
+         break;
        }
-    }
 
-  if (*s != rw)
-    return NULL;
-  s += 1;
+      switch (ttype)
+       {
+       case BPF_UNKNOWN:
+       case BPF_LL:
+         break;
 
-  if (*s == '1')
-    {
-      if (*(s + 1) == '0')
-        {
-          *regno = 10;
-          s += 2;
-        }
-      else
-        {
-          *regno = 1;
-          s += 1;
-        }
-    }
-  else if (*s >= '0' && *s <= '9')
-    {
-      *regno = *s - '0';
-      s += 1;
-    }
+       case BPF_REG:
+         switch (state)
+           {
+           case 0:
+             memcpy (dst_reg, token, tlen);
+             state = 1; /* 'dst_reg' */
+             break;
+
+           case 3:
+             /* dst_reg bpf_op 'src_reg' */
+             memcpy (src_reg, token, tlen);
+             if (*dst_reg == *src_reg)
+               bpf_insn = build_bpf_arithm_insn (dst_reg, src_reg, 0,
+                                                 NULL, bpf_arithm_op);
+             else
+               {
+                 syntax_err ("different register sizes: '%s', '%s'",
+                             dst_reg, src_reg);
+                 break;
+               }
+             state = ST_EOI;
+             break;
+
+           case 5:
+             memcpy (src_reg, token, tlen);
+             state = 6; /* dst_reg = str_cast ( 'src_reg' */
+             break;
+
+           case 9:
+             memcpy (dst_reg, token, tlen);
+             state = 10; /* str_cast ( 'dst_reg' */
+             break;
+
+           case 11:
+             /* str_cast ( dst_reg offset ) = 'src_reg' */
+             memcpy (src_reg, token, tlen);
+             bpf_insn = build_bpf_load_store_insn (dst_reg, src_reg,
+                                                   bpf_cast, str_offset, 0);
+             state = ST_EOI;
+             break;
+
+           case 14:
+             memcpy (dst_reg, token, tlen);
+             state = 15; /* if 'dst_reg' */
+             break;
+
+           case 16:
+             memcpy (src_reg, token, tlen);
+             state = 17; /* if dst_reg jmp_op 'src_reg' */
+             break;
+
+           case 24:
+             /* dst_reg = endianness src_reg */
+             memcpy (src_reg, token, tlen);
+             if (*dst_reg == 'r' && !strcmp (dst_reg, src_reg))
+               bpf_insn = build_bpf_endianness (dst_reg, bpf_endianness);
+             else
+               syntax_err ("invalid operand for instruction: '%s'", token);
+
+             state = ST_EOI;
+             break;
+
+           case 28:
+             memcpy (dst_reg, token, tlen);
+             state = 29; /* lock str_cast ( 'dst_reg'  */
+             break;
+
+           case 32:
+             {
+               /* lock str_cast ( dst_reg offset ) atomic_insn 'src_reg' */
+               int with_offset = *str_offset != '\0';
+
+               memcpy (src_reg, token, tlen);
+               if ((bpf_cast != BPF_CAST_U32
+                    && bpf_cast != BPF_CAST_U64)
+                   || *dst_reg != 'r'
+                   || *src_reg != 'r')
+                 syntax_err ("invalid wide atomic instruction");
+               else
+                 bpf_insn = build_bpf_atomic_insn (dst_reg, src_reg, bpf_atomic_insn,
+                                                   bpf_cast, with_offset ? str_offset : str_symbol);
+             }
+
+             state = ST_EOI;
+             break;
+
+           case 33:
+             /* callx 'dst_reg' */
+             bpf_insn = xasprintf ("%s %%%s", "call", token);
+             state = ST_EOI;
+             break;
+
+           case 35:
+             memcpy (src_reg, token, tlen);
+             state = 36; /* dst_reg = str_cast skb [ 'src_reg' */
+             break;
+           }
+         break;
 
-  return s;
-}
+       case BPF_MOV:
+       case BPF_ADD:
+       case BPF_SUB:
+       case BPF_MUL:
+       case BPF_DIV:
+       case BPF_OR:
+       case BPF_AND:
+       case BPF_LSH:
+       case BPF_RSH:
+       case BPF_MOD:
+       case BPF_XOR:
+       case BPF_ARSH:
+       case BPF_NEG:
+         switch (state)
+           {
+           case 1:
+             state = 3;  /* dst_reg 'arith_op' */
+             bpf_arithm_op = ttype;
+             break;
+
+           case 3:
+             if (ttype == BPF_NEG)
+               {
+                 /* reg = -reg */
+                 bpf_arithm_op = ttype;
+                 memcpy (src_reg, token + 1, tlen - 1);
+                 if (strcmp (dst_reg, src_reg))
+                   {
+                     syntax_err ("found: '%s', expected: -%s", token, dst_reg);
+                     break;
+                   }
+
+                 bpf_insn = build_bpf_arithm_insn (dst_reg, src_reg, 0,
+                                                   NULL, bpf_arithm_op);
+                 state = ST_EOI;
+               }
+             break;
+
+           case 23:
+             memcpy (src_reg, token, tlen);
+             state = 11; /* str_cast ( dst_reg offset ) '=' */
+             break;
+
+           case 12:
+             if (ttype == BPF_MOV)
+               state = 13; /* str_cast ( dst_reg offset ) '=' */
+             break;
+
+           case 31:
+             bpf_atomic_insn = ttype;
+             state = 32; /* lock str_cast ( dst_reg offset ) 'atomic_insn' */
+             break;
+
+           default:
+             syntax_err ("unexpected '%s'", token);
+             state = ST_EOI;
+           }
+         break;
 
-/* Collect a parse error message.  */
+       case BPF_CAST_U8:
+       case BPF_CAST_U16:
+       case BPF_CAST_U32:
+       case BPF_CAST_U64:
+         bpf_cast = ttype;
+         switch (state)
+           {
+           case 3:
+             state = 4; /* dst_reg = 'str_cast' */
+             break;
+
+           case 0:
+             state = 8;  /* 'str_cast' */
+             break;
+
+           case 26:
+             state = 27; /* lock 'str_cast' */
+             break;
+           }
+         break;
 
-static int partial_match_length = 0;
-static char *errmsg = NULL;
+       case BPF_CHR_OPEN_BR:
+         switch (state)
+           {
+           case 4:
+             state = 5; /* dst_reg = str_cast '(' */
+             break;
+
+           case 8:
+             state = 9; /* str_cast '(' */
+             break;
+
+           case 27:
+             state = 28; /* lock str_cast '(' */
+             break;
+
+           case 34:
+             state = 35; /* dst_reg = str_cast skb '[' */
+             break;
+           }
+         break;
 
-static void
-parse_error (int length, const char *fmt, ...)
-{
-  if (length > partial_match_length)
-    {
-      va_list args;
+       case BPF_CHR_CLSE_BR:
+         switch (state)
+           {
+           case 7:
+             /* dst_reg = str_cast ( imm32 ')' */
+             bpf_insn = build_bpf_load_store_insn (dst_reg, src_reg,
+                                                   bpf_cast, str_imm32, 1);
+             state = ST_EOI;
+             break;
+
+           case 11:
+             state = 12; /* str_cast ( dst_reg imm32 ')' */
+             break;
+
+           case 21:
+             /* dst_reg = str_cast ( src_reg  offset ')' */
+             bpf_insn = build_bpf_load_store_insn (dst_reg, src_reg,
+                                                   bpf_cast, str_offset, 1);
+             state = ST_EOI;
+             break;
+
+           case 22:
+             state = 23; /* str_cast ( dst_reg offset ')' */
+             break;
+
+           case 30:
+             state = 31; /* lock str_cast ( dst_reg offset ')' */
+             break;
+
+           case 37:
+             /* dst_reg = str_cast skb [ src_reg imm32 ']' */
+             if (*dst_reg != 'w' && !strcmp ("r0", dst_reg))
+               bpf_insn = build_bpf_non_generic_load (*src_reg != '\0' ? src_reg : NULL,
+                                                      bpf_cast, str_imm32);
+             else
+               syntax_err ("invalid register operand: '%s'", dst_reg);
+
+             state = ST_EOI;
+             break;
+           }
+         break;
 
-      free (errmsg);
-      va_start (args, fmt);
-      errmsg = xvasprintf (fmt, args);
-      va_end (args);
-      partial_match_length = length;
-    }
-}
+       case BPF_EXPR:
+         switch (state)
+           {
+           case 3:
+             {
+               /* dst_reg bpf_arithm_op 'imm32' */
+               int load64 = 0;
+
+               memcpy (str_imm32, token, tlen);
+               memset (token, 0, tlen);
+
+               if ((ttype = get_token (&str, token, &tlen)) == BPF_LL
+                   && bpf_arithm_op == BPF_MOV)
+                 load64 = 1;
+               else if (ttype != BPF_UNKNOWN)
+                 syntax_err ("unexpected token: '%s'", token);
+
+               if (load64 && *dst_reg == 'w')
+                 syntax_err ("unexpected register size: '%s'", dst_reg);
+
+               if (! parse_err)
+                 bpf_insn = build_bpf_arithm_insn (dst_reg, NULL, load64,
+                                                   str_imm32, bpf_arithm_op);
+               state = ST_EOI;
+             }
+             break;
+
+           case 18:
+             {
+               /* if dst_reg jmp_op src_reg goto 'offset' */
+               int with_src = *src_reg != '\0';
+
+               memcpy (str_offset, token, tlen);
+               if (with_src && *dst_reg != *src_reg)
+                 syntax_err ("different register size: '%s', '%s'",
+                             dst_reg, src_reg);
+               else
+                 bpf_insn = build_bpf_jmp_insn (dst_reg, with_src ? src_reg : NULL,
+                                                with_src ? NULL: str_imm32,
+                                                bpf_jmp_op, NULL, str_offset);
+               state = ST_EOI;
+             }
+             break;
+
+           case 19:
+             /* goto 'offset' */
+             memcpy (str_offset, token, tlen);
+             bpf_insn = xasprintf ("%s %s", "ja", str_offset);
+             state = ST_EOI;
+             break;
+
+           case 6:
+             memcpy (str_offset, token, tlen);
+             state = 21; /* dst_reg = str_cast ( src_reg  'offset' */
+             break;
+
+           case 10:
+             memcpy (str_offset, token, tlen);
+             state = 22; /* str_cast ( dst_reg 'offset' */
+             break;
+
+           case 16:
+             memcpy (str_imm32, token, tlen);
+             state = 25; /* if dst_reg jmp_op 'imm32' */
+             break;
+
+           case 29:
+             memcpy (str_offset, token, tlen);
+             state = 30; /* lock str_cast ( dst_reg 'offset' */
+             break;
+
+           case 34:
+             /* dst_reg = str_cast skb 'imm32' */
+             if (*dst_reg != 'w' && !strcmp ("r0", dst_reg))
+               {
+                 memcpy (str_imm32, token, tlen);
+                 bpf_insn = build_bpf_non_generic_load (*src_reg != '\0' ? src_reg : NULL,
+                                                        bpf_cast, str_imm32);
+               }
+             else
+               syntax_err ("invalid register operand: '%s'", dst_reg);
+
+             state = ST_EOI;
+             break;
+
+           case 36:
+             memcpy (str_imm32, token, tlen);
+             state = 37; /* dst_reg = str_cast skb [ src_reg 'imm32' */
+             break;
+           }
+         break;
 
-/* Assemble a machine instruction in STR and emit the frags/bytes it
-   assembles to.  */
+       case BPF_IF:
+         if (state == 0)
+           state = 14;
+         break;
 
-void
-md_assemble (char *str ATTRIBUTE_UNUSED)
-{
-  /* There are two different syntaxes that can be used to write BPF
-     instructions.  One is very conventional and like any other
-     assembly language where each instruction is conformed by an
-     instruction mnemonic followed by its operands.  This is what we
-     call the "normal" syntax.  The other syntax tries to look like C
-     statements. We have to support both syntaxes in this assembler.
-
-     One of the many nuisances introduced by this eccentricity is that
-     in the pseudo-c syntax it is not possible to hash the opcodes
-     table by instruction mnemonic, because there is none.  So we have
-     no other choice than to try to parse all instruction opcodes
-     until one matches.  This is slow.
-
-     Another problem is that emitting detailed diagnostics becomes
-     tricky, since the lack of mnemonic means it is not clear what
-     instruction was intended by the user, and we cannot emit
-     diagnostics for every attempted template.  So if an instruction
-     is not parsed, we report the diagnostic corresponding to the
-     partially parsed instruction that was matched further.  */
-
-  unsigned int idx = 0;
-  struct bpf_insn insn;
-  const struct bpf_opcode *opcode;
-
-  /* Initialize the global diagnostic variables.  See the parse_error
-     function above.  */
-  partial_match_length = 0;
-  errmsg = NULL;
-
-#define PARSE_ERROR(...) parse_error (s - str, __VA_ARGS__)
-
-  while ((opcode = bpf_get_opcode (idx++)) != NULL)
-    {
-      const char *p;
-      char *s;
-      const char *template
-        = (asm_dialect == DIALECT_PSEUDOC ? opcode->pseudoc : opcode->normal);
-
-      /* Do not try to match opcodes with a higher version than the
-         selected ISA spec.  */
-      if (opcode->version > isa_spec)
-        continue;
-
-      memset (&insn, 0, sizeof (struct bpf_insn));
-      insn.size = 8;
-      for (s = str, p = template; *p != '\0';)
-        {
-          if (*p == ' ')
-            {
-              /* Expect zero or more spaces.  */
-              while (*s != '\0' && (*s == ' ' || *s == '\t'))
-                s += 1;
-              p += 1;
-            }
-          else if (*p == '%')
-            {
-              if (*(p + 1) == '%')
-                {
-                  if (*s != '%')
-                    {
-                      PARSE_ERROR ("expected '%%'");
-                      break;
-                    }
-                  p += 2;
-                  s += 1;
-                }
-              else if (*(p + 1) == 'w')
-                {
-                  /* Expect zero or more spaces.  */
-                  while (*s != '\0' && (*s == ' ' || *s == '\t'))
-                    s += 1;
-                  p += 2;
-                }
-              else if (*(p + 1) == 'W')
-                {
-                  /* Expect one or more spaces.  */
-                  if (*s != ' ' && *s != '\t')
-                    {
-                      PARSE_ERROR ("expected white space, got '%s'",
-                                   s);
-                      break;
-                    }
-                  while (*s != '\0' && (*s == ' ' || *s == '\t'))
-                    s += 1;
-                  p += 2;
-                }
-              else if (strncmp (p, "%dr", 3) == 0)
-                {
-                  uint8_t regno;
-                  char *news = parse_bpf_register (s, 'r', &regno);
-
-                  if (news == NULL || (insn.has_dst && regno != insn.dst))
-                    {
-                      if (news != NULL)
-                        PARSE_ERROR ("expected register r%d, got r%d",
-                                     insn.dst, regno);
-                      else
-                        PARSE_ERROR ("expected register name, got '%s'", s);
-                      break;
-                    }
-                  s = news;
-                  insn.dst = regno;
-                  insn.has_dst = 1;
-                  p += 3;
-                }
-              else if (strncmp (p, "%sr", 3) == 0)
-                {
-                  uint8_t regno;
-                  char *news = parse_bpf_register (s, 'r', &regno);
-
-                  if (news == NULL || (insn.has_src && regno != insn.src))
-                    {
-                      if (news != NULL)
-                        PARSE_ERROR ("expected register r%d, got r%d",
-                                     insn.dst, regno);
-                      else
-                        PARSE_ERROR ("expected register name, got '%s'", s);
-                      break;
-                    }
-                  s = news;
-                  insn.src = regno;
-                  insn.has_src = 1;
-                  p += 3;
-                }
-              else if (strncmp (p, "%dw", 3) == 0)
-                {
-                  uint8_t regno;
-                  char *news = parse_bpf_register (s, 'w', &regno);
-
-                  if (news == NULL || (insn.has_dst && regno != insn.dst))
-                    {
-                      if (news != NULL)
-                        PARSE_ERROR ("expected register r%d, got r%d",
-                                     insn.dst, regno);
-                      else
-                        PARSE_ERROR ("expected register name, got '%s'", s);
-                      break;
-                    }
-                  s = news;
-                  insn.dst = regno;
-                  insn.has_dst = 1;
-                  p += 3;
-                }
-              else if (strncmp (p, "%sw", 3) == 0)
-                {
-                  uint8_t regno;
-                  char *news = parse_bpf_register (s, 'w', &regno);
-
-                  if (news == NULL || (insn.has_src && regno != insn.src))
-                    {
-                      if (news != NULL)
-                        PARSE_ERROR ("expected register r%d, got r%d",
-                                     insn.dst, regno);
-                      else
-                        PARSE_ERROR ("expected register name, got '%s'", s);
-                      break;
-                    }
-                  s = news;
-                  insn.src = regno;
-                  insn.has_src = 1;
-                  p += 3;
-                }
-              else if (strncmp (p, "%i32", 4) == 0
-                       || strncmp (p, "%I32", 4) == 0)
-                {
-                  if (p[1] == 'I')
-                    {
-                      while (*s == ' ' || *s == '\t')
-                        s += 1;
-                      if (*s != '+' && *s != '-')
-                        {
-                          PARSE_ERROR ("expected `+' or `-', got `%c'", *s);
-                          break;
-                        }
-                    }
-
-                  s = parse_expression (s, &insn.imm32);
-                  if (s == NULL)
-                    {
-                      PARSE_ERROR ("expected signed 32-bit immediate");
-                      break;
-                    }
-                  insn.has_imm32 = 1;
-                  p += 4;
-                }
-              else if (strncmp (p, "%o16", 4) == 0)
-                {
-                  while (*s == ' ' || *s == '\t')
-                    s += 1;
-                  if (*s != '+' && *s != '-')
-                    {
-                      PARSE_ERROR ("expected `+' or `-', got `%c'", *s);
-                      break;
-                    }
-
-                  s = parse_expression (s, &insn.offset16);
-                  if (s == NULL)
-                    {
-                      PARSE_ERROR ("expected signed 16-bit offset");
-                      break;
-                    }
-                  insn.has_offset16 = 1;
-                  p += 4;
-                }
-              else if (strncmp (p, "%d16", 4) == 0)
-                {
-                  s = parse_expression (s, &insn.disp16);
-                  if (s == NULL)
-                    {
-                      PARSE_ERROR ("expected signed 16-bit displacement");
-                      break;
-                    }
-                  insn.has_disp16 = 1;
-                  insn.is_relaxable = 1;
-                  p += 4;
-                }
-              else if (strncmp (p, "%d32", 4) == 0)
-                {
-                  s = parse_expression (s, &insn.disp32);
-                  if (s == NULL)
-                    {
-                      PARSE_ERROR ("expected signed 32-bit displacement");
-                      break;
-                    }
-                  insn.has_disp32 = 1;
-                  p += 4;
-                }
-              else if (strncmp (p, "%i64", 4) == 0)
-                {
-                  s = parse_expression (s, &insn.imm64);
-                  if (s == NULL)
-                    {
-                      PARSE_ERROR ("expected signed 64-bit immediate");
-                      break;
-                    }
-                  insn.has_imm64 = 1;
-                  insn.size = 16;
-                  p += 4;
-                }
-              else
-                as_fatal (_("invalid %%-tag in BPF opcode '%s'\n"), template);
-            }
-          else
-            {
-              /* Match a literal character.  */
-              if (*s != *p)
-                {
-                  if (*s == '\0')
-                    PARSE_ERROR ("expected '%c'", *p);
-                  else if (*s == '%')
-                    {
-                      /* This is to workaround a bug in as_bad. */
-                      char tmp[3];
-
-                      tmp[0] = '%';
-                      tmp[1] = '%';
-                      tmp[2] = '\0';
-
-                      PARSE_ERROR ("expected '%c', got '%s'", *p, tmp);
-                    }
-                  else
-                    PARSE_ERROR ("expected '%c', got '%c'", *p, *s);
-                  break;
-                }
-              p += 1;
-              s += 1;
-            }
-        }
+       case BPF_JSGT:
+       case BPF_JSLT:
+       case BPF_JSLE:
+       case BPF_JSGE:
+       case BPF_JGT:
+       case BPF_JGE:
+       case BPF_JLE:
+       case BPF_JSET:
+       case BPF_JNE:
+       case BPF_JLT:
+       case BPF_JEQ:
+         if (state == 15)
+           {
+             bpf_jmp_op = ttype;
+             state = 16; /* if dst_reg 'jmp_op' */
+           }
+         break;
 
-      if (*p == '\0')
-        {
-          /* Allow white spaces at the end of the line.  */
-          while (*s != '\0' && (*s == ' ' || *s == '\t'))
-            s += 1;
-          if (*s == '\0')
-            /* We parsed an instruction successfully.  */
-            break;
-          PARSE_ERROR ("extra junk at end of line");
-        }
-    }
+       case BPF_GOTO:
+         switch (state)
+           {
+           case 17:
+           case 25:
+             state = 18; /* if dst_reg jmp_op src_reg|imm32 'goto' */
+             break;
+
+           case 0:
+             state = 19;
+             break;
+           }
+         break;
 
-  if (opcode == NULL)
-    {
-      as_bad (_("unrecognized instruction `%s'"), str);
-      if (errmsg != NULL)
-        {
-          as_bad ("%s", errmsg);
-          free (errmsg);
-        }
+       case BPF_SYMBOL:
+         switch (state)
+           {
+           case 18:
+             {
+               /* if dst_reg jmp_op src_reg goto 'sym' */
+               int with_src = *src_reg != '\0';
+
+               memcpy (str_symbol, token, tlen);
+               if (with_src && *dst_reg != *src_reg)
+                 syntax_err ("different register size: '%s', '%s'",
+                             dst_reg, src_reg);
+               else
+                 bpf_insn = build_bpf_jmp_insn (dst_reg, with_src ? src_reg : NULL,
+                                                with_src ? NULL: str_imm32,
+                                                bpf_jmp_op, str_symbol, NULL);
+               state = ST_EOI;
+             }
+             break;
+
+           case 19:
+             /* goto 'sym' */
+             memcpy (str_symbol, token, tlen);
+             bpf_insn = xasprintf ("%s %s", "ja", str_symbol);
+             state = ST_EOI;
+             break;
+
+           case 0:
+             state = ST_EOI;
+             break;
+
+           case 3:
+             {
+               /* dst_reg arithm_op 'sym' */
+               int load64 = 0;
+               
+               memcpy (str_symbol, token, tlen);
+               memset (token, 0, tlen);
+
+               if ((ttype = get_token (&str, token, &tlen)) == BPF_LL
+                   && bpf_arithm_op == BPF_MOV)
+                 load64 = 1;
+               else if (ttype != BPF_UNKNOWN)
+                 syntax_err ("unexpected token: '%s'", token);
+
+               if (load64 && *dst_reg == 'w')
+                 syntax_err ("unexpected register size: '%s'", dst_reg);
+
+               if (! parse_err)
+                 bpf_insn = build_bpf_arithm_insn (dst_reg, NULL, load64,
+                                                   str_symbol, bpf_arithm_op);
+               state = ST_EOI;
+             }
+             break;
+           }
+         break;
 
-      return;
-    }
-  insn.id = opcode->id;
-  insn.opcode = opcode->opcode;
+       case BPF_LE16:
+       case BPF_LE32:
+       case BPF_LE64:
+       case BPF_BE16:
+       case BPF_BE32:
+       case BPF_BE64:
+         bpf_endianness = ttype;
+         state = 24; /* dst_reg = 'endianness' */
+         break;
 
-#undef PARSE_ERROR
+       case BPF_LOCK:
+         state = 26;
+         break;
 
-  /* Generate the frags and fixups for the parsed instruction.  */
-  if (do_relax && isa_spec >= BPF_V4 && insn.is_relaxable)
-    {
-      expressionS *relaxable_exp = NULL;
+       case BPF_IND_CALL:
+         state = 33;
+         break;
 
-      if (insn.has_disp16)
-        relaxable_exp = &insn.disp16;
-      else
-        abort ();
+       case BPF_LD:
+         state = 34; /* dst_reg = str_cast 'skb' */
+         break;
+       }
 
-      add_relaxed_insn (&insn, relaxable_exp);
+      memset (token, 0, tlen);
     }
-  else
-    add_fixed_insn (&insn);
 
-  /* Emit DWARF2 debugging information.  */
-  dwarf2_emit_insn (insn.size);
+  if (state != ST_EOI)
+    syntax_err ("incomplete instruction");
+
+  *errmsg = errbuf;
+  return bpf_insn;
+
+#undef syntax_err
 }
 
-/* Parse an operand that is machine-specific.  */
+void
+md_assemble (char *str)
+{
+  const CGEN_INSN *insn;
+  char *errmsg;
+  char *a_errmsg;
+  CGEN_FIELDS fields;
+  char *normal;
+
+#if CGEN_INT_INSN_P
+  CGEN_INSN_INT buffer[CGEN_MAX_INSN_SIZE / sizeof (CGEN_INT_INSN_P)];
+#else
+  unsigned char buffer[CGEN_MAX_INSN_SIZE];
+#endif
+
+  gas_cgen_init_parse ();
+  insn = bpf_cgen_assemble_insn (gas_cgen_cpu_desc, str, &fields,
+                                  buffer, &errmsg);
+  if (insn == NULL)
+    {
+      normal = bpf_pseudoc_to_normal_syntax (str, &a_errmsg);
+      if (normal)
+       {
+         insn = bpf_cgen_assemble_insn (gas_cgen_cpu_desc, normal, &fields,
+                                        buffer, &a_errmsg);
+         xfree (normal);
+       }
+
+      if (insn == NULL)
+       {
+         as_bad ("%s", errmsg);
+         if (a_errmsg)
+           {
+             as_bad ("%s", a_errmsg);
+             xfree (a_errmsg);
+           }
+         return;
+       }
+    }
+
+  gas_cgen_finish_insn (insn, buffer, CGEN_FIELDS_BITSIZE (&fields),
+                        0, /* zero to ban relaxable insns.  */
+                        NULL); /* NULL so results not returned here.  */
+}
 
 void
 md_operand (expressionS *expressionP)
 {
-  /* If this hook is invoked it means GAS failed to parse a generic
-  expression.  We should inhibit the as_bad in expr.c, so we can fail
-  while parsing instruction alternatives.  To do that, we change the
-  expression to not have an O_absent.  But then we also need to set
-  exp_parse_failed to parse_expression above does the right thing.  */
-  ++input_line_pointer;
-  expressionP->X_op = O_constant;
-  expressionP->X_add_number = 0;
-  exp_parse_failed = 1;
+  invalid_expression = input_line_pointer - 1;
+  gas_cgen_md_operand (expressionP);
 }
 
+
 symbolS *
 md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
 {
@@ -1653,38 +1929,3 @@ md_atof (int type, char *litP, int *sizeP)
 {
   return ieee_md_atof (type, litP, sizeP, false);
 }
-
-\f
-/* Determine whether the equal sign in the given string corresponds to
-   a BPF instruction, i.e. when it is not to be considered a symbol
-   assignment.  */
-
-bool
-bpf_tc_equal_in_insn (int c ATTRIBUTE_UNUSED, char *str ATTRIBUTE_UNUSED)
-{
-  uint8_t regno;
-
-  /* Only pseudo-c instructions can have equal signs, and of these,
-     all that could be confused with a symbol assignment all start
-     with a register name.  */
-  if (asm_dialect == DIALECT_PSEUDOC)
-    {
-      char *w = parse_bpf_register (str, 'w', &regno);
-      char *r = parse_bpf_register (str, 'r', &regno);
-
-      if ((w != NULL && *w == '\0')
-          || (r != NULL && *r == '\0'))
-        return 1;
-    }
-
-  return 0;
-}
-
-/* Some special processing for a BPF ELF file.  */
-
-void
-bpf_elf_final_processing (void)
-{
-  /* Annotate the BPF ISA version in the ELF flag bits.  */
-  elf_elfheader (stdoutput)->e_flags |= (isa_spec & EF_BPF_CPUVER);
-}