This is the mail archive of the gas2@sourceware.cygnus.com mailing list for the gas2 project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
I finally just decided to do this myself; wasn't too hard. This patch creates '.code16' and '.code32' pseudo-opcodes for i386 gas, which determine whether it writes 16-bit or 32-bit code. When writing 16-bit code, it still only uses 32-bit addressing modes, so the resulting code is suboptimal; but how much performance-critical 16-bit code is there these days anyway? :-) BTW, this patch is to binutils-2.5.2. Please acknowledge that you've received it and when you expect it'll appear in a release. Thanks! *** include/opcode/old/i386.h Fri Nov 25 07:11:50 1994 --- include/opcode/i386.h Fri Nov 25 08:09:00 1994 *************** *** 36,43 **** conflict with the "movs" string move instruction. Thus, {"movsb", 2, 0x0fbe, _, ReverseRegRegmem|Modrm, { Reg8|Mem, Reg16|Reg32, 0} }, is not kosher; we must seperate the two instructions. */ ! {"movsbl", 2, 0x0fbe, _, ReverseRegRegmem|Modrm, { Reg8|Mem, Reg32, 0} }, ! {"movsbw", 2, 0x660fbe, _, ReverseRegRegmem|Modrm, { Reg8|Mem, Reg16, 0} }, {"movswl", 2, 0x0fbf, _, ReverseRegRegmem|Modrm, { Reg16|Mem, Reg32, 0} }, /* move with zero extend */ --- 36,43 ---- conflict with the "movs" string move instruction. Thus, {"movsb", 2, 0x0fbe, _, ReverseRegRegmem|Modrm, { Reg8|Mem, Reg16|Reg32, 0} }, is not kosher; we must seperate the two instructions. */ ! {"movsbl", 2, 0x0fbe, _, ReverseRegRegmem|Modrm|Data32, { Reg8|Mem, Reg32, 0} }, ! {"movsbw", 2, 0x0fbe, _, ReverseRegRegmem|Modrm|Data16, { Reg8|Mem, Reg16, 0} }, {"movswl", 2, 0x0fbf, _, ReverseRegRegmem|Modrm, { Reg16|Mem, Reg32, 0} }, /* move with zero extend */ *************** *** 167,181 **** /* conversion insns */ /* conversion: intel naming */ ! {"cbw", 0, 0x6698, _, NoModrm, { 0, 0, 0} }, ! {"cwd", 0, 0x6699, _, NoModrm, { 0, 0, 0} }, ! {"cwde", 0, 0x98, _, NoModrm, { 0, 0, 0} }, ! {"cdq", 0, 0x99, _, NoModrm, { 0, 0, 0} }, /* att naming */ ! {"cbtw", 0, 0x6698, _, NoModrm, { 0, 0, 0} }, ! {"cwtl", 0, 0x98, _, NoModrm, { 0, 0, 0} }, ! {"cwtd", 0, 0x6699, _, NoModrm, { 0, 0, 0} }, ! {"cltd", 0, 0x99, _, NoModrm, { 0, 0, 0} }, /* Warning! the mul/imul (opcode 0xf6) must only have 1 operand! They are expanding 64-bit multiplies, and *cannot* be selected to accomplish --- 167,181 ---- /* conversion insns */ /* conversion: intel naming */ ! {"cbw", 0, 0x98, _, NoModrm|Data16, { 0, 0, 0} }, ! {"cwd", 0, 0x99, _, NoModrm|Data16, { 0, 0, 0} }, ! {"cwde", 0, 0x98, _, NoModrm|Data32, { 0, 0, 0} }, ! {"cdq", 0, 0x99, _, NoModrm|Data32, { 0, 0, 0} }, /* att naming */ ! {"cbtw", 0, 0x98, _, NoModrm|Data16, { 0, 0, 0} }, ! {"cwtl", 0, 0x98, _, NoModrm|Data32, { 0, 0, 0} }, ! {"cwtd", 0, 0x99, _, NoModrm|Data16, { 0, 0, 0} }, ! {"cltd", 0, 0x99, _, NoModrm|Data32, { 0, 0, 0} }, /* Warning! the mul/imul (opcode 0xf6) must only have 1 operand! They are expanding 64-bit multiplies, and *cannot* be selected to accomplish *************** *** 321,334 **** {"jnle", 1, 0x7f, _, Jump, { Disp, 0, 0} }, {"jg", 1, 0x7f, _, Jump, { Disp, 0, 0} }, /* these turn into pseudo operations when disp is larger than 8 bits */ #define IS_JUMP_ON_CX_ZERO(o) \ (o == 0x66e3) #define IS_JUMP_ON_ECX_ZERO(o) \ (o == 0xe3) ! {"jcxz", 1, 0x66e3, _, JumpByte, { Disp, 0, 0} }, ! {"jecxz", 1, 0xe3, _, JumpByte, { Disp, 0, 0} }, #define IS_LOOP_ECX_TIMES(o) \ (o == 0xe2 || o == 0xe1 || o == 0xe0) --- 321,339 ---- {"jnle", 1, 0x7f, _, Jump, { Disp, 0, 0} }, {"jg", 1, 0x7f, _, Jump, { Disp, 0, 0} }, + #if 0 /* XXX where are these macros used? + To get them working again, they need to take + an entire template as the parameter, + and check for Data16/Data32 flags. */ /* these turn into pseudo operations when disp is larger than 8 bits */ #define IS_JUMP_ON_CX_ZERO(o) \ (o == 0x66e3) #define IS_JUMP_ON_ECX_ZERO(o) \ (o == 0xe3) + #endif ! {"jcxz", 1, 0xe3, _, JumpByte|Data16, { Disp, 0, 0} }, ! {"jecxz", 1, 0xe3, _, JumpByte|Data32, { Disp, 0, 0} }, #define IS_LOOP_ECX_TIMES(o) \ (o == 0xe2 || o == 0xe1 || o == 0xe0) *************** *** 432,439 **** /* i386sl (and i486sl?) only */ {"rsm", 0, 0x0faa, _, NoModrm,{ 0, 0, 0} }, ! {"boundl", 2, 0x62, _, Modrm, { Reg32, Mem, 0} }, ! {"boundw", 2, 0x6662, _, Modrm, { Reg16, Mem, 0} }, {"hlt", 0, 0xf4, _, NoModrm, { 0, 0, 0} }, {"wait", 0, 0x9b, _, NoModrm, { 0, 0, 0} }, --- 437,444 ---- /* i386sl (and i486sl?) only */ {"rsm", 0, 0x0faa, _, NoModrm,{ 0, 0, 0} }, ! {"boundl", 2, 0x62, _, Modrm|Data32, { Reg32, Mem, 0} }, ! {"boundw", 2, 0x62, _, Modrm|Data16, { Reg16, Mem, 0} }, {"hlt", 0, 0xf4, _, NoModrm, { 0, 0, 0} }, {"wait", 0, 0x9b, _, NoModrm, { 0, 0, 0} }, *************** *** 808,813 **** --- 813,819 ---- }; static const prefix_entry i386_prefixtab[] = { + #define ADDR_PREFIX_OPCODE 0x67 { "addr16", 0x67 }, /* address size prefix ==> 16bit addressing * (How is this useful?) */ #define WORD_PREFIX_OPCODE 0x66 *** gas/config/old/tc-i386.h Fri Nov 25 06:34:23 1994 --- gas/config/tc-i386.h Fri Nov 25 08:06:26 1994 *************** *** 125,131 **** #define tc_headers_hook(a) {;} /* not used */ #define MAX_OPERANDS 3 /* max operands per insn */ ! #define MAX_PREFIXES 4 /* max prefixes per opcode */ #define MAX_IMMEDIATE_OPERANDS 2/* max immediates per insn */ #define MAX_MEMORY_OPERANDS 2 /* max memory ref per insn (lcall uses 2) */ --- 125,131 ---- #define tc_headers_hook(a) {;} /* not used */ #define MAX_OPERANDS 3 /* max operands per insn */ ! #define MAX_PREFIXES 5 /* max prefixes per opcode */ #define MAX_IMMEDIATE_OPERANDS 2/* max immediates per insn */ #define MAX_MEMORY_OPERANDS 2 /* max memory ref per insn (lcall uses 2) */ *************** *** 263,268 **** --- 263,270 ---- #define JumpByte 0x4000 #define JumpDword 0x8000 #define ReverseRegRegmem 0x10000 + #define Data16 0x20000 /* needs data prefix if in 32-bit mode */ + #define Data32 0x40000 /* needs data prefix if in 16-bit mode */ /* (opcode_modifier & COMES_IN_ALL_SIZES) is true if the instuction comes in byte, word, and dword sizes and is encoded into *** gas/config/old/tc-i386.c Fri Nov 25 06:34:23 1994 --- gas/config/tc-i386.c Fri Nov 25 08:37:02 1994 *************** *** 174,179 **** --- 174,181 ---- static int flag_do_long_jump; /* FIXME what does this do? */ + static int flag_16bit_code; /* 1 if we're writing 16-bit code, 0 if 32-bit */ + /* Interface to relax_segment. There are 2 relax states for 386 jump insns: one for conditional & one for unconditional jumps. This is because the these two types *************** *** 318,323 **** --- 320,331 ---- : (Imm32)); } /* smallest_imm_type() */ + void set_16bit_code_flag(new_16bit_code_flag) + int new_16bit_code_flag; + { + flag_16bit_code = new_16bit_code_flag; + } + const pseudo_typeS md_pseudo_table[] = { #ifndef I386COFF *************** *** 334,339 **** --- 342,349 ---- {"value", cons, 2}, {"noopt", s_ignore, 0}, {"optim", s_ignore, 0}, + {"code16", set_16bit_code_flag, 1}, + {"code32", set_16bit_code_flag, 0}, {0, 0, 0} }; *************** *** 1034,1039 **** --- 1044,1064 ---- i.tm = *t; t = &i.tm; /* alter new copy of template */ + /* If the matched instruction specifies an explicit opcode suffix, + use it - and make sure none has already been specified. */ + if (t->opcode_modifier & (Data16|Data32)) + { + if (i.suffix) + { + as_bad ("extraneous opcode suffix given"); + return; + } + if (t->opcode_modifier & Data16) + i.suffix = WORD_OPCODE_SUFFIX; + else + i.suffix = DWORD_OPCODE_SUFFIX; + } + /* If there's no opcode suffix we try to invent one based on register operands. */ if (!i.suffix && i.reg_operands) *************** *** 1117,1123 **** t->base_opcode |= W; /* Now select between word & dword operations via the operand size prefix. */ ! if (i.suffix == WORD_OPCODE_SUFFIX) { if (i.prefixes == MAX_PREFIXES) { --- 1142,1148 ---- t->base_opcode |= W; /* Now select between word & dword operations via the operand size prefix. */ ! if ((i.suffix == WORD_OPCODE_SUFFIX) ^ flag_16bit_code) { if (i.prefixes == MAX_PREFIXES) { *************** *** 1383,1388 **** --- 1408,1427 ---- if (t->extension_opcode != None) i.rm.reg = t->extension_opcode; } + + /* GAS currently doesn't support 16-bit memory addressing modes at all, + so if we're writing 16-bit code and using a memory addressing mode, + always spew out an address size prefix. */ + if ((i.rm.mode != 3) && flag_16bit_code) + { + if (i.prefixes == MAX_PREFIXES) + { + as_bad ("%d prefixes given and address size override gives too many prefixes", + MAX_PREFIXES); + return; + } + i.prefix[i.prefixes++] = ADDR_PREFIX_OPCODE; + } } } } *************** *** 1470,1475 **** --- 1509,1527 ---- { int size = (t->opcode_modifier & JumpByte) ? 1 : 4; unsigned long n = i.disps[0]->X_add_number; + unsigned char *q; + + /* The jcx/jecx instruction might need a data size prefix. + XXX would it be OK just to output all the prefixes? */ + for (q = i.prefix; q < i.prefix + i.prefixes; q++) + { + if (*q == WORD_PREFIX_OPCODE) + { + p = frag_more (1); + insn_size += 1; + md_number_to_chars (p, (valueT) *q, 1); + } + } if (fits_in_unsigned_byte (t->base_opcode)) { Bryan --- Bryan Ford baford@cs.utah.edu University of Utah, CSS `finger baford@schirf.cs.utah.edu' for PGP key and other info.