- };
- return GOT_symbol;
- }
- return 0;
-}
-
-/* Round up a section size to the appropriate boundary. */
-
-valueT
-md_section_align (segment, size)
- segT segment ATTRIBUTE_UNUSED;
- valueT size;
-{
-#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
- if (OUTPUT_FLAVOR == bfd_target_aout_flavour)
- {
- /* For a.out, force the section size to be aligned. If we don't do
- this, BFD will align it for us, but it will not write out the
- final bytes of the section. This may be a bug in BFD, but it is
- easier to fix it here since that is how the other a.out targets
- work. */
- int align;
-
- align = bfd_get_section_alignment (stdoutput, segment);
- size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
- }
-#endif
-
- return size;
-}
-
-/* On the i386, PC-relative offsets are relative to the start of the
- next instruction. That is, the address of the offset, plus its
- size, since the offset is always the last part of the insn. */
-
-long
-md_pcrel_from (fixP)
- fixS *fixP;
-{
- return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
-}
-
-#ifndef I386COFF
-
-static void
-s_bss (ignore)
- int ignore ATTRIBUTE_UNUSED;
-{
- int temp;
-
-#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
- if (IS_ELF)
- obj_elf_section_change_hook ();
-#endif
- temp = get_absolute_expression ();
- subseg_set (bss_section, (subsegT) temp);
- demand_empty_rest_of_line ();
-}
-
-#endif
-
-void
-i386_validate_fix (fixp)
- fixS *fixp;
-{
- if (fixp->fx_subsy && fixp->fx_subsy == GOT_symbol)
- {
- if (fixp->fx_r_type == BFD_RELOC_32_PCREL)
- {
- if (!object_64bit)
- abort ();
- fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL;
- }
- else
- {
- if (!object_64bit)
- fixp->fx_r_type = BFD_RELOC_386_GOTOFF;
- else
- fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64;
- }
- fixp->fx_subsy = 0;
- }
-}
-
-arelent *
-tc_gen_reloc (section, fixp)
- asection *section ATTRIBUTE_UNUSED;
- fixS *fixp;
-{
- arelent *rel;
- bfd_reloc_code_real_type code;
-
- switch (fixp->fx_r_type)
- {
- case BFD_RELOC_X86_64_PLT32:
- case BFD_RELOC_X86_64_GOT32:
- case BFD_RELOC_X86_64_GOTPCREL:
- case BFD_RELOC_386_PLT32:
- case BFD_RELOC_386_GOT32:
- case BFD_RELOC_386_GOTOFF:
- case BFD_RELOC_386_GOTPC:
- case BFD_RELOC_386_TLS_GD:
- case BFD_RELOC_386_TLS_LDM:
- case BFD_RELOC_386_TLS_LDO_32:
- case BFD_RELOC_386_TLS_IE_32:
- case BFD_RELOC_386_TLS_IE:
- case BFD_RELOC_386_TLS_GOTIE:
- case BFD_RELOC_386_TLS_LE_32:
- case BFD_RELOC_386_TLS_LE:
- case BFD_RELOC_X86_64_TLSGD:
- case BFD_RELOC_X86_64_TLSLD:
- case BFD_RELOC_X86_64_DTPOFF32:
- case BFD_RELOC_X86_64_DTPOFF64:
- case BFD_RELOC_X86_64_GOTTPOFF:
- case BFD_RELOC_X86_64_TPOFF32:
- case BFD_RELOC_X86_64_TPOFF64:
- case BFD_RELOC_X86_64_GOTOFF64:
- case BFD_RELOC_X86_64_GOTPC32:
- case BFD_RELOC_RVA:
- case BFD_RELOC_VTABLE_ENTRY:
- case BFD_RELOC_VTABLE_INHERIT:
-#ifdef TE_PE
- case BFD_RELOC_32_SECREL:
-#endif
- code = fixp->fx_r_type;
- break;
- case BFD_RELOC_X86_64_32S:
- if (!fixp->fx_pcrel)
- {
- /* Don't turn BFD_RELOC_X86_64_32S into BFD_RELOC_32. */
- code = fixp->fx_r_type;
- break;
- }
- default:
- if (fixp->fx_pcrel)
- {
- switch (fixp->fx_size)
- {
- default:
- as_bad_where (fixp->fx_file, fixp->fx_line,
- _("can not do %d byte pc-relative relocation"),
- fixp->fx_size);
- code = BFD_RELOC_32_PCREL;
- break;
- case 1: code = BFD_RELOC_8_PCREL; break;
- case 2: code = BFD_RELOC_16_PCREL; break;
- case 4: code = BFD_RELOC_32_PCREL; break;
-#ifdef BFD64
- case 8: code = BFD_RELOC_64_PCREL; break;
-#endif
- }
- }
- else
- {
- switch (fixp->fx_size)
- {
- default:
- as_bad_where (fixp->fx_file, fixp->fx_line,
- _("can not do %d byte relocation"),
- fixp->fx_size);
- code = BFD_RELOC_32;
- break;
- case 1: code = BFD_RELOC_8; break;
- case 2: code = BFD_RELOC_16; break;
- case 4: code = BFD_RELOC_32; break;
-#ifdef BFD64
- case 8: code = BFD_RELOC_64; break;
-#endif
- }
- }
- break;
- }
-
- if ((code == BFD_RELOC_32 || code == BFD_RELOC_32_PCREL)
- && GOT_symbol
- && fixp->fx_addsy == GOT_symbol)
- {
- if (!object_64bit)
- code = BFD_RELOC_386_GOTPC;
- else
- code = BFD_RELOC_X86_64_GOTPC32;
- }
-
- rel = (arelent *) xmalloc (sizeof (arelent));
- rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
- *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
-
- rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
-
- if (!use_rela_relocations)
- {
- /* HACK: Since i386 ELF uses Rel instead of Rela, encode the
- vtable entry to be used in the relocation's section offset. */
- if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
- rel->address = fixp->fx_offset;
-
- rel->addend = 0;
- }
- /* Use the rela in 64bit mode. */
- else
- {
- if (!fixp->fx_pcrel)
- rel->addend = fixp->fx_offset;
- else
- switch (code)
- {
- case BFD_RELOC_X86_64_PLT32:
- case BFD_RELOC_X86_64_GOT32:
- case BFD_RELOC_X86_64_GOTPCREL:
- case BFD_RELOC_X86_64_TLSGD:
- case BFD_RELOC_X86_64_TLSLD:
- case BFD_RELOC_X86_64_GOTTPOFF:
- rel->addend = fixp->fx_offset - fixp->fx_size;
- break;
- default:
- rel->addend = (section->vma
- - fixp->fx_size
- + fixp->fx_addnumber
- + md_pcrel_from (fixp));
- break;
- }
- }
-
- rel->howto = bfd_reloc_type_lookup (stdoutput, code);
- if (rel->howto == NULL)
- {
- as_bad_where (fixp->fx_file, fixp->fx_line,
- _("cannot represent relocation type %s"),
- bfd_get_reloc_code_name (code));
- /* Set howto to a garbage value so that we can keep going. */
- rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
- assert (rel->howto != NULL);
- }
-
- return rel;
-}
-
-\f
-/* Parse operands using Intel syntax. This implements a recursive descent
- parser based on the BNF grammar published in Appendix B of the MASM 6.1
- Programmer's Guide.
-
- FIXME: We do not recognize the full operand grammar defined in the MASM
- documentation. In particular, all the structure/union and
- high-level macro operands are missing.
-
- Uppercase words are terminals, lower case words are non-terminals.
- Objects surrounded by double brackets '[[' ']]' are optional. Vertical
- bars '|' denote choices. Most grammar productions are implemented in
- functions called 'intel_<production>'.
-
- Initial production is 'expr'.
-
- addOp + | -
-
- alpha [a-zA-Z]
-
- binOp & | AND | \| | OR | ^ | XOR
-
- byteRegister AL | AH | BL | BH | CL | CH | DL | DH
-
- constant digits [[ radixOverride ]]
-
- dataType BYTE | WORD | DWORD | FWORD | QWORD | TBYTE | OWORD | XMMWORD
-
- digits decdigit
- | digits decdigit
- | digits hexdigit
-
- decdigit [0-9]
-
- e04 e04 addOp e05
- | e05
-
- e05 e05 binOp e06
- | e06
-
- e06 e06 mulOp e09
- | e09
-
- e09 OFFSET e10
- | SHORT e10
- | + e10
- | - e10
- | ~ e10
- | NOT e10
- | e09 PTR e10
- | e09 : e10
- | e10
-
- e10 e10 [ expr ]
- | e11
-
- e11 ( expr )
- | [ expr ]
- | constant
- | dataType
- | id
- | $
- | register
-
- => expr expr cmpOp e04
- | e04
-
- gpRegister AX | EAX | BX | EBX | CX | ECX | DX | EDX
- | BP | EBP | SP | ESP | DI | EDI | SI | ESI
-
- hexdigit a | b | c | d | e | f
- | A | B | C | D | E | F
-
- id alpha
- | id alpha
- | id decdigit
-
- mulOp * | / | % | MOD | << | SHL | >> | SHR
-
- quote " | '
-
- register specialRegister
- | gpRegister
- | byteRegister
-
- segmentRegister CS | DS | ES | FS | GS | SS
-
- specialRegister CR0 | CR2 | CR3 | CR4
- | DR0 | DR1 | DR2 | DR3 | DR6 | DR7
- | TR3 | TR4 | TR5 | TR6 | TR7
-
- We simplify the grammar in obvious places (e.g., register parsing is
- done by calling parse_register) and eliminate immediate left recursion
- to implement a recursive-descent parser.
-
- expr e04 expr'
-
- expr' cmpOp e04 expr'
- | Empty
-
- e04 e05 e04'
-
- e04' addOp e05 e04'
- | Empty
-
- e05 e06 e05'
-
- e05' binOp e06 e05'
- | Empty
-
- e06 e09 e06'
-
- e06' mulOp e09 e06'
- | Empty
-
- e09 OFFSET e10 e09'
- | SHORT e10'
- | + e10'
- | - e10'
- | ~ e10'
- | NOT e10'
- | e10 e09'
-
- e09' PTR e10 e09'
- | : e10 e09'
- | Empty
-
- e10 e11 e10'
-
- e10' [ expr ] e10'
- | Empty
-
- e11 ( expr )
- | [ expr ]
- | BYTE
- | WORD
- | DWORD
- | FWORD
- | QWORD
- | TBYTE
- | OWORD
- | XMMWORD
- | .
- | $
- | register
- | id
- | constant */
-
-/* Parsing structure for the intel syntax parser. Used to implement the
- semantic actions for the operand grammar. */
-struct intel_parser_s
- {
- char *op_string; /* The string being parsed. */
- int got_a_float; /* Whether the operand is a float. */
- int op_modifier; /* Operand modifier. */
- int is_mem; /* 1 if operand is memory reference. */
- int in_offset; /* >=1 if parsing operand of offset. */
- int in_bracket; /* >=1 if parsing operand in brackets. */
- const reg_entry *reg; /* Last register reference found. */
- char *disp; /* Displacement string being built. */
- char *next_operand; /* Resume point when splitting operands. */
- };
-
-static struct intel_parser_s intel_parser;
-
-/* Token structure for parsing intel syntax. */
-struct intel_token
- {
- int code; /* Token code. */
- const reg_entry *reg; /* Register entry for register tokens. */
- char *str; /* String representation. */
- };
-
-static struct intel_token cur_token, prev_token;
-
-/* Token codes for the intel parser. Since T_SHORT is already used
- by COFF, undefine it first to prevent a warning. */
-#define T_NIL -1
-#define T_CONST 1
-#define T_REG 2
-#define T_BYTE 3
-#define T_WORD 4
-#define T_DWORD 5
-#define T_FWORD 6
-#define T_QWORD 7
-#define T_TBYTE 8
-#define T_XMMWORD 9
-#undef T_SHORT
-#define T_SHORT 10
-#define T_OFFSET 11
-#define T_PTR 12
-#define T_ID 13
-#define T_SHL 14
-#define T_SHR 15
-
-/* Prototypes for intel parser functions. */
-static int intel_match_token PARAMS ((int code));
-static void intel_get_token PARAMS ((void));
-static void intel_putback_token PARAMS ((void));
-static int intel_expr PARAMS ((void));
-static int intel_e04 PARAMS ((void));
-static int intel_e05 PARAMS ((void));
-static int intel_e06 PARAMS ((void));
-static int intel_e09 PARAMS ((void));
-static int intel_bracket_expr PARAMS ((void));
-static int intel_e10 PARAMS ((void));
-static int intel_e11 PARAMS ((void));
-
-static int
-i386_intel_operand (operand_string, got_a_float)
- char *operand_string;
- int got_a_float;
-{
- int ret;
- char *p;
-
- p = intel_parser.op_string = xstrdup (operand_string);
- intel_parser.disp = (char *) xmalloc (strlen (operand_string) + 1);
-
- for (;;)
- {
- /* Initialize token holders. */
- cur_token.code = prev_token.code = T_NIL;
- cur_token.reg = prev_token.reg = NULL;
- cur_token.str = prev_token.str = NULL;
-
- /* Initialize parser structure. */
- intel_parser.got_a_float = got_a_float;
- intel_parser.op_modifier = 0;
- intel_parser.is_mem = 0;
- intel_parser.in_offset = 0;
- intel_parser.in_bracket = 0;
- intel_parser.reg = NULL;
- intel_parser.disp[0] = '\0';
- intel_parser.next_operand = NULL;
-
- /* Read the first token and start the parser. */
- intel_get_token ();
- ret = intel_expr ();
-
- if (!ret)
- break;
-
- if (cur_token.code != T_NIL)
- {
- as_bad (_("invalid operand for '%s' ('%s' unexpected)"),
- current_templates->start->name, cur_token.str);
- ret = 0;
- }
- /* If we found a memory reference, hand it over to i386_displacement
- to fill in the rest of the operand fields. */
- else if (intel_parser.is_mem)
- {
- if ((i.mem_operands == 1
- && (current_templates->start->opcode_modifier & IsString) == 0)
- || i.mem_operands == 2)
- {
- as_bad (_("too many memory references for '%s'"),
- current_templates->start->name);
- ret = 0;
- }
- else
- {
- char *s = intel_parser.disp;
- i.mem_operands++;
-
- if (!quiet_warnings && intel_parser.is_mem < 0)
- /* See the comments in intel_bracket_expr. */
- as_warn (_("Treating `%s' as memory reference"), operand_string);
-
- /* Add the displacement expression. */
- if (*s != '\0')
- ret = i386_displacement (s, s + strlen (s));
- if (ret)
- {
- /* Swap base and index in 16-bit memory operands like
- [si+bx]. Since i386_index_check is also used in AT&T
- mode we have to do that here. */
- if (i.base_reg
- && i.index_reg
- && (i.base_reg->reg_type & Reg16)
- && (i.index_reg->reg_type & Reg16)
- && i.base_reg->reg_num >= 6
- && i.index_reg->reg_num < 6)
- {
- const reg_entry *base = i.index_reg;
-
- i.index_reg = i.base_reg;
- i.base_reg = base;
- }
- ret = i386_index_check (operand_string);
- }
- }
- }
-
- /* Constant and OFFSET expressions are handled by i386_immediate. */
- else if ((intel_parser.op_modifier & (1 << T_OFFSET))
- || intel_parser.reg == NULL)
- ret = i386_immediate (intel_parser.disp);
-
- if (intel_parser.next_operand && this_operand >= MAX_OPERANDS - 1)
- ret = 0;
- if (!ret || !intel_parser.next_operand)
- break;
- intel_parser.op_string = intel_parser.next_operand;
- this_operand = i.operands++;
- }
-
- free (p);
- free (intel_parser.disp);
-
- return ret;
-}
-
-#define NUM_ADDRESS_REGS (!!i.base_reg + !!i.index_reg)
-
-/* expr e04 expr'
-
- expr' cmpOp e04 expr'
- | Empty */
-static int
-intel_expr ()
-{
- /* XXX Implement the comparison operators. */
- return intel_e04 ();
-}
-
-/* e04 e05 e04'
-
- e04' addOp e05 e04'
- | Empty */
-static int
-intel_e04 ()
-{
- int nregs = -1;
-
- for (;;)
- {
- if (!intel_e05())
- return 0;
-
- if (nregs >= 0 && NUM_ADDRESS_REGS > nregs)
- i.base_reg = i386_regtab + REGNAM_AL; /* al is invalid as base */
-
- if (cur_token.code == '+')
- nregs = -1;
- else if (cur_token.code == '-')
- nregs = NUM_ADDRESS_REGS;
- else
- return 1;
-
- strcat (intel_parser.disp, cur_token.str);
- intel_match_token (cur_token.code);
- }
-}
-
-/* e05 e06 e05'
-
- e05' binOp e06 e05'
- | Empty */
-static int
-intel_e05 ()
-{
- int nregs = ~NUM_ADDRESS_REGS;
-
- for (;;)
- {
- if (!intel_e06())
- return 0;
-
- if (cur_token.code == '&' || cur_token.code == '|' || cur_token.code == '^')
- {
- char str[2];
-
- str[0] = cur_token.code;
- str[1] = 0;
- strcat (intel_parser.disp, str);
- }
- else
- break;
-
- intel_match_token (cur_token.code);
-
- if (nregs < 0)
- nregs = ~nregs;
- }
- if (nregs >= 0 && NUM_ADDRESS_REGS > nregs)
- i.base_reg = i386_regtab + REGNAM_AL + 1; /* cl is invalid as base */
- return 1;
-}
-
-/* e06 e09 e06'
-
- e06' mulOp e09 e06'
- | Empty */
-static int
-intel_e06 ()
-{
- int nregs = ~NUM_ADDRESS_REGS;
-
- for (;;)
- {
- if (!intel_e09())
- return 0;
-
- if (cur_token.code == '*' || cur_token.code == '/' || cur_token.code == '%')
- {
- char str[2];
-
- str[0] = cur_token.code;
- str[1] = 0;
- strcat (intel_parser.disp, str);
- }
- else if (cur_token.code == T_SHL)
- strcat (intel_parser.disp, "<<");
- else if (cur_token.code == T_SHR)
- strcat (intel_parser.disp, ">>");
- else
- break;
-
- intel_match_token (cur_token.code);
-
- if (nregs < 0)
- nregs = ~nregs;
- }
- if (nregs >= 0 && NUM_ADDRESS_REGS > nregs)
- i.base_reg = i386_regtab + REGNAM_AL + 2; /* dl is invalid as base */
- return 1;
-}
-
-/* e09 OFFSET e09
- | SHORT e09
- | + e09
- | - e09
- | ~ e09
- | NOT e09
- | e10 e09'
-
- e09' PTR e10 e09'
- | : e10 e09'
- | Empty */
-static int
-intel_e09 ()
-{
- int nregs = ~NUM_ADDRESS_REGS;
- int in_offset = 0;
-
- for (;;)
- {
- /* Don't consume constants here. */
- if (cur_token.code == '+' || cur_token.code == '-')
- {
- /* Need to look one token ahead - if the next token
- is a constant, the current token is its sign. */
- int next_code;
-
- intel_match_token (cur_token.code);
- next_code = cur_token.code;
- intel_putback_token ();
- if (next_code == T_CONST)
- break;
- }
-
- /* e09 OFFSET e09 */
- if (cur_token.code == T_OFFSET)
- {
- if (!in_offset++)
- ++intel_parser.in_offset;
- }
-
- /* e09 SHORT e09 */
- else if (cur_token.code == T_SHORT)
- intel_parser.op_modifier |= 1 << T_SHORT;
-
- /* e09 + e09 */
- else if (cur_token.code == '+')
- strcat (intel_parser.disp, "+");
-
- /* e09 - e09
- | ~ e09
- | NOT e09 */
- else if (cur_token.code == '-' || cur_token.code == '~')
- {
- char str[2];
-
- if (nregs < 0)
- nregs = ~nregs;
- str[0] = cur_token.code;
- str[1] = 0;
- strcat (intel_parser.disp, str);
- }
-
- /* e09 e10 e09' */
- else
- break;
-
- intel_match_token (cur_token.code);
- }
-
- for (;;)
- {
- if (!intel_e10 ())
- return 0;
-
- /* e09' PTR e10 e09' */
- if (cur_token.code == T_PTR)
- {
- char suffix;
-
- if (prev_token.code == T_BYTE)
- suffix = BYTE_MNEM_SUFFIX;
-
- else if (prev_token.code == T_WORD)
- {
- if (current_templates->start->name[0] == 'l'
- && current_templates->start->name[2] == 's'
- && current_templates->start->name[3] == 0)
- suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
- else if (intel_parser.got_a_float == 2) /* "fi..." */
- suffix = SHORT_MNEM_SUFFIX;
- else
- suffix = WORD_MNEM_SUFFIX;
- }
-
- else if (prev_token.code == T_DWORD)
- {
- if (current_templates->start->name[0] == 'l'
- && current_templates->start->name[2] == 's'
- && current_templates->start->name[3] == 0)
- suffix = WORD_MNEM_SUFFIX;
- else if (flag_code == CODE_16BIT
- && (current_templates->start->opcode_modifier
- & (Jump | JumpDword)))
- suffix = LONG_DOUBLE_MNEM_SUFFIX;
- else if (intel_parser.got_a_float == 1) /* "f..." */
- suffix = SHORT_MNEM_SUFFIX;
- else
- suffix = LONG_MNEM_SUFFIX;
- }
-
- else if (prev_token.code == T_FWORD)
- {
- if (current_templates->start->name[0] == 'l'
- && current_templates->start->name[2] == 's'
- && current_templates->start->name[3] == 0)
- suffix = LONG_MNEM_SUFFIX;
- else if (!intel_parser.got_a_float)
- {
- if (flag_code == CODE_16BIT)
- add_prefix (DATA_PREFIX_OPCODE);
- suffix = LONG_DOUBLE_MNEM_SUFFIX;
- }
- else
- suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
- }
-
- else if (prev_token.code == T_QWORD)
- {
- if (intel_parser.got_a_float == 1) /* "f..." */
- suffix = LONG_MNEM_SUFFIX;
- else
- suffix = QWORD_MNEM_SUFFIX;
- }
-
- else if (prev_token.code == T_TBYTE)
- {
- if (intel_parser.got_a_float == 1)
- suffix = LONG_DOUBLE_MNEM_SUFFIX;
- else
- suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
- }
-
- else if (prev_token.code == T_XMMWORD)
- {
- /* XXX ignored for now, but accepted since gcc uses it */
- suffix = 0;
- }
-
- else
- {
- as_bad (_("Unknown operand modifier `%s'"), prev_token.str);
- return 0;
- }
-
- /* Operands for jump/call using 'ptr' notation denote absolute
- addresses. */
- if (current_templates->start->opcode_modifier & (Jump | JumpDword))
- i.types[this_operand] |= JumpAbsolute;
-
- if (current_templates->start->base_opcode == 0x8d /* lea */)
- ;
- else if (!i.suffix)
- i.suffix = suffix;
- else if (i.suffix != suffix)
- {
- as_bad (_("Conflicting operand modifiers"));
- return 0;
- }
-
- }
-
- /* e09' : e10 e09' */
- else if (cur_token.code == ':')
- {
- if (prev_token.code != T_REG)
- {
- /* While {call,jmp} SSSS:OOOO is MASM syntax only when SSSS is a
- segment/group identifier (which we don't have), using comma
- as the operand separator there is even less consistent, since
- there all branches only have a single operand. */
- if (this_operand != 0
- || intel_parser.in_offset
- || intel_parser.in_bracket
- || (!(current_templates->start->opcode_modifier
- & (Jump|JumpDword|JumpInterSegment))
- && !(current_templates->start->operand_types[0]
- & JumpAbsolute)))
- return intel_match_token (T_NIL);
- /* Remember the start of the 2nd operand and terminate 1st
- operand here.
- XXX This isn't right, yet (when SSSS:OOOO is right operand of
- another expression), but it gets at least the simplest case
- (a plain number or symbol on the left side) right. */
- intel_parser.next_operand = intel_parser.op_string;
- *--intel_parser.op_string = '\0';
- return intel_match_token (':');
- }
- }
-
- /* e09' Empty */
- else
- break;
-
- intel_match_token (cur_token.code);
-
- }
-
- if (in_offset)
- {
- --intel_parser.in_offset;
- if (nregs < 0)
- nregs = ~nregs;
- if (NUM_ADDRESS_REGS > nregs)
- {
- as_bad (_("Invalid operand to `OFFSET'"));
- return 0;
- }
- intel_parser.op_modifier |= 1 << T_OFFSET;
- }
-
- if (nregs >= 0 && NUM_ADDRESS_REGS > nregs)
- i.base_reg = i386_regtab + REGNAM_AL + 3; /* bl is invalid as base */
- return 1;
-}
-
-static int
-intel_bracket_expr ()
-{
- int was_offset = intel_parser.op_modifier & (1 << T_OFFSET);
- const char *start = intel_parser.op_string;
- int len;
-
- if (i.op[this_operand].regs)
- return intel_match_token (T_NIL);
-
- intel_match_token ('[');
-
- /* Mark as a memory operand only if it's not already known to be an
- offset expression. If it's an offset expression, we need to keep
- the brace in. */
- if (!intel_parser.in_offset)
- {
- ++intel_parser.in_bracket;
-
- /* Operands for jump/call inside brackets denote absolute addresses. */
- if (current_templates->start->opcode_modifier & (Jump | JumpDword))
- i.types[this_operand] |= JumpAbsolute;
-
- /* Unfortunately gas always diverged from MASM in a respect that can't
- be easily fixed without risking to break code sequences likely to be
- encountered (the testsuite even check for this): MASM doesn't consider
- an expression inside brackets unconditionally as a memory reference.
- When that is e.g. a constant, an offset expression, or the sum of the
- two, this is still taken as a constant load. gas, however, always
- treated these as memory references. As a compromise, we'll try to make
- offset expressions inside brackets work the MASM way (since that's
- less likely to be found in real world code), but make constants alone
- continue to work the traditional gas way. In either case, issue a
- warning. */
- intel_parser.op_modifier &= ~was_offset;
- }
- else
- strcat (intel_parser.disp, "[");
-
- /* Add a '+' to the displacement string if necessary. */
- if (*intel_parser.disp != '\0'
- && *(intel_parser.disp + strlen (intel_parser.disp) - 1) != '+')
- strcat (intel_parser.disp, "+");
-
- if (intel_expr ()
- && (len = intel_parser.op_string - start - 1,
- intel_match_token (']')))
- {
- /* Preserve brackets when the operand is an offset expression. */
- if (intel_parser.in_offset)
- strcat (intel_parser.disp, "]");
- else
- {
- --intel_parser.in_bracket;
- if (i.base_reg || i.index_reg)
- intel_parser.is_mem = 1;
- if (!intel_parser.is_mem)
- {
- if (!(intel_parser.op_modifier & (1 << T_OFFSET)))
- /* Defer the warning until all of the operand was parsed. */
- intel_parser.is_mem = -1;
- else if (!quiet_warnings)
- as_warn (_("`[%.*s]' taken to mean just `%.*s'"), len, start, len, start);
- }
- }
- intel_parser.op_modifier |= was_offset;
-
- return 1;
- }
- return 0;
-}
-
-/* e10 e11 e10'
-
- e10' [ expr ] e10'
- | Empty */
-static int
-intel_e10 ()
-{
- if (!intel_e11 ())
- return 0;
-
- while (cur_token.code == '[')
- {
- if (!intel_bracket_expr ())
- return 0;
- }
-
- return 1;
-}
-
-/* e11 ( expr )
- | [ expr ]
- | BYTE
- | WORD
- | DWORD
- | FWORD
- | QWORD
- | TBYTE
- | OWORD
- | XMMWORD
- | $
- | .
- | register
- | id
- | constant */
-static int
-intel_e11 ()
-{
- switch (cur_token.code)
- {
- /* e11 ( expr ) */
- case '(':
- intel_match_token ('(');
- strcat (intel_parser.disp, "(");
-
- if (intel_expr () && intel_match_token (')'))
- {
- strcat (intel_parser.disp, ")");
- return 1;
- }
- return 0;
-
- /* e11 [ expr ] */
- case '[':
- return intel_bracket_expr ();
-
- /* e11 $
- | . */
- case '.':
- strcat (intel_parser.disp, cur_token.str);
- intel_match_token (cur_token.code);
-
- /* Mark as a memory operand only if it's not already known to be an
- offset expression. */
- if (!intel_parser.in_offset)
- intel_parser.is_mem = 1;
-
- return 1;
-
- /* e11 register */
- case T_REG:
- {
- const reg_entry *reg = intel_parser.reg = cur_token.reg;
-
- intel_match_token (T_REG);
-
- /* Check for segment change. */
- if (cur_token.code == ':')
- {
- if (!(reg->reg_type & (SReg2 | SReg3)))
- {
- as_bad (_("`%s' is not a valid segment register"), reg->reg_name);
- return 0;
- }
- else if (i.seg[i.mem_operands])
- as_warn (_("Extra segment override ignored"));
- else
- {
- if (!intel_parser.in_offset)
- intel_parser.is_mem = 1;
- switch (reg->reg_num)
- {
- case 0:
- i.seg[i.mem_operands] = &es;
- break;
- case 1:
- i.seg[i.mem_operands] = &cs;
- break;
- case 2:
- i.seg[i.mem_operands] = &ss;
- break;
- case 3:
- i.seg[i.mem_operands] = &ds;
- break;
- case 4:
- i.seg[i.mem_operands] = &fs;
- break;
- case 5:
- i.seg[i.mem_operands] = &gs;
- break;
- }
- }
- }
-
- /* Not a segment register. Check for register scaling. */
- else if (cur_token.code == '*')
- {
- if (!intel_parser.in_bracket)
- {
- as_bad (_("Register scaling only allowed in memory operands"));
- return 0;
- }
-
- if (reg->reg_type & Reg16) /* Disallow things like [si*1]. */
- reg = i386_regtab + REGNAM_AX + 4; /* sp is invalid as index */
- else if (i.index_reg)
- reg = i386_regtab + REGNAM_EAX + 4; /* esp is invalid as index */
-
- /* What follows must be a valid scale. */
- intel_match_token ('*');
- i.index_reg = reg;
- i.types[this_operand] |= BaseIndex;
-
- /* Set the scale after setting the register (otherwise,
- i386_scale will complain) */
- if (cur_token.code == '+' || cur_token.code == '-')
- {
- char *str, sign = cur_token.code;
- intel_match_token (cur_token.code);
- if (cur_token.code != T_CONST)
- {
- as_bad (_("Syntax error: Expecting a constant, got `%s'"),
- cur_token.str);
- return 0;
- }
- str = (char *) xmalloc (strlen (cur_token.str) + 2);
- strcpy (str + 1, cur_token.str);
- *str = sign;
- if (!i386_scale (str))
- return 0;
- free (str);
- }
- else if (!i386_scale (cur_token.str))
- return 0;
- intel_match_token (cur_token.code);
- }
-
- /* No scaling. If this is a memory operand, the register is either a
- base register (first occurrence) or an index register (second
- occurrence). */
- else if (intel_parser.in_bracket && !(reg->reg_type & (SReg2 | SReg3)))
- {
-
- if (!i.base_reg)
- i.base_reg = reg;
- else if (!i.index_reg)
- i.index_reg = reg;
- else
- {
- as_bad (_("Too many register references in memory operand"));
- return 0;
- }
-
- i.types[this_operand] |= BaseIndex;
- }
-
- /* Offset modifier. Add the register to the displacement string to be
- parsed as an immediate expression after we're done. */
- else if (intel_parser.in_offset)
- {
- as_warn (_("Using register names in OFFSET expressions is deprecated"));
- strcat (intel_parser.disp, reg->reg_name);
- }
-
- /* It's neither base nor index nor offset. */
- else if (!intel_parser.is_mem)
- {
- i.types[this_operand] |= reg->reg_type & ~BaseIndex;
- i.op[this_operand].regs = reg;
- i.reg_operands++;
- }
- else
- {
- as_bad (_("Invalid use of register"));
- return 0;
- }
-
- /* Since registers are not part of the displacement string (except
- when we're parsing offset operands), we may need to remove any
- preceding '+' from the displacement string. */
- if (*intel_parser.disp != '\0'
- && !intel_parser.in_offset)
- {
- char *s = intel_parser.disp;
- s += strlen (s) - 1;
- if (*s == '+')
- *s = '\0';
- }
-
- return 1;
- }
-
- /* e11 BYTE
- | WORD
- | DWORD
- | FWORD
- | QWORD
- | TBYTE
- | OWORD
- | XMMWORD */
- case T_BYTE:
- case T_WORD:
- case T_DWORD:
- case T_FWORD:
- case T_QWORD:
- case T_TBYTE:
- case T_XMMWORD:
- intel_match_token (cur_token.code);
-
- if (cur_token.code == T_PTR)
- return 1;
-
- /* It must have been an identifier. */
- intel_putback_token ();
- cur_token.code = T_ID;
- /* FALLTHRU */
-
- /* e11 id
- | constant */
- case T_ID:
- if (!intel_parser.in_offset && intel_parser.is_mem <= 0)
- {
- symbolS *symbolP;
-
- /* The identifier represents a memory reference only if it's not
- preceded by an offset modifier and if it's not an equate. */
- symbolP = symbol_find(cur_token.str);
- if (!symbolP || S_GET_SEGMENT(symbolP) != absolute_section)
- intel_parser.is_mem = 1;
- }
- /* FALLTHRU */
-
- case T_CONST:
- case '-':
- case '+':
- {
- char *save_str, sign = 0;
-
- /* Allow constants that start with `+' or `-'. */
- if (cur_token.code == '-' || cur_token.code == '+')
- {
- sign = cur_token.code;
- intel_match_token (cur_token.code);
- if (cur_token.code != T_CONST)
- {
- as_bad (_("Syntax error: Expecting a constant, got `%s'"),
- cur_token.str);
- return 0;
- }
- }
-
- save_str = (char *) xmalloc (strlen (cur_token.str) + 2);
- strcpy (save_str + !!sign, cur_token.str);
- if (sign)
- *save_str = sign;
-
- /* Get the next token to check for register scaling. */
- intel_match_token (cur_token.code);
-
- /* Check if this constant is a scaling factor for an index register. */
- if (cur_token.code == '*')
- {
- if (intel_match_token ('*') && cur_token.code == T_REG)
- {
- const reg_entry *reg = cur_token.reg;
-
- if (!intel_parser.in_bracket)
- {
- as_bad (_("Register scaling only allowed in memory operands"));
- return 0;
- }
-
- if (reg->reg_type & Reg16) /* Disallow things like [1*si]. */
- reg = i386_regtab + REGNAM_AX + 4; /* sp is invalid as index */
- else if (i.index_reg)
- reg = i386_regtab + REGNAM_EAX + 4; /* esp is invalid as index */
-
- /* The constant is followed by `* reg', so it must be
- a valid scale. */
- i.index_reg = reg;
- i.types[this_operand] |= BaseIndex;
-
- /* Set the scale after setting the register (otherwise,
- i386_scale will complain) */
- if (!i386_scale (save_str))
- return 0;
- intel_match_token (T_REG);
-
- /* Since registers are not part of the displacement
- string, we may need to remove any preceding '+' from
- the displacement string. */
- if (*intel_parser.disp != '\0')
- {
- char *s = intel_parser.disp;
- s += strlen (s) - 1;
- if (*s == '+')
- *s = '\0';
- }
-
- free (save_str);
-
- return 1;
- }
-
- /* The constant was not used for register scaling. Since we have
- already consumed the token following `*' we now need to put it
- back in the stream. */
- intel_putback_token ();
- }
-
- /* Add the constant to the displacement string. */
- strcat (intel_parser.disp, save_str);
- free (save_str);
-
- return 1;
- }
- }
-
- as_bad (_("Unrecognized token '%s'"), cur_token.str);
- return 0;
-}
-
-/* Match the given token against cur_token. If they match, read the next
- token from the operand string. */
-static int
-intel_match_token (code)
- int code;
-{
- if (cur_token.code == code)
- {
- intel_get_token ();
- return 1;
- }
- else
- {
- as_bad (_("Unexpected token `%s'"), cur_token.str);
- return 0;