* Patch: support for 16-bit i386 code.
@ 1994-11-25 7:56 Bryan Ford
0 siblings, 0 replies; only message in thread
From: Bryan Ford @ 1994-11-25 7:56 UTC (permalink / raw)
To: gas2; +Cc: mach4-users
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.
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~1994-11-25 7:56 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1994-11-25 7:56 Patch: support for 16-bit i386 code Bryan Ford
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).