diff options
author | Jan Beulich <jbeulich@novell.com> | 2005-03-17 12:05:24 +0000 |
---|---|---|
committer | Jan Beulich <jbeulich@novell.com> | 2005-03-17 12:05:24 +0000 |
commit | a724f0f4f542cfa496da75b817f7d63e6727dcc1 (patch) | |
tree | 0dc61b1f1dcdbb1a85eac3e555bd10fee29d9607 /gas | |
parent | f7e6ca5e6bb25bf81a5df4bfb0df13cf8b21deb1 (diff) | |
download | gdb-a724f0f4f542cfa496da75b817f7d63e6727dcc1.zip gdb-a724f0f4f542cfa496da75b817f7d63e6727dcc1.tar.gz gdb-a724f0f4f542cfa496da75b817f7d63e6727dcc1.tar.bz2 |
gas/
2005-03-17 Jan Beulich <jbeulich@novell.com>
* config/tc-i386.c (i386_scale): Beautify error message.
(Intel syntax comments): Update.
(struct intel_parser_s): Add fields in_offset, in_bracket, and
next_operand.
(intel_e04_1, intel_e05_1, intel_e05_1, intel_e09_1, intel_e10_1):
Remove declarations.
(intel_bracket_expr): Declare.
(i386_intel_operand): Initialize new intel_parser fields. Wrap most
of the function body in a loop allowing to split an operand into two.
Replace calls to malloc and checks of it returning non-NULL with
calls to xmalloc/xstrdup.
(intel_expr): SHORT no longer handled here. Add comment indicating
comparison ops need implementation.
(intel_e04, intel_e04_1): Combine, replace recursion with loop.
Check right operand of - does not specify a register when parsing
the address of a memory reference.
(intel_e05, intel_e05_1): Combine, replace recursion with loop.
Check operands do not specify a register when parsing the address of
a memory reference.
(intel_e06, intel_e06_1): Likewise.
(intel_e09, intel_e09_1): Combine, replace recursion with loop. Also
handle SHORT as well as unary + and -. Don't accept : except for
segment overrides or in direct far jump/call insns.
(intel_brack_expr): New.
(intel_e10, intel_e10_1): Combine, replace recursion with loop. Use
intel_brack_expr.
(intel_e11): Replace chain of if/else-if by switch, alloing fall-
through in certain cases. Use intel_brack_expr. Add new diagnostics.
Allow symbolic constants as register scale value.
(intel_get_token): Replace call to malloc and check of return value
with call to xmalloc. Change handling for FLAT to match MASM's.
(intel_putback_token): Don't try to back up/free current token if
that is T_NIL.
gas/testsuite/
2005-03-17 Jan Beulich <jbeulich@novell.com>
* gas/i386/intel.d: Add stderr directive.
* gas/i386/intel.e: New.
* gas/i386/intel16.d: Add stderr directive. Adjust for changed
source.
* gas/i386/intel16.e: New.
* gas/i386/intel16.s: Add instances of addressing forms with base
and index specified in reverse order.
* gas/i386/intelbad.l: Adjust for changed source.
* gas/i386/intelbad.s: Add more operand forms to check.
* gas/i386/intelok.d: Remove -r from objdump options. Add stderr
directive. Adjust for changed source.
* gas/i386/intelok.e: New.
* gas/i386/intelok.s: Define MASM constants byte, word, etc. Add
more operand forms to check.
* gas/i386/x86_64.d: Add stderr directive.
* gas/i386/x86_64.e: New.
* gas/i386/x86_64.s: Adjust for parser changes.
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 36 | ||||
-rw-r--r-- | gas/config/tc-i386.c | 1195 | ||||
-rw-r--r-- | gas/testsuite/ChangeLog | 20 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/intel.d | 1 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/intel.e | 8 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/intel16.d | 11 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/intel16.e | 7 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/intel16.s | 10 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/intelbad.l | 50 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/intelbad.s | 51 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/intelok.d | 77 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/intelok.e | 8 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/intelok.s | 71 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/x86_64.d | 1 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/x86_64.e | 9 | ||||
-rw-r--r-- | gas/testsuite/gas/i386/x86_64.s | 10 |
16 files changed, 1007 insertions, 558 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index db3af83..1610ac5 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,39 @@ +2005-03-17 Jan Beulich <jbeulich@novell.com> + + * config/tc-i386.c (i386_scale): Beautify error message. + (Intel syntax comments): Update. + (struct intel_parser_s): Add fields in_offset, in_bracket, and + next_operand. + (intel_e04_1, intel_e05_1, intel_e05_1, intel_e09_1, intel_e10_1): + Remove declarations. + (intel_bracket_expr): Declare. + (i386_intel_operand): Initialize new intel_parser fields. Wrap most + of the function body in a loop allowing to split an operand into two. + Replace calls to malloc and checks of it returning non-NULL with + calls to xmalloc/xstrdup. + (intel_expr): SHORT no longer handled here. Add comment indicating + comparison ops need implementation. + (intel_e04, intel_e04_1): Combine, replace recursion with loop. + Check right operand of - does not specify a register when parsing + the address of a memory reference. + (intel_e05, intel_e05_1): Combine, replace recursion with loop. + Check operands do not specify a register when parsing the address of + a memory reference. + (intel_e06, intel_e06_1): Likewise. + (intel_e09, intel_e09_1): Combine, replace recursion with loop. Also + handle SHORT as well as unary + and -. Don't accept : except for + segment overrides or in direct far jump/call insns. + (intel_brack_expr): New. + (intel_e10, intel_e10_1): Combine, replace recursion with loop. Use + intel_brack_expr. + (intel_e11): Replace chain of if/else-if by switch, alloing fall- + through in certain cases. Use intel_brack_expr. Add new diagnostics. + Allow symbolic constants as register scale value. + (intel_get_token): Replace call to malloc and check of return value + with call to xmalloc. Change handling for FLAT to match MASM's. + (intel_putback_token): Don't try to back up/free current token if + that is T_NIL. + 2005-03-16 Daniel Jacobowitz <dan@codesourcery.com> * configure.tgt: Set emulation for arm-*-eabi*. diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index bdcb55e..220e99c 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -3965,10 +3965,16 @@ i386_scale (scale) i.log2_scale_factor = 3; break; default: - as_bad (_("expecting scale factor of 1, 2, 4, or 8: got `%s'"), - scale); - input_line_pointer = save; - return NULL; + { + char sep = *input_line_pointer; + + *input_line_pointer = '\0'; + as_bad (_("expecting scale factor of 1, 2, 4, or 8: got `%s'"), + scale); + *input_line_pointer = sep; + input_line_pointer = save; + return NULL; + } } if (i.log2_scale_factor != 0 && i.index_reg == 0) { @@ -5514,6 +5520,9 @@ tc_gen_reloc (section, fixp) | e09 e09 OFFSET e10 + | SHORT e10 + | + e10 + | - e10 | ~ e10 | NOT e10 | e09 PTR e10 @@ -5531,7 +5540,7 @@ tc_gen_reloc (section, fixp) | $ | register - => expr SHORT e04 + => expr expr cmpOp e04 | e04 gpRegister AX | EAX | BX | EBX | CX | ECX | DX | EDX @@ -5562,8 +5571,10 @@ tc_gen_reloc (section, fixp) done by calling parse_register) and eliminate immediate left recursion to implement a recursive-descent parser. - expr SHORT e04 - | e04 + expr e04 expr' + + expr' cmpOp e04 expr' + | Empty e04 e05 e04' @@ -5581,8 +5592,11 @@ tc_gen_reloc (section, fixp) | Empty e09 OFFSET e10 e09' - | ~ e10 - | NOT e10 + | SHORT e10' + | + e10' + | - e10' + | ~ e10' + | NOT e10' | e10 e09' e09' PTR e10 e09' @@ -5618,8 +5632,11 @@ struct intel_parser_s 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; @@ -5660,15 +5677,11 @@ 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_e04_1 PARAMS ((void)); static int intel_e05 PARAMS ((void)); -static int intel_e05_1 PARAMS ((void)); static int intel_e06 PARAMS ((void)); -static int intel_e06_1 PARAMS ((void)); static int intel_e09 PARAMS ((void)); -static int intel_e09_1 PARAMS ((void)); +static int intel_bracket_expr PARAMS ((void)); static int intel_e10 PARAMS ((void)); -static int intel_e10_1 PARAMS ((void)); static int intel_e11 PARAMS ((void)); static int @@ -5679,31 +5692,33 @@ i386_intel_operand (operand_string, got_a_float) int ret; char *p; - /* 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. */ - p = intel_parser.op_string = (char *) malloc (strlen (operand_string) + 1); - if (p == NULL) - abort (); - strcpy (intel_parser.op_string, operand_string); - intel_parser.got_a_float = got_a_float; - intel_parser.op_modifier = -1; - intel_parser.is_mem = 0; - intel_parser.reg = NULL; - intel_parser.disp = (char *) malloc (strlen (operand_string) + 1); - if (intel_parser.disp == NULL) - abort (); - intel_parser.disp[0] = '\0'; - - /* Read the first token and start the parser. */ - intel_get_token (); - ret = intel_expr (); - - if (ret) + 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)"), @@ -5727,18 +5742,46 @@ i386_intel_operand (operand_string, got_a_float) 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) - ret = i386_index_check (operand_string); + { + /* 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 == T_OFFSET + 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); @@ -5747,54 +5790,46 @@ i386_intel_operand (operand_string, got_a_float) return ret; } -/* expr SHORT e04 - | e04 */ +#define NUM_ADDRESS_REGS (!!i.base_reg + !!i.index_reg) + +/* expr e04 expr' + + expr' cmpOp e04 expr' + | Empty */ static int intel_expr () { - /* expr SHORT e04 */ - if (cur_token.code == T_SHORT) - { - intel_parser.op_modifier = T_SHORT; - intel_match_token (T_SHORT); - - return (intel_e04 ()); - } - - /* expr e04 */ - else - return intel_e04 (); + /* XXX Implement the comparison operators. */ + return intel_e04 (); } -/* e04 e06 e04' +/* e04 e05 e04' - e04' addOp e06 e04' + e04' addOp e05 e04' | Empty */ static int intel_e04 () { - return (intel_e05 () && intel_e04_1 ()); -} + int nregs = -1; -static int -intel_e04_1 () -{ - /* e04' addOp e05 e04' */ - if (cur_token.code == '+' || cur_token.code == '-') + for (;;) { - char str[2]; + if (!intel_e05()) + return 0; - str[0] = cur_token.code; - str[1] = 0; - strcat (intel_parser.disp, str); - intel_match_token (cur_token.code); + if (nregs >= 0 && NUM_ADDRESS_REGS > nregs) + i.base_reg = i386_regtab + REGNAM_AL; /* al is invalid as base */ - return (intel_e05 () && intel_e04_1 ()); - } + if (cur_token.code == '+') + nregs = -1; + else if (cur_token.code == '-') + nregs = NUM_ADDRESS_REGS; + else + return 1; - /* e04' Empty */ - else - return 1; + strcat (intel_parser.disp, cur_token.str); + intel_match_token (cur_token.code); + } } /* e05 e06 e05' @@ -5804,28 +5839,32 @@ intel_e04_1 () static int intel_e05 () { - return (intel_e06 () && intel_e05_1 ()); -} + int nregs = ~NUM_ADDRESS_REGS; -static int -intel_e05_1 () -{ - /* e05' binOp e06 e05' */ - if (cur_token.code == '&' || cur_token.code == '|' || cur_token.code == '^') + for (;;) { - char str[2]; + 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; - str[0] = cur_token.code; - str[1] = 0; - strcat (intel_parser.disp, str); intel_match_token (cur_token.code); - return (intel_e06 () && intel_e05_1 ()); + if (nregs < 0) + nregs = ~nregs; } - - /* e05' Empty */ - else - return 1; + 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' @@ -5835,49 +5874,44 @@ intel_e05_1 () static int intel_e06 () { - return (intel_e09 () && intel_e06_1 ()); -} + int nregs = ~NUM_ADDRESS_REGS; -static int -intel_e06_1 () -{ - /* e06' mulOp e09 e06' */ - if (cur_token.code == '*' || cur_token.code == '/' || cur_token.code == '%') + for (;;) { - char str[2]; + if (!intel_e09()) + return 0; - str[0] = cur_token.code; - str[1] = 0; - strcat (intel_parser.disp, str); - intel_match_token (cur_token.code); + if (cur_token.code == '*' || cur_token.code == '/' || cur_token.code == '%') + { + char str[2]; - return (intel_e09 () && intel_e06_1 ()); - } - else if (cur_token.code == T_SHL) - { - strcat (intel_parser.disp, "<<"); - intel_match_token (cur_token.code); + 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; - return (intel_e09 () && intel_e06_1 ()); - } - else if (cur_token.code == T_SHR) - { - strcat (intel_parser.disp, ">>"); - intel_match_token (cur_token.code); + intel_match_token (cur_token.code); - return (intel_e09 () && intel_e06_1 ()); + if (nregs < 0) + nregs = ~nregs; } - - /* e06' Empty */ - else - return 1; + if (nregs >= 0 && NUM_ADDRESS_REGS > nregs) + i.base_reg = i386_regtab + REGNAM_AL + 2; /* dl is invalid as base */ + return 1; } -/* e09 OFFSET e10 e09' - | e10 e09' - - e09 ~ e10 e09' - | NOT e10 e09' +/* e09 OFFSET e09 + | SHORT e09 + | + e09 + | - e09 + | ~ e09 + | NOT e09 | e10 e09' e09' PTR e10 e09' @@ -5886,146 +5920,277 @@ intel_e06_1 () static int intel_e09 () { - /* e09 OFFSET e10 e09' */ - if (cur_token.code == T_OFFSET) + int nregs = ~NUM_ADDRESS_REGS; + int in_offset = 0; + + for (;;) { - intel_parser.is_mem = 0; - intel_parser.op_modifier = T_OFFSET; - intel_match_token (T_OFFSET); + /* 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]; - return (intel_e10 () && intel_e09_1 ()); + 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); } - /* e09 NOT e10 e09' */ - else if (cur_token.code == '~') + for (;;) { - char str[2]; + if (!intel_e10 ()) + return 0; - str[0] = cur_token.code; - str[1] = 0; - strcat (intel_parser.disp, str); - intel_match_token (cur_token.code); + /* e09' PTR e10 e09' */ + if (cur_token.code == T_PTR) + { + char suffix; - return (intel_e10 () && intel_e09_1 ()); - } + if (prev_token.code == T_BYTE) + suffix = BYTE_MNEM_SUFFIX; - /* e09 e10 e09' */ - else - return (intel_e10 () && intel_e09_1 ()); -} + 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; + } -static int -intel_e09_1 () -{ - /* e09' PTR e10 e09' */ - if (cur_token.code == T_PTR) - { - char 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|JumpInterSegment))) + suffix = LONG_DOUBLE_MNEM_SUFFIX; + else if (intel_parser.got_a_float == 1) /* "f..." */ + suffix = SHORT_MNEM_SUFFIX; + else + suffix = LONG_MNEM_SUFFIX; + } - if (prev_token.code == T_BYTE) - suffix = BYTE_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_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_QWORD) + { + if (intel_parser.got_a_float == 1) /* "f..." */ + suffix = LONG_MNEM_SUFFIX; + else + suffix = QWORD_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|JumpInterSegment))) - 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_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_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) + else if (prev_token.code == T_XMMWORD) { - if (flag_code == CODE_16BIT) - add_prefix (DATA_PREFIX_OPCODE); - suffix = LONG_DOUBLE_MNEM_SUFFIX; + /* XXX ignored for now, but accepted since gcc uses it */ + suffix = 0; } - 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; - } + { + as_bad (_("Unknown operand modifier `%s'"), prev_token.str); + return 0; + } + + 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; + } - 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) + /* e09' : e10 e09' */ + else if (cur_token.code == ':') { - /* XXX ignored for now, but accepted since gcc uses it */ - suffix = 0; + 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 - { - as_bad (_("Unknown operand modifier `%s'"), prev_token.str); - return 0; - } + break; - if (current_templates->start->base_opcode == 0x8d /* lea */) - ; - else if (!i.suffix) - i.suffix = suffix; - else if (i.suffix != suffix) + 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 (_("Conflicting operand modifiers")); + as_bad (_("Invalid operand to `OFFSET'")); return 0; } + intel_parser.op_modifier |= 1 << T_OFFSET; + } - intel_match_token (T_PTR); + if (nregs >= 0 && NUM_ADDRESS_REGS > nregs) + i.base_reg = i386_regtab + REGNAM_AL + 3; /* bl is invalid as base */ + return 1; +} - return (intel_e10 () && intel_e09_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; + /* 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, "+"); - /* e09 : e10 e09' */ - else if (cur_token.code == ':') + if (intel_expr () + && (len = intel_parser.op_string - start - 1, + intel_match_token (']'))) { - /* Mark as a memory operand only if it's not already known to be an - offset expression. */ - if (intel_parser.op_modifier != T_OFFSET) - intel_parser.is_mem = 1; + /* 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 (intel_match_token (':') && intel_e10 () && intel_e09_1 ()); + return 1; } - - /* e09' Empty */ - else - return 1; + return 0; } /* e10 e11 e10' @@ -6035,45 +6200,16 @@ intel_e09_1 () static int intel_e10 () { - return (intel_e11 () && intel_e10_1 ()); -} + if (!intel_e11 ()) + return 0; -static int -intel_e10_1 () -{ - /* e10' [ expr ] e10' */ - if (cur_token.code == '[') + while (cur_token.code == '[') { - 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.op_modifier != T_OFFSET) - intel_parser.is_mem = 1; - 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 () && intel_match_token (']')) - { - /* Preserve brackets when the operand is an offset expression. */ - if (intel_parser.op_modifier == T_OFFSET) - strcat (intel_parser.disp, "]"); - - return intel_e10_1 (); - } - else + if (!intel_bracket_expr ()) return 0; } - /* e10' Empty */ - else - return 1; + return 1; } /* e11 ( expr ) @@ -6094,9 +6230,10 @@ intel_e10_1 () static int intel_e11 () { - /* e11 ( expr ) */ - if (cur_token.code == '(') + switch (cur_token.code) { + /* e11 ( expr ) */ + case '(': intel_match_token ('('); strcat (intel_parser.disp, "("); @@ -6105,318 +6242,299 @@ intel_e11 () strcat (intel_parser.disp, ")"); return 1; } - else - return 0; - } - - /* e11 [ expr ] */ - else if (cur_token.code == '[') - { - 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.op_modifier != T_OFFSET) - intel_parser.is_mem = 1; - else - strcat (intel_parser.disp, "["); + return 0; - /* Operands for jump/call inside brackets denote absolute addresses. */ + /* e11 [ expr ] */ + case '[': + /* Operands for jump/call inside brackets denote absolute addresses. + XXX This shouldn't be needed anymore (or if it should rather live + in intel_bracket_expr). */ if (current_templates->start->opcode_modifier & (Jump|JumpDword|JumpByte|JumpInterSegment)) i.types[this_operand] |= JumpAbsolute; - /* 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 () && intel_match_token (']')) - { - /* Preserve brackets when the operand is an offset expression. */ - if (intel_parser.op_modifier == T_OFFSET) - strcat (intel_parser.disp, "]"); - - return 1; - } - else - return 0; - } - - /* e11 BYTE - | WORD - | DWORD - | FWORD - | QWORD - | TBYTE - | OWORD - | XMMWORD */ - else if (cur_token.code == T_BYTE - || cur_token.code == T_WORD - || cur_token.code == T_DWORD - || cur_token.code == T_FWORD - || cur_token.code == T_QWORD - || cur_token.code == T_TBYTE - || cur_token.code == T_XMMWORD) - { - intel_match_token (cur_token.code); + return intel_bracket_expr (); - if (cur_token.code != T_PTR) - { - /* It must have been an identifier; add it to the displacement string. */ - strcat (intel_parser.disp, prev_token.str); - - /* The identifier represents a memory reference only if it's not - preceded by an offset modifier and if it's not an equate. */ - if (intel_parser.op_modifier != T_OFFSET) - { - symbolS *symbolP; - - symbolP = symbol_find(prev_token.str); - if (!symbolP || S_GET_SEGMENT(symbolP) != absolute_section) - intel_parser.is_mem = 1; - } - } - - return 1; - } - - /* e11 $ - | . */ - else if (cur_token.code == '.') - { + /* 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.op_modifier != T_OFFSET) + if (!intel_parser.in_offset) intel_parser.is_mem = 1; return 1; - } - /* e11 register */ - else if (cur_token.code == T_REG) - { - const reg_entry *reg = intel_parser.reg = cur_token.reg; + /* e11 register */ + case T_REG: + { + const reg_entry *reg = intel_parser.reg = cur_token.reg; - intel_match_token (T_REG); + intel_match_token (T_REG); - /* Check for segment change. */ - if (cur_token.code == ':') - { - if (reg->reg_type & (SReg2 | SReg3)) - { - 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; - } - } - else - { - as_bad (_("`%s' is not a valid segment register"), reg->reg_name); - return 0; - } - } + /* 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.is_mem) - { - as_bad (_("Register scaling only allowed in memory operands.")); - return 0; - } + /* 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; + } - /* What follows must be a valid scale. */ - if (intel_match_token ('*') - && strchr ("01248", *cur_token.str)) - { - i.index_reg = reg; - i.types[this_operand] |= BaseIndex; + 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 */ - /* Set the scale after setting the register (otherwise, - i386_scale will complain) */ - i386_scale (cur_token.str); - intel_match_token (T_CONST); - } - else - { - as_bad (_("expecting scale factor of 1, 2, 4, or 8: got `%s'"), - cur_token.str); - return 0; - } - } + /* What follows must be a valid scale. */ + intel_match_token ('*'); + i.index_reg = reg; + i.types[this_operand] |= BaseIndex; - /* 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.is_mem && !(reg->reg_type & (SReg2 | SReg3))) - { - if (i.base_reg && i.index_reg) - { - as_bad (_("Too many register references in memory operand.")); + /* 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); + } - if (i.base_reg == NULL) - i.base_reg = reg; - else - i.index_reg = reg; + /* 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))) + { - i.types[this_operand] |= BaseIndex; - } + 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; + } - /* Offset modifier. Add the register to the displacement string to be - parsed as an immediate expression after we're done. */ - else if (intel_parser.op_modifier == T_OFFSET) - strcat (intel_parser.disp, reg->reg_name); + i.types[this_operand] |= BaseIndex; + } - /* It's neither base nor index nor offset. */ - else - { - i.types[this_operand] |= reg->reg_type & ~BaseIndex; - i.op[this_operand].regs = reg; - i.reg_operands++; - } + /* 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); + } - /* 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.op_modifier != T_OFFSET) - { - char *s = intel_parser.disp; - s += strlen (s) - 1; - if (*s == '+') - *s = '\0'; - } + /* 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; + } - return 1; - } + /* 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'; + } - /* e11 id */ - else if (cur_token.code == T_ID) - { - /* Add the identifier to the displacement string. */ - strcat (intel_parser.disp, cur_token.str); + 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); - /* The identifier represents a memory reference only if it's not - preceded by an offset modifier and if it's not an equate. */ - if (intel_parser.op_modifier != T_OFFSET) + 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 */ - intel_match_token (T_ID); - return 1; - } - - /* e11 constant */ - else if (cur_token.code == T_CONST - || cur_token.code == '-' - || cur_token.code == '+') - { - char *save_str; + case T_CONST: + case '-': + case '+': + { + char *save_str, sign = 0; - /* Allow constants that start with `+' or `-'. */ - if (cur_token.code == '-' || cur_token.code == '+') - { - strcat (intel_parser.disp, cur_token.str); - 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; - } - } + /* 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 *) malloc (strlen (cur_token.str) + 1); - if (save_str == NULL) - abort (); - strcpy (save_str, cur_token.str); + 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); + /* 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) - { - if (!intel_parser.is_mem) - { - as_bad (_("Register scaling only allowed in memory operands.")); + /* 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; - } - - /* The constant is followed by `* reg', so it must be - a valid scale. */ - if (strchr ("01248", *save_str)) - { - i.index_reg = cur_token.reg; - i.types[this_operand] |= BaseIndex; - - /* Set the scale after setting the register (otherwise, - i386_scale will complain) */ - i386_scale (save_str); - 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; - } - else - 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. */ - else + /* 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); + /* Add the constant to the displacement string. */ + strcat (intel_parser.disp, save_str); + free (save_str); - return 1; + return 1; + } } as_bad (_("Unrecognized token '%s'"), cur_token.str); @@ -6473,9 +6591,7 @@ intel_get_token () /* The new token cannot be larger than the remainder of the operand string. */ - new_token.str = (char *) malloc (strlen (intel_parser.op_string) + 1); - if (new_token.str == NULL) - abort (); + new_token.str = (char *) xmalloc (strlen (intel_parser.op_string) + 1); new_token.str[0] = '\0'; if (strchr ("0123456789", *intel_parser.op_string)) @@ -6595,7 +6711,13 @@ intel_get_token () /* ??? This is not mentioned in the MASM grammar. */ else if (strcasecmp (new_token.str, "FLAT") == 0) - new_token.code = T_OFFSET; + { + new_token.code = T_OFFSET; + if (*q == ':') + strcat (new_token.str, ":"); + else + as_bad (_("`:' expected")); + } else new_token.code = T_ID; @@ -6630,8 +6752,11 @@ intel_get_token () static void intel_putback_token () { - intel_parser.op_string -= strlen (cur_token.str); - free (cur_token.str); + if (cur_token.code != T_NIL) + { + intel_parser.op_string -= strlen (cur_token.str); + free (cur_token.str); + } cur_token = prev_token; /* Forget prev_token. */ diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index 86af7eb..630745a 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,23 @@ +2005-03-17 Jan Beulich <jbeulich@novell.com> + + * gas/i386/intel.d: Add stderr directive. + * gas/i386/intel.e: New. + * gas/i386/intel16.d: Add stderr directive. Adjust for changed + source. + * gas/i386/intel16.e: New. + * gas/i386/intel16.s: Add instances of addressing forms with base + and index specified in reverse order. + * gas/i386/intelbad.l: Adjust for changed source. + * gas/i386/intelbad.s: Add more operand forms to check. + * gas/i386/intelok.d: Remove -r from objdump options. Add stderr + directive. Adjust for changed source. + * gas/i386/intelok.e: New. + * gas/i386/intelok.s: Define MASM constants byte, word, etc. Add + more operand forms to check. + * gas/i386/x86_64.d: Add stderr directive. + * gas/i386/x86_64.e: New. + * gas/i386/x86_64.s: Adjust for parser changes. + 2005-03-15 Zack Weinberg <zack@codesourcery.com> * gas/arm/archv6t2.d, gas/arm/archv6t2.s: New dump test. diff --git a/gas/testsuite/gas/i386/intel.d b/gas/testsuite/gas/i386/intel.d index 24f4536..3fb9270 100644 --- a/gas/testsuite/gas/i386/intel.d +++ b/gas/testsuite/gas/i386/intel.d @@ -1,6 +1,7 @@ #as: -J #objdump: -dw #name: i386 intel +#stderr: intel.e .*: +file format .* diff --git a/gas/testsuite/gas/i386/intel.e b/gas/testsuite/gas/i386/intel.e new file mode 100644 index 0000000..b56da1a --- /dev/null +++ b/gas/testsuite/gas/i386/intel.e @@ -0,0 +1,8 @@ +.*: Assembler messages: +.*:154: Warning: Treating .\[0x90909090\]. as memory reference +.*:155: Warning: Treating .\[0x90909090\]. as memory reference +.*:156: Warning: Treating .\[0x90909090\]. as memory reference +.*:157: Warning: Treating .\[0x90909090\]. as memory reference +.*:492: Warning: Treating .\[0x90909090\]. as memory reference +.*:493: Warning: Treating .\[0x90909090\]. as memory reference +.*:580: Warning: Using register names in OFFSET expressions is deprecated diff --git a/gas/testsuite/gas/i386/intel16.d b/gas/testsuite/gas/i386/intel16.d index 79e57d8..495fe14 100644 --- a/gas/testsuite/gas/i386/intel16.d +++ b/gas/testsuite/gas/i386/intel16.d @@ -1,5 +1,6 @@ #objdump: -dw -mi8086 #name: i386 intel16 +#stderr: intel16.e .*: +file format .* @@ -12,4 +13,12 @@ Disassembly of section .text: 11: 66 0f b7 06 00 00 [ ]*movzwl 0,%eax 17: 66 0f b6 06 00 00 [ ]*movzbl 0,%eax 1d: 0f b6 06 00 00 [ ]*movzbw 0,%ax -#pass + 22: 8d 00 [ ]*lea \(%bx,%si\),%ax + 24: 8d 02 [ ]*lea \(%bp,%si\),%ax + 26: 8d 01 [ ]*lea \(%bx,%di\),%ax + 28: 8d 03 [ ]*lea \(%bp,%di\),%ax + 2a: 8d 00 [ ]*lea \(%bx,%si\),%ax + 2c: 8d 02 [ ]*lea \(%bp,%si\),%ax + 2e: 8d 01 [ ]*lea \(%bx,%di\),%ax + 30: 8d 03 [ ]*lea \(%bp,%di\),%ax + ... diff --git a/gas/testsuite/gas/i386/intel16.e b/gas/testsuite/gas/i386/intel16.e new file mode 100644 index 0000000..62da8a7 --- /dev/null +++ b/gas/testsuite/gas/i386/intel16.e @@ -0,0 +1,7 @@ +.*: Assembler messages: +.*:5: Warning: Treating .word ptr \[0\]. as memory reference +.*:6: Warning: Treating .byte ptr \[0\]. as memory reference +.*:7: Warning: Treating .byte ptr \[0\]. as memory reference +.*:8: Warning: Treating .word ptr \[0\]. as memory reference +.*:9: Warning: Treating .byte ptr \[0\]. as memory reference +.*:10: Warning: Treating .byte ptr \[0\]. as memory reference diff --git a/gas/testsuite/gas/i386/intel16.s b/gas/testsuite/gas/i386/intel16.s index bf78ad8..e27b017 100644 --- a/gas/testsuite/gas/i386/intel16.s +++ b/gas/testsuite/gas/i386/intel16.s @@ -8,4 +8,14 @@ movzx eax,word ptr [0] movzx eax,byte ptr [0] movzx ax,byte ptr [0] + + lea ax, [si+bx] + lea ax, [si+bp] + lea ax, [di+bx] + lea ax, [di+bp] + lea ax, [si][bx] + lea ax, [si][bp] + lea ax, [di][bx] + lea ax, [di][bp] + .p2align 4,0 diff --git a/gas/testsuite/gas/i386/intelbad.l b/gas/testsuite/gas/i386/intelbad.l index 45c21d2..5eaa5d1 100644 --- a/gas/testsuite/gas/i386/intelbad.l +++ b/gas/testsuite/gas/i386/intelbad.l @@ -59,3 +59,53 @@ .*:89: Error: .* .*:90: Error: .* .*:91: Error: .* +.*:94: Error: .* +.*:95: Error: .* +.*:96: Error: .* +.*:97: Error: .* +.*:98: Error: .* +.*:99: Error: .* +.*:100: Error: .* +.*:101: Error: .* +.*:102: Error: .* +.*:103: Error: .* +.*:104: Error: .* +.*:105: Error: .* +.*:106: Error: .* +.*:107: Error: .* +.*:108: Error: .* +.*:109: Error: .* +.*:110: Error: .* +.*:111: Error: .* +.*:112: Error: .* +.*:113: Error: .* +.*:114: Error: .* +.*:115: Error: .* +.*:116: Error: .* +.*:117: Error: .* +.*:118: Error: .* +.*:119: Error: .* +.*:120: Error: .* +.*:121: Error: .* +.*:122: Error: .* +.*:123: Error: .* +.*:124: Error: .* +.*:125: Error: .* +.*:126: Error: .* +.*:127: Error: .* +.*:128: Error: .* +#... +.*:129: Error: .* +#... +.*:130: Error: .* +.*:131: Error: .* +.*:132: Error: .* +.*:133: Error: .* +.*:135: Warning: .* +.*:136: Warning: .* +.*:137: Warning: .* +.*:138: Warning: .* +.*:139: Warning: .* +.*:141: Error: .* +.*:142: Warning: .* +.*:142: Error: .* diff --git a/gas/testsuite/gas/i386/intelbad.s b/gas/testsuite/gas/i386/intelbad.s index c4b03f3..2a9daad 100644 --- a/gas/testsuite/gas/i386/intelbad.s +++ b/gas/testsuite/gas/i386/intelbad.s @@ -89,3 +89,54 @@ start: push 1 1 push 1 + push 1 * * 1 + + # memory references + mov eax, [ecx*3] + mov eax, [3*ecx] + mov eax, [-1*ecx + 1] + mov eax, [esp + esp] + mov eax, [eax - 1*ecx + 1] + mov eax, [(eax-1) * (eax-1)] + mov eax, [eax-1 xor eax-1] + mov eax, [(eax-1) xor (eax-1)] + mov eax, [not eax + 1] + mov eax, [ecx*2 + edx*4] + mov eax, [2*ecx + 4*edx] + mov eax, [eax]1[ecx] # ugly diag + mov eax, [eax][ecx]1 # ugly diag + mov eax, eax[ecx] # ugly diag + mov eax, es[ecx] + mov eax, cr0[ecx] + mov eax, [eax]ecx + mov eax, [eax]+ecx + mov eax, [eax]+ecx*2 + mov eax, [eax]+2*ecx + mov eax, [[eax]ecx] + mov eax, eax:[ecx] + lea eax, [bx+si*1] + lea eax, [bp+si*2] + lea eax, [bx+di*4] + lea eax, [bp+di*8] + lea eax, [bx+1*si] + lea eax, [bp+2*si] + lea eax, [bx+4*di] + lea eax, [bp+8*di] + mov eax, [ah] + mov eax, [ax] + mov eax, [eax+bx] + mov eax, offset [1*eax] + mov eax, offset 1*eax + mov eax, offset x[eax] # ugly diag + mov eax, offset [x][eax] # ugly diag + mov eax, flat x + mov eax, flat [x] + mov eax, es:eax + + mov eax, offset [eax] + mov eax, offset eax + mov eax, offset offset eax + mov eax, es:ss:[eax] + mov eax, es:[eax]+ss:[eax] + + mov eax, 3:5 + call 3:[5] diff --git a/gas/testsuite/gas/i386/intelok.d b/gas/testsuite/gas/i386/intelok.d index f596eb6..e8a80a7 100644 --- a/gas/testsuite/gas/i386/intelok.d +++ b/gas/testsuite/gas/i386/intelok.d @@ -1,6 +1,7 @@ #as: -J -#objdump: -drwMintel +#objdump: -dwMintel #name: i386 intel-ok +#stderr: intelok.e .*: +file format .* @@ -93,20 +94,39 @@ Disassembly of section .text: [ ]*[0-9a-f]+: d7[ ]+xlat(b|[ ]+(BYTE PTR )?(ds:)?\[ebx\]) [ ]*[0-9a-f]+: d7[ ]+xlat(b|[ ]+(BYTE PTR )?(ds:)?\[ebx\]) [ ]*[0-9a-f]+: d7[ ]+xlat(b|[ ]+(BYTE PTR )?(ds:)?\[ebx\]) -[ ]*[0-9a-f]+: 8b 80 00 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\][ ]+[0-9a-f]+:[ ]+(R_386_|dir)?32[ ]+byte -[ ]*[0-9a-f]+: 8b 80 00 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\][ ]+[0-9a-f]+:[ ]+(R_386_|dir)?32[ ]+byte +[ ]*[0-9a-f]+: 8b 40 01[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+1\] +[ ]*[0-9a-f]+: 8b 40 01[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+1\] [ ]*[0-9a-f]+: 8b 40 04[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+4\] [ ]*[0-9a-f]+: 8b 40 04[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+4\] -[ ]*[0-9a-f]+: 8b 80 00 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\][ ]+[0-9a-f]+:[ ]+(R_386_|dir)?32[ ]+fword -[ ]*[0-9a-f]+: 8b 80 00 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\][ ]+[0-9a-f]+:[ ]+(R_386_|dir)?32[ ]+fword -[ ]*[0-9a-f]+: 8b 80 04 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+4\][ ]+[0-9a-f]+:[ ]+(R_386_|dir)?32[ ]+qword -[ ]*[0-9a-f]+: 8b 80 04 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+4\][ ]+[0-9a-f]+:[ ]+(R_386_|dir)?32[ ]+qword -[ ]*[0-9a-f]+: 8b 80 08 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+8\][ ]+[0-9a-f]+:[ ]+(R_386_|dir)?32[ ]+tbyte -[ ]*[0-9a-f]+: 8b 80 08 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+8\][ ]+[0-9a-f]+:[ ]+(R_386_|dir)?32[ ]+tbyte -#[ ]*[0-9a-f]+: 8b 04 85 00 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\*4\][ ]+[0-9a-f]+:[ ]+(R_386_|dir)?32[ ]+word -#[ ]*[0-9a-f]+: 8b 04 85 00 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\*4\][ ]+[0-9a-f]+:[ ]+(R_386_|dir)?32[ ]+word -#[ ]*[0-9a-f]+: 8b 04 85 04 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\*4\+4\][ ]+[0-9a-f]+:[ ]+(R_386_|dir)?32[ ]+xmmword -#[ ]*[0-9a-f]+: 8b 04 85 04 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\*4\+4\][ ]+[0-9a-f]+:[ ]+(R_386_|dir)?32[ ]+xmmword +[ ]*[0-9a-f]+: 8b 40 06[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+6\] +[ ]*[0-9a-f]+: 8b 40 06[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+6\] +[ ]*[0-9a-f]+: 8b 40 0c[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+12\] +[ ]*[0-9a-f]+: 8b 40 0c[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+12\] +[ ]*[0-9a-f]+: 8b 40 12[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+18\] +[ ]*[0-9a-f]+: 8b 40 12[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+18\] +[ ]*[0-9a-f]+: 8b 04 85 02 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\*4\+2\] +[ ]*[0-9a-f]+: 8b 04 85 02 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\*4\+2\] +[ ]*[0-9a-f]+: 8b 04 45 00 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\*2\] +[ ]*[0-9a-f]+: 8b 04 45 00 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\*2\] +[ ]*[0-9a-f]+: 8b 04 8d 00 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[ecx\*4\] +[ ]*[0-9a-f]+: 8b 04 8d 00 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[ecx\*4\] +[ ]*[0-9a-f]+: 8b 40 01[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+1\] +[ ]*[0-9a-f]+: 8b 40 01[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+1\] +[ ]*[0-9a-f]+: 8b 44 08 fb[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+ecx\-5\] +[ ]*[0-9a-f]+: 8b 44 08 01[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+ecx\+1\] +[ ]*[0-9a-f]+: 8b 44 08 0f[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+ecx\+15\] +[ ]*[0-9a-f]+: 8b 40 10[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+16\] +[ ]*[0-9a-f]+: 8b 40 10[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+16\] +[ ]*[0-9a-f]+: 8b 44 08 10[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+ecx\+16\] +[ ]*[0-9a-f]+: 8b 44 08 01[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+ecx\+1\] +[ ]*[0-9a-f]+: 8b 44 08 01[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+ecx\+1\] +[ ]*[0-9a-f]+: 8b 44 08 01[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+ecx\+1\] +[ ]*[0-9a-f]+: 8b 44 08 01[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+ecx\+1\] +[ ]*[0-9a-f]+: 8b 44 08 01[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+ecx\+1\] +[ ]*[0-9a-f]+: 8b 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\] +[ ]*[0-9a-f]+: 8b 04 08[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+ecx\] +[ ]*[0-9a-f]+: 8b 04 08[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+ecx\] +[ ]*[0-9a-f]+: 26 8b 00[ ]+mov[ ]+eax,es:(DWORD PTR )?\[eax\] [ ]*[0-9a-f]+: 6a 01[ ]+push[ ]+0x1 [ ]*[0-9a-f]+: 6a ff[ ]+push[ ]+0xffffffff [ ]*[0-9a-f]+: 6a fe[ ]+push[ ]+0xfffffffe @@ -120,4 +140,35 @@ Disassembly of section .text: [ ]*[0-9a-f]+: 6a 02[ ]+push[ ]+0x2 [ ]*[0-9a-f]+: 6a 03[ ]+push[ ]+0x3 [ ]*[0-9a-f]+: 6a 0d[ ]+push[ ]+0xd +[ ]*[0-9a-f]+: 6a 04[ ]+push[ ]+0x4 +[ ]*[0-9a-f]+: 6a fc[ ]+push[ ]+0xfffffffc +[ ]*[0-9a-f]+: 6a fb[ ]+push[ ]+0xfffffffb +[ ]*[0-9a-f]+: 6a fb[ ]+push[ ]+0xfffffffb +[ ]*[0-9a-f]+: 6a 03[ ]+push[ ]+0x3 +[ ]*[0-9a-f]+: 6a 04[ ]+push[ ]+0x4 +[ ]*[0-9a-f]+: b8 00 00 00 00[ ]+mov[ ]+eax,0x0 +[ ]*[0-9a-f]+: b8 00 00 00 00[ ]+mov[ ]+eax,0x0 +[ ]*[0-9a-f]+: b8 00 00 00 00[ ]+mov[ ]+eax,0x0 +[ ]*[0-9a-f]+: b8 00 00 00 00[ ]+mov[ ]+eax,0x0 +[ ]*[0-9a-f]+: b8 00 00 00 00[ ]+mov[ ]+eax,0x0 +[ ]*[0-9a-f]+: b8 00 00 00 00[ ]+mov[ ]+eax,0x0 +[ ]*[0-9a-f]+: b8 00 00 00 00[ ]+mov[ ]+eax,0x0 +[ ]*[0-9a-f]+: 8b 80 00 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\] +[ ]*[0-9a-f]+: 8b 40 01[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+1] +[ ]*[0-9a-f]+: 8b 80 00 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\] +[ ]*[0-9a-f]+: 8b 80 01 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+1\] +[ ]*[0-9a-f]+: 8b 80 00 00 00 00[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\] +[ ]*[0-9a-f]+: 8b 40 01[ ]+mov[ ]+eax,(DWORD PTR )?\[eax\+1\] +[ ]*[0-9a-f]+: a1 01 00 00 00[ ]+mov[ ]+eax,ds:0x1 +[ ]*[0-9a-f]+: a1 ff ff ff ff[ ]+mov[ ]+eax,ds:0xffffffff +[ ]*[0-9a-f]+: 26 a1 02 00 00 00[ ]+mov[ ]+eax,es:0x2 +#... +[ ]*[0-9a-f]+: b8 03 00 00 00[ ]+mov[ ]+eax,0x3 +[ ]*[0-9a-f]+: a1 04 00 00 00[ ]+mov[ ]+eax,ds:0x4 +[ ]*[0-9a-f]+: a1 05 00 00 00[ ]+mov[ ]+eax,ds:0x5 +[ ]*[0-9a-f]+: 36 a1 06 00 00 00[ ]+mov[ ]+eax,ss:0x6 +[ ]*[0-9a-f]+: 36 a1 07 00 00 00[ ]+mov[ ]+eax,ss:0x7 +[ ]*[0-9a-f]+: a1 08 00 00 00[ ]+mov[ ]+eax,ds:0x8 +[ ]*[0-9a-f]+: 9a 05 00 00 00 03 00[ ]+l?call[ ]+0x3[,:]0x5 +[ ]*[0-9a-f]+: ea 03 00 00 00 05 00[ ]+l?jmp[ ]+0x5[,:]0x3 #pass diff --git a/gas/testsuite/gas/i386/intelok.e b/gas/testsuite/gas/i386/intelok.e new file mode 100644 index 0000000..8403bf2 --- /dev/null +++ b/gas/testsuite/gas/i386/intelok.e @@ -0,0 +1,8 @@ +.*: Assembler messages: +.*:170: Warning: .* taken to mean just .* +.*:177: Warning: Treating .* as memory reference +.*:178: Warning: .* taken to mean just .* +.*:178: Warning: Treating .* as memory reference +.*:181: Warning: Treating .* as memory reference +.*:182: Warning: Treating .* as memory reference +.*:185: Warning: Treating .* as memory reference diff --git a/gas/testsuite/gas/i386/intelok.s b/gas/testsuite/gas/i386/intelok.s index 590d793..a35b38c 100644 --- a/gas/testsuite/gas/i386/intelok.s +++ b/gas/testsuite/gas/i386/intelok.s @@ -1,5 +1,12 @@ .intel_syntax noprefix + .equiv byte, 1 + .equiv word, 2 .equiv dword, 4 + .equiv fword, 6 + .equiv qword, 8 + .equiv tbyte, 10 + .equiv oword, 16 + .equiv xmmword, 16 .text start: @@ -104,10 +111,30 @@ start: mov eax, qword[eax+dword] mov eax, [tbyte+eax+dword*2] mov eax, tbyte[eax+dword*2] -# mov eax, [word+eax*dword] -# mov eax, word[eax*dword] -# mov eax, [xmmword+(eax+1)*dword] -# mov eax, xmmword[(eax+1)*dword] + mov eax, [word+eax*dword] + mov eax, word[eax*dword] + + mov eax, [eax*+2] + mov eax, [+2*eax] + mov eax, [ecx*dword] + mov eax, [dword*ecx] + mov eax, 1[eax] + mov eax, [eax]+1 + mov eax, [eax - 5 + ecx] + mov eax, [eax + 5 and 3 + ecx] + mov eax, [eax + 5*3 + ecx] + mov eax, [oword][eax] + mov eax, [eax][oword] + mov eax, xmmword[eax][ecx] + mov eax, [eax]+1[ecx] + mov eax, [eax][ecx]+1 + mov eax, [1][eax][ecx] + mov eax, [eax][1][ecx] + mov eax, [eax][ecx][1] + mov eax, [[eax]] + mov eax, [eax[ecx]] + mov eax, [[eax][ecx]] + mov eax, es:[eax] # expressions @@ -125,5 +152,41 @@ start: push 7 xor 4 push 8 or 5 + push +dword + push -dword + push not dword + push not +dword + push not -dword + push not not dword + + # offset expressions + + mov eax, offset x + mov eax, offset flat:x + mov eax, flat:x + mov eax, offset [x] + mov eax, offset flat:[x] + mov eax, flat:[x] + mov eax, [offset x] + mov eax, [eax + offset x] + mov eax, [eax + offset 1] + mov eax, [offset x + eax] + mov eax, offset x+1[eax] + mov eax, [eax] + offset x + mov eax, [eax] + offset 1 + mov eax, offset x + [1] + mov eax, [offset x] - [1] + mov eax, offset x + es:[2] + mov eax, offset x + offset es:[3] + mov eax, [4] + offset x + mov eax, [5] + [offset x] + mov eax, ss:[6] + offset x + mov eax, ss:[7] + [offset x] + mov eax, dword ptr [8] + + # other operands + call 3:5 + jmp 5:3 + # Force a good alignment. .p2align 4,0 diff --git a/gas/testsuite/gas/i386/x86_64.d b/gas/testsuite/gas/i386/x86_64.d index 92ae3af..7cea081 100644 --- a/gas/testsuite/gas/i386/x86_64.d +++ b/gas/testsuite/gas/i386/x86_64.d @@ -1,6 +1,7 @@ #as: -J #objdump: -dw #name: i386 x86_64 +#stderr: x86_64.e .*: +file format .* Disassembly of section .text: diff --git a/gas/testsuite/gas/i386/x86_64.e b/gas/testsuite/gas/i386/x86_64.e new file mode 100644 index 0000000..e11e903 --- /dev/null +++ b/gas/testsuite/gas/i386/x86_64.e @@ -0,0 +1,9 @@ +.*.s: Assembler messages: +.*:51: Warning: Treating .\[0x22222222\]. as memory reference +.*:89: Warning: Treating .DWORD PTR \[0x22222222\]. as memory reference +.*:91: Warning: Treating .\[0x8877665544332211\]. as memory reference +.*:92: Warning: Treating .\[0x8877665544332211\]. as memory reference +.*:93: Warning: Treating .\[0x8877665544332211\]. as memory reference +.*:94: Warning: Treating .\[0x8877665544332211\]. as memory reference +.*:95: Warning: Treating .\[0x8877665544332211\]. as memory reference +.*:96: Warning: Treating .\[0x8877665544332211\]. as memory reference diff --git a/gas/testsuite/gas/i386/x86_64.s b/gas/testsuite/gas/i386/x86_64.s index ad2a48d..4e94a50 100644 --- a/gas/testsuite/gas/i386/x86_64.s +++ b/gas/testsuite/gas/i386/x86_64.s @@ -127,12 +127,12 @@ mov symbol(%rip), %eax .intel_syntax noprefix #immediates - various sizes: -mov al, flat symbol -mov ax, flat symbol -mov eax, flat symbol -mov rax, flat symbol +mov al, flat:symbol +mov ax, flat:symbol +mov eax, flat:symbol +mov rax, flat:symbol -#parts aren't supported by the parser +#parts aren't supported by the parser, yet (and not at all for symbol refs) #mov eax, high part symbol #mov eax, low part symbol |