Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 5221 → Rev 5222

/contrib/toolchain/binutils/gas/config/atof-ieee.c
0,0 → 1,813
/* atof_ieee.c - turn a Flonum into an IEEE floating point number
Copyright 1987, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001, 2005,
2007, 2009 Free Software Foundation, Inc.
 
This file is part of GAS, the GNU Assembler.
 
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
 
GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
#include "as.h"
 
/* Flonums returned here. */
extern FLONUM_TYPE generic_floating_point_number;
 
extern const char EXP_CHARS[];
/* Precision in LittleNums. */
/* Don't count the gap in the m68k extended precision format. */
#define MAX_PRECISION 5
#define F_PRECISION 2
#define D_PRECISION 4
#define X_PRECISION 5
#define P_PRECISION 5
 
/* Length in LittleNums of guard bits. */
#define GUARD 2
 
#ifndef TC_LARGEST_EXPONENT_IS_NORMAL
#define TC_LARGEST_EXPONENT_IS_NORMAL(PRECISION) 0
#endif
 
static const unsigned long mask[] =
{
0x00000000,
0x00000001,
0x00000003,
0x00000007,
0x0000000f,
0x0000001f,
0x0000003f,
0x0000007f,
0x000000ff,
0x000001ff,
0x000003ff,
0x000007ff,
0x00000fff,
0x00001fff,
0x00003fff,
0x00007fff,
0x0000ffff,
0x0001ffff,
0x0003ffff,
0x0007ffff,
0x000fffff,
0x001fffff,
0x003fffff,
0x007fffff,
0x00ffffff,
0x01ffffff,
0x03ffffff,
0x07ffffff,
0x0fffffff,
0x1fffffff,
0x3fffffff,
0x7fffffff,
0xffffffff,
};
static int bits_left_in_littlenum;
static int littlenums_left;
static LITTLENUM_TYPE *littlenum_pointer;
 
static int
next_bits (int number_of_bits)
{
int return_value;
 
if (!littlenums_left)
return 0;
 
if (number_of_bits >= bits_left_in_littlenum)
{
return_value = mask[bits_left_in_littlenum] & *littlenum_pointer;
number_of_bits -= bits_left_in_littlenum;
return_value <<= number_of_bits;
 
if (--littlenums_left)
{
bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits;
--littlenum_pointer;
return_value |=
(*littlenum_pointer >> bits_left_in_littlenum)
& mask[number_of_bits];
}
}
else
{
bits_left_in_littlenum -= number_of_bits;
return_value =
mask[number_of_bits] & (*littlenum_pointer >> bits_left_in_littlenum);
}
return return_value;
}
 
/* Num had better be less than LITTLENUM_NUMBER_OF_BITS. */
 
static void
unget_bits (int num)
{
if (!littlenums_left)
{
++littlenum_pointer;
++littlenums_left;
bits_left_in_littlenum = num;
}
else if (bits_left_in_littlenum + num > LITTLENUM_NUMBER_OF_BITS)
{
bits_left_in_littlenum =
num - (LITTLENUM_NUMBER_OF_BITS - bits_left_in_littlenum);
++littlenum_pointer;
++littlenums_left;
}
else
bits_left_in_littlenum += num;
}
 
static void
make_invalid_floating_point_number (LITTLENUM_TYPE *words)
{
as_bad (_("cannot create floating-point number"));
/* Zero the leftmost bit. */
words[0] = (LITTLENUM_TYPE) ((unsigned) -1) >> 1;
words[1] = (LITTLENUM_TYPE) -1;
words[2] = (LITTLENUM_TYPE) -1;
words[3] = (LITTLENUM_TYPE) -1;
words[4] = (LITTLENUM_TYPE) -1;
words[5] = (LITTLENUM_TYPE) -1;
}
/* Warning: This returns 16-bit LITTLENUMs. It is up to the caller to
figure out any alignment problems and to conspire for the
bytes/word to be emitted in the right order. Bigendians beware! */
 
/* Note that atof-ieee always has X and P precisions enabled. it is up
to md_atof to filter them out if the target machine does not support
them. */
 
/* Returns pointer past text consumed. */
 
char *
atof_ieee (char *str, /* Text to convert to binary. */
int what_kind, /* 'd', 'f', 'x', 'p'. */
LITTLENUM_TYPE *words) /* Build the binary here. */
{
/* Extra bits for zeroed low-order bits.
The 1st MAX_PRECISION are zeroed, the last contain flonum bits. */
static LITTLENUM_TYPE bits[MAX_PRECISION + MAX_PRECISION + GUARD];
char *return_value;
/* Number of 16-bit words in the format. */
int precision;
long exponent_bits;
FLONUM_TYPE save_gen_flonum;
 
/* We have to save the generic_floating_point_number because it
contains storage allocation about the array of LITTLENUMs where
the value is actually stored. We will allocate our own array of
littlenums below, but have to restore the global one on exit. */
save_gen_flonum = generic_floating_point_number;
 
return_value = str;
generic_floating_point_number.low = bits + MAX_PRECISION;
generic_floating_point_number.high = NULL;
generic_floating_point_number.leader = NULL;
generic_floating_point_number.exponent = 0;
generic_floating_point_number.sign = '\0';
 
/* Use more LittleNums than seems necessary: the highest flonum may
have 15 leading 0 bits, so could be useless. */
 
memset (bits, '\0', sizeof (LITTLENUM_TYPE) * MAX_PRECISION);
 
switch (what_kind)
{
case 'f':
case 'F':
case 's':
case 'S':
precision = F_PRECISION;
exponent_bits = 8;
break;
 
case 'd':
case 'D':
case 'r':
case 'R':
precision = D_PRECISION;
exponent_bits = 11;
break;
 
case 'x':
case 'X':
case 'e':
case 'E':
precision = X_PRECISION;
exponent_bits = 15;
break;
 
case 'p':
case 'P':
precision = P_PRECISION;
exponent_bits = -1;
break;
 
default:
make_invalid_floating_point_number (words);
return (NULL);
}
 
generic_floating_point_number.high
= generic_floating_point_number.low + precision - 1 + GUARD;
 
if (atof_generic (&return_value, ".", EXP_CHARS,
&generic_floating_point_number))
{
make_invalid_floating_point_number (words);
return NULL;
}
gen_to_words (words, precision, exponent_bits);
 
/* Restore the generic_floating_point_number's storage alloc (and
everything else). */
generic_floating_point_number = save_gen_flonum;
 
return return_value;
}
 
/* Turn generic_floating_point_number into a real float/double/extended. */
 
int
gen_to_words (LITTLENUM_TYPE *words, int precision, long exponent_bits)
{
int return_value = 0;
 
long exponent_1;
long exponent_2;
long exponent_3;
long exponent_4;
int exponent_skippage;
LITTLENUM_TYPE word1;
LITTLENUM_TYPE *lp;
LITTLENUM_TYPE *words_end;
 
words_end = words + precision;
#ifdef TC_M68K
if (precision == X_PRECISION)
/* On the m68k the extended precision format has a gap of 16 bits
between the exponent and the mantissa. */
words_end++;
#endif
 
if (generic_floating_point_number.low > generic_floating_point_number.leader)
{
/* 0.0e0 seen. */
if (generic_floating_point_number.sign == '+')
words[0] = 0x0000;
else
words[0] = 0x8000;
memset (&words[1], '\0',
(words_end - words - 1) * sizeof (LITTLENUM_TYPE));
return return_value;
}
 
/* NaN: Do the right thing. */
if (generic_floating_point_number.sign == 0)
{
if (TC_LARGEST_EXPONENT_IS_NORMAL (precision))
as_warn (_("NaNs are not supported by this target\n"));
if (precision == F_PRECISION)
{
words[0] = 0x7fff;
words[1] = 0xffff;
}
else if (precision == X_PRECISION)
{
#ifdef TC_M68K
words[0] = 0x7fff;
words[1] = 0;
words[2] = 0xffff;
words[3] = 0xffff;
words[4] = 0xffff;
words[5] = 0xffff;
#else /* ! TC_M68K */
#ifdef TC_I386
words[0] = 0xffff;
words[1] = 0xc000;
words[2] = 0;
words[3] = 0;
words[4] = 0;
#else /* ! TC_I386 */
abort ();
#endif /* ! TC_I386 */
#endif /* ! TC_M68K */
}
else
{
words[0] = 0x7fff;
words[1] = 0xffff;
words[2] = 0xffff;
words[3] = 0xffff;
}
return return_value;
}
else if (generic_floating_point_number.sign == 'P')
{
if (TC_LARGEST_EXPONENT_IS_NORMAL (precision))
as_warn (_("Infinities are not supported by this target\n"));
 
/* +INF: Do the right thing. */
if (precision == F_PRECISION)
{
words[0] = 0x7f80;
words[1] = 0;
}
else if (precision == X_PRECISION)
{
#ifdef TC_M68K
words[0] = 0x7fff;
words[1] = 0;
words[2] = 0;
words[3] = 0;
words[4] = 0;
words[5] = 0;
#else /* ! TC_M68K */
#ifdef TC_I386
words[0] = 0x7fff;
words[1] = 0x8000;
words[2] = 0;
words[3] = 0;
words[4] = 0;
#else /* ! TC_I386 */
abort ();
#endif /* ! TC_I386 */
#endif /* ! TC_M68K */
}
else
{
words[0] = 0x7ff0;
words[1] = 0;
words[2] = 0;
words[3] = 0;
}
return return_value;
}
else if (generic_floating_point_number.sign == 'N')
{
if (TC_LARGEST_EXPONENT_IS_NORMAL (precision))
as_warn (_("Infinities are not supported by this target\n"));
 
/* Negative INF. */
if (precision == F_PRECISION)
{
words[0] = 0xff80;
words[1] = 0x0;
}
else if (precision == X_PRECISION)
{
#ifdef TC_M68K
words[0] = 0xffff;
words[1] = 0;
words[2] = 0;
words[3] = 0;
words[4] = 0;
words[5] = 0;
#else /* ! TC_M68K */
#ifdef TC_I386
words[0] = 0xffff;
words[1] = 0x8000;
words[2] = 0;
words[3] = 0;
words[4] = 0;
#else /* ! TC_I386 */
abort ();
#endif /* ! TC_I386 */
#endif /* ! TC_M68K */
}
else
{
words[0] = 0xfff0;
words[1] = 0x0;
words[2] = 0x0;
words[3] = 0x0;
}
return return_value;
}
 
/* The floating point formats we support have:
Bit 15 is sign bit.
Bits 14:n are excess-whatever exponent.
Bits n-1:0 (if any) are most significant bits of fraction.
Bits 15:0 of the next word(s) are the next most significant bits.
 
So we need: number of bits of exponent, number of bits of
mantissa. */
bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS;
littlenum_pointer = generic_floating_point_number.leader;
littlenums_left = (1
+ generic_floating_point_number.leader
- generic_floating_point_number.low);
 
/* Seek (and forget) 1st significant bit. */
for (exponent_skippage = 0; !next_bits (1); ++exponent_skippage);
exponent_1 = (generic_floating_point_number.exponent
+ generic_floating_point_number.leader
+ 1
- generic_floating_point_number.low);
 
/* Radix LITTLENUM_RADIX, point just higher than
generic_floating_point_number.leader. */
exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS;
 
/* Radix 2. */
exponent_3 = exponent_2 - exponent_skippage;
 
/* Forget leading zeros, forget 1st bit. */
exponent_4 = exponent_3 + ((1 << (exponent_bits - 1)) - 2);
 
/* Offset exponent. */
lp = words;
 
/* Word 1. Sign, exponent and perhaps high bits. */
word1 = ((generic_floating_point_number.sign == '+')
? 0
: (1 << (LITTLENUM_NUMBER_OF_BITS - 1)));
 
/* Assume 2's complement integers. */
if (exponent_4 <= 0)
{
int prec_bits;
int num_bits;
 
unget_bits (1);
num_bits = -exponent_4;
prec_bits =
LITTLENUM_NUMBER_OF_BITS * precision - (exponent_bits + 1 + num_bits);
#ifdef TC_I386
if (precision == X_PRECISION && exponent_bits == 15)
{
/* On the i386 a denormalized extended precision float is
shifted down by one, effectively decreasing the exponent
bias by one. */
prec_bits -= 1;
num_bits += 1;
}
#endif
 
if (num_bits >= LITTLENUM_NUMBER_OF_BITS - exponent_bits)
{
/* Bigger than one littlenum. */
num_bits -= (LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits;
*lp++ = word1;
if (num_bits + exponent_bits + 1
> precision * LITTLENUM_NUMBER_OF_BITS)
{
/* Exponent overflow. */
make_invalid_floating_point_number (words);
return return_value;
}
#ifdef TC_M68K
if (precision == X_PRECISION && exponent_bits == 15)
*lp++ = 0;
#endif
while (num_bits >= LITTLENUM_NUMBER_OF_BITS)
{
num_bits -= LITTLENUM_NUMBER_OF_BITS;
*lp++ = 0;
}
if (num_bits)
*lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS - (num_bits));
}
else
{
if (precision == X_PRECISION && exponent_bits == 15)
{
*lp++ = word1;
#ifdef TC_M68K
*lp++ = 0;
#endif
*lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS - num_bits);
}
else
{
word1 |= next_bits ((LITTLENUM_NUMBER_OF_BITS - 1)
- (exponent_bits + num_bits));
*lp++ = word1;
}
}
while (lp < words_end)
*lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS);
 
/* Round the mantissa up, but don't change the number. */
if (next_bits (1))
{
--lp;
if (prec_bits >= LITTLENUM_NUMBER_OF_BITS)
{
int n = 0;
int tmp_bits;
 
n = 0;
tmp_bits = prec_bits;
while (tmp_bits > LITTLENUM_NUMBER_OF_BITS)
{
if (lp[n] != (LITTLENUM_TYPE) - 1)
break;
--n;
tmp_bits -= LITTLENUM_NUMBER_OF_BITS;
}
if (tmp_bits > LITTLENUM_NUMBER_OF_BITS
|| (lp[n] & mask[tmp_bits]) != mask[tmp_bits]
|| (prec_bits != (precision * LITTLENUM_NUMBER_OF_BITS
- exponent_bits - 1)
#ifdef TC_I386
/* An extended precision float with only the integer
bit set would be invalid. That must be converted
to the smallest normalized number. */
&& !(precision == X_PRECISION
&& prec_bits == (precision * LITTLENUM_NUMBER_OF_BITS
- exponent_bits - 2))
#endif
))
{
unsigned long carry;
 
for (carry = 1; carry && (lp >= words); lp--)
{
carry = *lp + carry;
*lp = carry;
carry >>= LITTLENUM_NUMBER_OF_BITS;
}
}
else
{
/* This is an overflow of the denormal numbers. We
need to forget what we have produced, and instead
generate the smallest normalized number. */
lp = words;
word1 = ((generic_floating_point_number.sign == '+')
? 0
: (1 << (LITTLENUM_NUMBER_OF_BITS - 1)));
word1 |= (1
<< ((LITTLENUM_NUMBER_OF_BITS - 1)
- exponent_bits));
*lp++ = word1;
#ifdef TC_I386
/* Set the integer bit in the extended precision format.
This cannot happen on the m68k where the mantissa
just overflows into the integer bit above. */
if (precision == X_PRECISION)
*lp++ = 1 << (LITTLENUM_NUMBER_OF_BITS - 1);
#endif
while (lp < words_end)
*lp++ = 0;
}
}
else
*lp += 1;
}
 
return return_value;
}
else if ((unsigned long) exponent_4 > mask[exponent_bits]
|| (! TC_LARGEST_EXPONENT_IS_NORMAL (precision)
&& (unsigned long) exponent_4 == mask[exponent_bits]))
{
/* Exponent overflow. Lose immediately. */
 
/* We leave return_value alone: admit we read the
number, but return a floating exception
because we can't encode the number. */
make_invalid_floating_point_number (words);
return return_value;
}
else
{
word1 |= (exponent_4 << ((LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits))
| next_bits ((LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits);
}
 
*lp++ = word1;
 
/* X_PRECISION is special: on the 68k, it has 16 bits of zero in the
middle. Either way, it is then followed by a 1 bit. */
if (exponent_bits == 15 && precision == X_PRECISION)
{
#ifdef TC_M68K
*lp++ = 0;
#endif
*lp++ = (1 << (LITTLENUM_NUMBER_OF_BITS - 1)
| next_bits (LITTLENUM_NUMBER_OF_BITS - 1));
}
 
/* The rest of the words are just mantissa bits. */
while (lp < words_end)
*lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS);
 
if (next_bits (1))
{
unsigned long carry;
/* Since the NEXT bit is a 1, round UP the mantissa.
The cunning design of these hidden-1 floats permits
us to let the mantissa overflow into the exponent, and
it 'does the right thing'. However, we lose if the
highest-order bit of the lowest-order word flips.
Is that clear? */
 
/* #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2)
Please allow at least 1 more bit in carry than is in a LITTLENUM.
We need that extra bit to hold a carry during a LITTLENUM carry
propagation. Another extra bit (kept 0) will assure us that we
don't get a sticky sign bit after shifting right, and that
permits us to propagate the carry without any masking of bits.
#endif */
for (carry = 1, lp--; carry; lp--)
{
carry = *lp + carry;
*lp = carry;
carry >>= LITTLENUM_NUMBER_OF_BITS;
if (lp == words)
break;
}
if (precision == X_PRECISION && exponent_bits == 15)
{
/* Extended precision numbers have an explicit integer bit
that we may have to restore. */
if (lp == words)
{
#ifdef TC_M68K
/* On the m68k there is a gap of 16 bits. We must
explicitly propagate the carry into the exponent. */
words[0] += words[1];
words[1] = 0;
lp++;
#endif
/* Put back the integer bit. */
lp[1] |= 1 << (LITTLENUM_NUMBER_OF_BITS - 1);
}
}
if ((word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1)))
{
/* We leave return_value alone: admit we read the number,
but return a floating exception because we can't encode
the number. */
*words &= ~(1 << (LITTLENUM_NUMBER_OF_BITS - 1));
}
}
return return_value;
}
 
#ifdef TEST
char *
print_gen (gen)
FLONUM_TYPE *gen;
{
FLONUM_TYPE f;
LITTLENUM_TYPE arr[10];
double dv;
float fv;
static char sbuf[40];
 
if (gen)
{
f = generic_floating_point_number;
generic_floating_point_number = *gen;
}
gen_to_words (&arr[0], 4, 11);
memcpy (&dv, &arr[0], sizeof (double));
sprintf (sbuf, "%x %x %x %x %.14G ", arr[0], arr[1], arr[2], arr[3], dv);
gen_to_words (&arr[0], 2, 8);
memcpy (&fv, &arr[0], sizeof (float));
sprintf (sbuf + strlen (sbuf), "%x %x %.12g\n", arr[0], arr[1], fv);
 
if (gen)
generic_floating_point_number = f;
 
return (sbuf);
}
#endif
 
extern const char FLT_CHARS[];
#define MAX_LITTLENUMS 6
 
/* This is a utility function called from various tc-*.c files. It
is here in order to reduce code duplication.
Turn a string at input_line_pointer into a floating point constant
of type TYPE (a character found in the FLT_CHARS macro), and store
it as LITTLENUMS in the bytes buffer LITP. The number of chars
emitted is stored in *SIZEP. BIG_WORDIAN is TRUE if the littlenums
should be emitted most significant littlenum first.
 
An error message is returned, or a NULL pointer if everything went OK. */
 
char *
ieee_md_atof (int type,
char *litP,
int *sizeP,
bfd_boolean big_wordian)
{
LITTLENUM_TYPE words[MAX_LITTLENUMS];
LITTLENUM_TYPE *wordP;
char *t;
int prec = 0;
 
if (strchr (FLT_CHARS, type) != NULL)
{
switch (type)
{
case 'f':
case 'F':
case 's':
case 'S':
prec = F_PRECISION;
break;
 
case 'd':
case 'D':
case 'r':
case 'R':
prec = D_PRECISION;
break;
 
case 't':
case 'T':
prec = X_PRECISION;
type = 'x'; /* This is what atof_ieee() understands. */
break;
 
case 'x':
case 'X':
case 'p':
case 'P':
#ifdef TC_M68K
/* Note: on the m68k there is a gap of 16 bits (one littlenum)
between the exponent and mantissa. Hence the precision is
6 and not 5. */
prec = P_PRECISION + 1;
#else
prec = P_PRECISION;
#endif
break;
 
default:
break;
}
}
/* The 'f' and 'd' types are always recognised, even if the target has
not put them into the FLT_CHARS macro. This is because the 'f' type
can come from the .dc.s, .dcb.s, .float or .single pseudo-ops and the
'd' type from the .dc.d, .dbc.d or .double pseudo-ops.
 
The 'x' type is not implicitly recongised however, even though it can
be generated by the .dc.x and .dbc.x pseudo-ops because not all targets
can support floating point values that big. ie the target has to
explicitly allow them by putting them into FLT_CHARS. */
else if (type == 'f')
prec = F_PRECISION;
else if (type == 'd')
prec = D_PRECISION;
 
if (prec == 0)
{
*sizeP = 0;
return _("Unrecognized or unsupported floating point constant");
}
 
gas_assert (prec <= MAX_LITTLENUMS);
 
t = atof_ieee (input_line_pointer, type, words);
if (t)
input_line_pointer = t;
 
*sizeP = prec * sizeof (LITTLENUM_TYPE);
 
if (big_wordian)
{
for (wordP = words; prec --;)
{
md_number_to_chars (litP, (valueT) (* wordP ++), sizeof (LITTLENUM_TYPE));
litP += sizeof (LITTLENUM_TYPE);
}
}
else
{
for (wordP = words + prec; prec --;)
{
md_number_to_chars (litP, (valueT) (* -- wordP), sizeof (LITTLENUM_TYPE));
litP += sizeof (LITTLENUM_TYPE);
}
}
 
return NULL;
}
/contrib/toolchain/binutils/gas/config/obj-coff-seh.c
0,0 → 1,1018
/* seh pdata/xdata coff object file format
Copyright 2009, 2010
Free Software Foundation, Inc.
 
This file is part of GAS.
 
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
 
GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
#include "obj-coff-seh.h"
 
 
/* Private segment collection list. */
struct seh_seg_list {
segT seg;
int subseg;
char *seg_name;
};
 
/* Local data. */
static seh_context *seh_ctx_cur = NULL;
 
static struct hash_control *seh_hash;
 
static struct seh_seg_list *x_segcur = NULL;
static struct seh_seg_list *p_segcur = NULL;
 
static void write_function_xdata (seh_context *);
static void write_function_pdata (seh_context *);
 
/* Build based on segment the derived .pdata/.xdata
segment name containing origin segment's postfix name part. */
static char *
get_pxdata_name (segT seg, const char *base_name)
{
const char *name,*dollar, *dot;
char *sname;
 
name = bfd_get_section_name (stdoutput, seg);
 
dollar = strchr (name, '$');
dot = strchr (name + 1, '.');
 
if (!dollar && !dot)
name = "";
else if (!dollar)
name = dot;
else if (!dot)
name = dollar;
else if (dot < dollar)
name = dot;
else
name = dollar;
 
sname = concat (base_name, name, NULL);
 
return sname;
}
 
/* Allocate a seh_seg_list structure. */
static struct seh_seg_list *
alloc_pxdata_item (segT seg, int subseg, char *name)
{
struct seh_seg_list *r;
 
r = (struct seh_seg_list *)
xmalloc (sizeof (struct seh_seg_list) + strlen (name));
r->seg = seg;
r->subseg = subseg;
r->seg_name = name;
return r;
}
 
/* Generate pdata/xdata segment with same linkonce properties
of based segment. */
static segT
make_pxdata_seg (segT cseg, char *name)
{
segT save_seg = now_seg;
int save_subseg = now_subseg;
segT r;
flagword flags;
 
r = subseg_new (name, 0);
/* Check if code segment is marked as linked once. */
flags = bfd_get_section_flags (stdoutput, cseg)
& (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD
| SEC_LINK_DUPLICATES_ONE_ONLY | SEC_LINK_DUPLICATES_SAME_SIZE
| SEC_LINK_DUPLICATES_SAME_CONTENTS);
 
/* Add standard section flags. */
flags |= SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA;
 
/* Apply possibly linked once flags to new generated segment, too. */
if (!bfd_set_section_flags (stdoutput, r, flags))
as_bad (_("bfd_set_section_flags: %s"),
bfd_errmsg (bfd_get_error ()));
 
/* Restore to previous segment. */
subseg_set (save_seg, save_subseg);
return r;
}
 
static void
seh_hash_insert (const char *name, struct seh_seg_list *item)
{
const char *error_string;
 
if ((error_string = hash_jam (seh_hash, name, (char *) item)))
as_fatal (_("Inserting \"%s\" into structure table failed: %s"),
name, error_string);
}
 
static struct seh_seg_list *
seh_hash_find (char *name)
{
return (struct seh_seg_list *) hash_find (seh_hash, name);
}
 
static struct seh_seg_list *
seh_hash_find_or_make (segT cseg, const char *base_name)
{
struct seh_seg_list *item;
char *name;
 
/* Initialize seh_hash once. */
if (!seh_hash)
seh_hash = hash_new ();
 
name = get_pxdata_name (cseg, base_name);
 
item = seh_hash_find (name);
if (!item)
{
item = alloc_pxdata_item (make_pxdata_seg (cseg, name), 0, name);
 
seh_hash_insert (item->seg_name, item);
}
else
free (name);
 
return item;
}
 
/* Check if current segment has same name. */
static int
seh_validate_seg (const char *directive)
{
const char *cseg_name, *nseg_name;
if (seh_ctx_cur->code_seg == now_seg)
return 1;
cseg_name = bfd_get_section_name (stdoutput, seh_ctx_cur->code_seg);
nseg_name = bfd_get_section_name (stdoutput, now_seg);
as_bad (_("%s used in segment '%s' instead of expected '%s'"),
directive, nseg_name, cseg_name);
ignore_rest_of_line ();
return 0;
}
 
static void
switch_xdata (int subseg, segT code_seg)
{
x_segcur = seh_hash_find_or_make (code_seg, ".xdata");
 
subseg_set (x_segcur->seg, subseg);
}
 
static void
switch_pdata (segT code_seg)
{
p_segcur = seh_hash_find_or_make (code_seg, ".pdata");
 
subseg_set (p_segcur->seg, p_segcur->subseg);
}
/* Parsing routines. */
 
/* Return the style of SEH unwind info to generate. */
 
static seh_kind
seh_get_target_kind (void)
{
if (!stdoutput)
return seh_kind_unknown;
switch (bfd_get_arch (stdoutput))
{
case bfd_arch_arm:
case bfd_arch_powerpc:
case bfd_arch_sh:
return seh_kind_arm;
case bfd_arch_i386:
switch (bfd_get_mach (stdoutput))
{
case bfd_mach_x86_64:
case bfd_mach_x86_64_intel_syntax:
return seh_kind_x64;
default:
break;
}
/* FALL THROUGH. */
case bfd_arch_mips:
return seh_kind_mips;
case bfd_arch_ia64:
/* Should return seh_kind_x64. But not implemented yet. */
return seh_kind_unknown;
default:
break;
}
return seh_kind_unknown;
}
 
/* Verify that we're in the context of a seh_proc. */
 
static int
verify_context (const char *directive)
{
if (seh_ctx_cur == NULL)
{
as_bad (_("%s used outside of .seh_proc block"), directive);
ignore_rest_of_line ();
return 0;
}
return 1;
}
 
/* Similar, except we also verify the appropriate target. */
 
static int
verify_context_and_target (const char *directive, seh_kind target)
{
if (seh_get_target_kind () != target)
{
as_warn (_("%s ignored for this target"), directive);
ignore_rest_of_line ();
return 0;
}
return verify_context (directive);
}
 
/* Skip whitespace and a comma. Error if the comma is not seen. */
 
static int
skip_whitespace_and_comma (int required)
{
SKIP_WHITESPACE ();
if (*input_line_pointer == ',')
{
input_line_pointer++;
SKIP_WHITESPACE ();
return 1;
}
else if (required)
{
as_bad (_("missing separator"));
ignore_rest_of_line ();
}
else
demand_empty_rest_of_line ();
return 0;
}
 
/* Mark current context to use 32-bit instruction (arm). */
 
static void
obj_coff_seh_32 (int what)
{
if (!verify_context_and_target ((what ? ".seh_32" : ".seh_no32"),
seh_kind_arm))
return;
 
seh_ctx_cur->use_instruction_32 = (what ? 1 : 0);
demand_empty_rest_of_line ();
}
 
/* Set for current context the handler and optional data (arm). */
 
static void
obj_coff_seh_eh (int what ATTRIBUTE_UNUSED)
{
if (!verify_context_and_target (".seh_eh", seh_kind_arm))
return;
 
/* Write block to .text if exception handler is set. */
seh_ctx_cur->handler_written = 1;
emit_expr (&seh_ctx_cur->handler, 4);
emit_expr (&seh_ctx_cur->handler_data, 4);
 
demand_empty_rest_of_line ();
}
 
/* Set for current context the default handler (x64). */
 
static void
obj_coff_seh_handler (int what ATTRIBUTE_UNUSED)
{
char *symbol_name;
char name_end;
 
if (!verify_context (".seh_handler"))
return;
 
if (*input_line_pointer == 0 || *input_line_pointer == '\n')
{
as_bad (_(".seh_handler requires a handler"));
demand_empty_rest_of_line ();
return;
}
 
SKIP_WHITESPACE ();
 
if (*input_line_pointer == '@')
{
symbol_name = input_line_pointer;
name_end = get_symbol_end ();
 
seh_ctx_cur->handler.X_op = O_constant;
seh_ctx_cur->handler.X_add_number = 0;
 
if (strcasecmp (symbol_name, "@0") == 0
|| strcasecmp (symbol_name, "@null") == 0)
;
else if (strcasecmp (symbol_name, "@1") == 0)
seh_ctx_cur->handler.X_add_number = 1;
else
as_bad (_("unknown constant value '%s' for handler"), symbol_name);
 
*input_line_pointer = name_end;
}
else
expression (&seh_ctx_cur->handler);
 
seh_ctx_cur->handler_data.X_op = O_constant;
seh_ctx_cur->handler_data.X_add_number = 0;
seh_ctx_cur->handler_flags = 0;
 
if (!skip_whitespace_and_comma (0))
return;
 
if (seh_get_target_kind () == seh_kind_x64)
{
do
{
symbol_name = input_line_pointer;
name_end = get_symbol_end ();
 
if (strcasecmp (symbol_name, "@unwind") == 0)
seh_ctx_cur->handler_flags |= UNW_FLAG_UHANDLER;
else if (strcasecmp (symbol_name, "@except") == 0)
seh_ctx_cur->handler_flags |= UNW_FLAG_EHANDLER;
else
as_bad (_(".seh_handler constant '%s' unknown"), symbol_name);
 
*input_line_pointer = name_end;
}
while (skip_whitespace_and_comma (0));
}
else
{
expression (&seh_ctx_cur->handler_data);
demand_empty_rest_of_line ();
 
if (seh_ctx_cur->handler_written)
as_warn (_(".seh_handler after .seh_eh is ignored"));
}
}
 
/* Switch to subsection for handler data for exception region (x64). */
 
static void
obj_coff_seh_handlerdata (int what ATTRIBUTE_UNUSED)
{
if (!verify_context_and_target (".seh_handlerdata", seh_kind_x64))
return;
demand_empty_rest_of_line ();
 
switch_xdata (seh_ctx_cur->subsection + 1, seh_ctx_cur->code_seg);
}
 
/* Mark end of current context. */
 
static void
do_seh_endproc (void)
{
seh_ctx_cur->end_addr = symbol_temp_new_now ();
 
write_function_xdata (seh_ctx_cur);
write_function_pdata (seh_ctx_cur);
seh_ctx_cur = NULL;
}
 
static void
obj_coff_seh_endproc (int what ATTRIBUTE_UNUSED)
{
demand_empty_rest_of_line ();
if (seh_ctx_cur == NULL)
{
as_bad (_(".seh_endproc used without .seh_proc"));
return;
}
seh_validate_seg (".seh_endproc");
do_seh_endproc ();
}
 
/* Mark begin of new context. */
 
static void
obj_coff_seh_proc (int what ATTRIBUTE_UNUSED)
{
char *symbol_name;
char name_end;
 
if (seh_ctx_cur != NULL)
{
as_bad (_("previous SEH entry not closed (missing .seh_endproc)"));
do_seh_endproc ();
}
 
if (*input_line_pointer == 0 || *input_line_pointer == '\n')
{
as_bad (_(".seh_proc requires function label name"));
demand_empty_rest_of_line ();
return;
}
 
seh_ctx_cur = XCNEW (seh_context);
 
seh_ctx_cur->code_seg = now_seg;
 
if (seh_get_target_kind () == seh_kind_x64)
{
x_segcur = seh_hash_find_or_make (seh_ctx_cur->code_seg, ".xdata");
seh_ctx_cur->subsection = x_segcur->subseg;
x_segcur->subseg += 2;
}
 
SKIP_WHITESPACE ();
 
symbol_name = input_line_pointer;
name_end = get_symbol_end ();
seh_ctx_cur->func_name = xstrdup (symbol_name);
*input_line_pointer = name_end;
 
demand_empty_rest_of_line ();
 
seh_ctx_cur->start_addr = symbol_temp_new_now ();
}
 
/* Mark end of prologue for current context. */
 
static void
obj_coff_seh_endprologue (int what ATTRIBUTE_UNUSED)
{
if (!verify_context (".seh_endprologue")
|| !seh_validate_seg (".seh_endprologue"))
return;
demand_empty_rest_of_line ();
 
if (seh_ctx_cur->endprologue_addr != NULL)
as_warn (_("duplicate .seh_endprologue in .seh_proc block"));
else
seh_ctx_cur->endprologue_addr = symbol_temp_new_now ();
}
 
/* End-of-file hook. */
 
void
obj_coff_seh_do_final (void)
{
if (seh_ctx_cur != NULL)
{
as_bad (_("open SEH entry at end of file (missing .cfi_endproc)"));
do_seh_endproc ();
}
}
 
/* Enter a prologue element into current context (x64). */
 
static void
seh_x64_make_prologue_element (int code, int info, offsetT off)
{
seh_prologue_element *n;
 
if (seh_ctx_cur == NULL)
return;
if (seh_ctx_cur->elems_count == seh_ctx_cur->elems_max)
{
seh_ctx_cur->elems_max += 8;
seh_ctx_cur->elems = XRESIZEVEC (seh_prologue_element,
seh_ctx_cur->elems,
seh_ctx_cur->elems_max);
}
 
n = &seh_ctx_cur->elems[seh_ctx_cur->elems_count++];
n->code = code;
n->info = info;
n->off = off;
n->pc_addr = symbol_temp_new_now ();
}
 
/* Helper to read a register name from input stream (x64). */
 
static int
seh_x64_read_reg (const char *directive, int kind)
{
static const char * const int_regs[16] =
{ "rax", "rcx", "rdx", "rbx", "rsp", "rbp","rsi","rdi",
"r8","r9","r10","r11","r12","r13","r14","r15" };
static const char * const xmm_regs[16] =
{ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
"xmm8", "xmm9", "xmm10","xmm11","xmm12","xmm13","xmm14","xmm15" };
 
const char * const *regs = NULL;
char name_end;
char *symbol_name = NULL;
int i;
 
switch (kind)
{
case 0:
case 1:
regs = int_regs;
break;
case 2:
regs = xmm_regs;
break;
default:
abort ();
}
 
SKIP_WHITESPACE ();
if (*input_line_pointer == '%')
++input_line_pointer;
symbol_name = input_line_pointer;
name_end = get_symbol_end ();
 
for (i = 0; i < 16; i++)
if (! strcasecmp (regs[i], symbol_name))
break;
 
*input_line_pointer = name_end;
 
/* Error if register not found, or EAX used as a frame pointer. */
if (i == 16 || (kind == 0 && i == 0))
{
as_bad (_("invalid register for %s"), directive);
return -1;
}
 
return i;
}
 
/* Add a register push-unwind token to the current context. */
 
static void
obj_coff_seh_pushreg (int what ATTRIBUTE_UNUSED)
{
int reg;
 
if (!verify_context_and_target (".seh_pushreg", seh_kind_x64)
|| !seh_validate_seg (".seh_pushreg"))
return;
 
reg = seh_x64_read_reg (".seh_pushreg", 1);
demand_empty_rest_of_line ();
 
if (reg < 0)
return;
 
seh_x64_make_prologue_element (UWOP_PUSH_NONVOL, reg, 0);
}
 
/* Add a register frame-unwind token to the current context. */
 
static void
obj_coff_seh_pushframe (int what ATTRIBUTE_UNUSED)
{
if (!verify_context_and_target (".seh_pushframe", seh_kind_x64)
|| !seh_validate_seg (".seh_pushframe"))
return;
demand_empty_rest_of_line ();
 
seh_x64_make_prologue_element (UWOP_PUSH_MACHFRAME, 0, 0);
}
 
/* Add a register save-unwind token to current context. */
 
static void
obj_coff_seh_save (int what)
{
const char *directive = (what == 1 ? ".seh_savereg" : ".seh_savexmm");
int code, reg, scale;
offsetT off;
 
if (!verify_context_and_target (directive, seh_kind_x64)
|| !seh_validate_seg (directive))
return;
 
reg = seh_x64_read_reg (directive, what);
 
if (!skip_whitespace_and_comma (1))
return;
 
off = get_absolute_expression ();
demand_empty_rest_of_line ();
 
if (reg < 0)
return;
if (off < 0)
{
as_bad (_("%s offset is negative"), directive);
return;
}
 
scale = (what == 1 ? 8 : 16);
 
if ((off & (scale - 1)) == 0 && off <= (offsetT) (0xffff * scale))
{
code = (what == 1 ? UWOP_SAVE_NONVOL : UWOP_SAVE_XMM128);
off /= scale;
}
else if (off < (offsetT) 0xffffffff)
code = (what == 1 ? UWOP_SAVE_NONVOL_FAR : UWOP_SAVE_XMM128_FAR);
else
{
as_bad (_("%s offset out of range"), directive);
return;
}
 
seh_x64_make_prologue_element (code, reg, off);
}
 
/* Add a stack-allocation token to current context. */
 
static void
obj_coff_seh_stackalloc (int what ATTRIBUTE_UNUSED)
{
offsetT off;
int code, info;
 
if (!verify_context_and_target (".seh_stackalloc", seh_kind_x64)
|| !seh_validate_seg (".seh_stackalloc"))
return;
 
off = get_absolute_expression ();
demand_empty_rest_of_line ();
 
if (off == 0)
return;
if (off < 0)
{
as_bad (_(".seh_stackalloc offset is negative"));
return;
}
 
if ((off & 7) == 0 && off <= 128)
code = UWOP_ALLOC_SMALL, info = (off - 8) >> 3, off = 0;
else if ((off & 7) == 0 && off <= (offsetT) (0xffff * 8))
code = UWOP_ALLOC_LARGE, info = 0, off >>= 3;
else if (off <= (offsetT) 0xffffffff)
code = UWOP_ALLOC_LARGE, info = 1;
else
{
as_bad (_(".seh_stackalloc offset out of range"));
return;
}
 
seh_x64_make_prologue_element (code, info, off);
}
 
/* Add a frame-pointer token to current context. */
 
static void
obj_coff_seh_setframe (int what ATTRIBUTE_UNUSED)
{
offsetT off;
int reg;
 
if (!verify_context_and_target (".seh_setframe", seh_kind_x64)
|| !seh_validate_seg (".seh_setframe"))
return;
 
reg = seh_x64_read_reg (".seh_setframe", 0);
 
if (!skip_whitespace_and_comma (1))
return;
 
off = get_absolute_expression ();
demand_empty_rest_of_line ();
 
if (reg < 0)
return;
if (off < 0)
as_bad (_(".seh_setframe offset is negative"));
else if (off > 240)
as_bad (_(".seh_setframe offset out of range"));
else if (off & 15)
as_bad (_(".seh_setframe offset not a multiple of 16"));
else if (seh_ctx_cur->framereg != 0)
as_bad (_("duplicate .seh_setframe in current .seh_proc"));
else
{
seh_ctx_cur->framereg = reg;
seh_ctx_cur->frameoff = off;
seh_x64_make_prologue_element (UWOP_SET_FPREG, 0, 0);
}
}
/* Data writing routines. */
 
/* Output raw integers in 1, 2, or 4 bytes. */
 
static inline void
out_one (int byte)
{
FRAG_APPEND_1_CHAR (byte);
}
 
static inline void
out_two (int data)
{
md_number_to_chars (frag_more (2), data, 2);
}
 
static inline void
out_four (int data)
{
md_number_to_chars (frag_more (4), data, 4);
}
 
/* Write out prologue data for x64. */
 
static void
seh_x64_write_prologue_data (const seh_context *c)
{
int i;
 
/* We have to store in reverse order. */
for (i = c->elems_count - 1; i >= 0; --i)
{
const seh_prologue_element *e = c->elems + i;
expressionS exp;
 
/* First comes byte offset in code. */
exp.X_op = O_subtract;
exp.X_add_symbol = e->pc_addr;
exp.X_op_symbol = c->start_addr;
exp.X_add_number = 0;
emit_expr (&exp, 1);
 
/* Second comes code+info packed into a byte. */
out_one ((e->info << 4) | e->code);
 
switch (e->code)
{
case UWOP_PUSH_NONVOL:
case UWOP_ALLOC_SMALL:
case UWOP_SET_FPREG:
case UWOP_PUSH_MACHFRAME:
/* These have no extra data. */
break;
 
case UWOP_ALLOC_LARGE:
if (e->info)
{
case UWOP_SAVE_NONVOL_FAR:
case UWOP_SAVE_XMM128_FAR:
/* An unscaled 4 byte offset. */
out_four (e->off);
break;
}
/* FALLTHRU */
 
case UWOP_SAVE_NONVOL:
case UWOP_SAVE_XMM128:
/* A scaled 2 byte offset. */
out_two (e->off);
break;
 
default:
abort ();
}
}
}
 
static int
seh_x64_size_prologue_data (const seh_context *c)
{
int i, ret = 0;
 
for (i = c->elems_count - 1; i >= 0; --i)
switch (c->elems[i].code)
{
case UWOP_PUSH_NONVOL:
case UWOP_ALLOC_SMALL:
case UWOP_SET_FPREG:
case UWOP_PUSH_MACHFRAME:
ret += 1;
break;
 
case UWOP_SAVE_NONVOL:
case UWOP_SAVE_XMM128:
ret += 2;
break;
 
case UWOP_SAVE_NONVOL_FAR:
case UWOP_SAVE_XMM128_FAR:
ret += 3;
break;
 
case UWOP_ALLOC_LARGE:
ret += (c->elems[i].info ? 3 : 2);
break;
 
default:
abort ();
}
 
return ret;
}
 
/* Write out the xdata information for one function (x64). */
 
static void
seh_x64_write_function_xdata (seh_context *c)
{
int flags, count_unwind_codes;
expressionS exp;
 
/* Set 4-byte alignment. */
frag_align (2, 0, 0);
 
c->xdata_addr = symbol_temp_new_now ();
flags = c->handler_flags;
count_unwind_codes = seh_x64_size_prologue_data (c);
 
/* ubyte:3 version, ubyte:5 flags. */
out_one ((flags << 3) | 1);
 
/* Size of prologue. */
if (c->endprologue_addr)
{
exp.X_op = O_subtract;
exp.X_add_symbol = c->endprologue_addr;
exp.X_op_symbol = c->start_addr;
exp.X_add_number = 0;
emit_expr (&exp, 1);
}
else
out_one (0);
 
/* Number of slots (i.e. shorts) in the unwind codes array. */
if (count_unwind_codes > 255)
as_fatal (_("too much unwind data in this .seh_proc"));
out_one (count_unwind_codes);
 
/* ubyte:4 frame-reg, ubyte:4 frame-reg-offset. */
/* Note that frameoff is already a multiple of 16, and therefore
the offset is already both scaled and shifted into place. */
out_one (c->frameoff | c->framereg);
 
seh_x64_write_prologue_data (c);
 
/* We need to align prologue data. */
if (count_unwind_codes & 1)
out_two (0);
 
if (flags & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER))
{
/* Force the use of segment-relative relocations instead of absolute
valued expressions. Don't adjust for constants (e.g. NULL). */
if (c->handler.X_op == O_symbol)
c->handler.X_op = O_symbol_rva;
emit_expr (&c->handler, 4);
}
 
/* Handler data will be tacked in here by subsections. */
}
 
/* Write out xdata for one function. */
 
static void
write_function_xdata (seh_context *c)
{
segT save_seg = now_seg;
int save_subseg = now_subseg;
 
/* MIPS, SH, ARM don't have xdata. */
if (seh_get_target_kind () != seh_kind_x64)
return;
 
switch_xdata (c->subsection, c->code_seg);
 
seh_x64_write_function_xdata (c);
 
subseg_set (save_seg, save_subseg);
}
 
/* Write pdata section data for one function (arm). */
 
static void
seh_arm_write_function_pdata (seh_context *c)
{
expressionS exp;
unsigned int prol_len = 0, func_len = 0;
unsigned int val;
 
/* Start address of the function. */
exp.X_op = O_symbol;
exp.X_add_symbol = c->start_addr;
exp.X_add_number = 0;
emit_expr (&exp, 4);
 
exp.X_op = O_subtract;
exp.X_add_symbol = c->end_addr;
exp.X_op_symbol = c->start_addr;
exp.X_add_number = 0;
if (resolve_expression (&exp) && exp.X_op == O_constant)
func_len = exp.X_add_number;
else
as_bad (_(".seh_endproc in a different section from .seh_proc"));
 
if (c->endprologue_addr)
{
exp.X_op = O_subtract;
exp.X_add_symbol = c->endprologue_addr;
exp.X_op_symbol = c->start_addr;
exp.X_add_number = 0;
 
if (resolve_expression (&exp) && exp.X_op == O_constant)
prol_len = exp.X_add_number;
else
as_bad (_(".seh_endprologue in a different section from .seh_proc"));
}
 
/* Both function and prologue are in units of instructions. */
func_len >>= (c->use_instruction_32 ? 2 : 1);
prol_len >>= (c->use_instruction_32 ? 2 : 1);
 
/* Assemble the second word of the pdata. */
val = prol_len & 0xff;
val |= (func_len & 0x3fffff) << 8;
if (c->use_instruction_32)
val |= 0x40000000U;
if (c->handler_written)
val |= 0x80000000U;
out_four (val);
}
 
/* Write out pdata for one function. */
 
static void
write_function_pdata (seh_context *c)
{
expressionS exp;
segT save_seg = now_seg;
int save_subseg = now_subseg;
memset (&exp, 0, sizeof (expressionS));
switch_pdata (c->code_seg);
 
switch (seh_get_target_kind ())
{
case seh_kind_x64:
exp.X_op = O_symbol_rva;
exp.X_add_number = 0;
 
exp.X_add_symbol = c->start_addr;
emit_expr (&exp, 4);
exp.X_op = O_symbol_rva;
exp.X_add_number = 0;
exp.X_add_symbol = c->end_addr;
emit_expr (&exp, 4);
exp.X_op = O_symbol_rva;
exp.X_add_number = 0;
exp.X_add_symbol = c->xdata_addr;
emit_expr (&exp, 4);
break;
 
case seh_kind_mips:
exp.X_op = O_symbol;
exp.X_add_number = 0;
 
exp.X_add_symbol = c->start_addr;
emit_expr (&exp, 4);
exp.X_add_symbol = c->end_addr;
emit_expr (&exp, 4);
 
emit_expr (&c->handler, 4);
emit_expr (&c->handler_data, 4);
 
exp.X_add_symbol = (c->endprologue_addr
? c->endprologue_addr
: c->start_addr);
emit_expr (&exp, 4);
break;
 
case seh_kind_arm:
seh_arm_write_function_pdata (c);
break;
 
default:
abort ();
}
 
subseg_set (save_seg, save_subseg);
}
/contrib/toolchain/binutils/gas/config/obj-coff-seh.h
0,0 → 1,205
/* seh pdata/xdata coff object file format
Copyright 2009, 2010, 2012
Free Software Foundation, Inc.
 
This file is part of GAS.
 
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
 
GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
/* Short overview:
There are at the moment three different function entry formats preset.
The first is the MIPS one. The second version
is for ARM, PPC, SH3, and SH4 mainly for Windows CE.
The third is the IA64 and x64 version. Note, the IA64 isn't implemented yet,
but to find information about it, please see specification about IA64 on
http://download.intel.com/design/Itanium/Downloads/245358.pdf file.
 
The first version has just entries in the pdata section: BeginAddress,
EndAddress, ExceptionHandler, HandlerData, and PrologueEndAddress. Each
value is a pointer to the corresponding data and has size of 4 bytes.
 
The second variant has the following entries in the pdata section.
BeginAddress, PrologueLength (8 bits), EndAddress (22 bits),
Use-32-bit-instruction (1 bit), and Exception-Handler-Exists (1 bit).
If the FunctionLength is zero, or the Exception-Handler-Exists bit
is true, a PDATA_EH block is placed directly before function entry.
 
The third version has a function entry block of BeginAddress (RVA),
EndAddress (RVA), and UnwindData (RVA). The description of the
prologue, excepetion-handler, and additional SEH data is stored
within the UNWIND_DATA field in the xdata section.
 
The pseudos:
.seh_proc <fct_name>
.seh_endprologue
.seh_handler <handler>[,@unwind][,@except] (x64)
.seh_handler <handler>[,<handler_data>] (others)
.seh_handlerdata
.seh_eh
.seh_32/.seh_no32
.seh_endproc
.seh_setframe <reg>,<offset>
.seh_stackalloc
.seh_pushreg
.seh_savereg
.seh_savexmm
.seh_pushframe
*/
 
/* architecture specific pdata/xdata handling. */
#define SEH_CMDS \
{"seh_proc", obj_coff_seh_proc, 0}, \
{"seh_endproc", obj_coff_seh_endproc, 0}, \
{"seh_pushreg", obj_coff_seh_pushreg, 0}, \
{"seh_savereg", obj_coff_seh_save, 1}, \
{"seh_savexmm", obj_coff_seh_save, 2}, \
{"seh_pushframe", obj_coff_seh_pushframe, 0}, \
{"seh_endprologue", obj_coff_seh_endprologue, 0}, \
{"seh_setframe", obj_coff_seh_setframe, 0}, \
{"seh_stackalloc", obj_coff_seh_stackalloc, 0}, \
{"seh_eh", obj_coff_seh_eh, 0}, \
{"seh_32", obj_coff_seh_32, 1}, \
{"seh_no32", obj_coff_seh_32, 0}, \
{"seh_handler", obj_coff_seh_handler, 0}, \
{"seh_handlerdata", obj_coff_seh_handlerdata, 0},
 
/* Type definitions. */
 
typedef struct seh_prologue_element
{
int code;
int info;
offsetT off;
symbolS *pc_addr;
} seh_prologue_element;
 
typedef struct seh_context
{
struct seh_context *next;
 
/* Initial code-segment. */
segT code_seg;
/* Function name. */
char *func_name;
/* BeginAddress. */
symbolS *start_addr;
/* EndAddress. */
symbolS *end_addr;
/* Unwind data. */
symbolS *xdata_addr;
/* PrologueEnd. */
symbolS *endprologue_addr;
/* ExceptionHandler. */
expressionS handler;
/* ExceptionHandlerData. (arm, mips) */
expressionS handler_data;
 
/* ARM .seh_eh directive seen. */
int handler_written;
 
/* WinCE specific data. */
int use_instruction_32;
/* Was record already processed. */
int done;
 
/* x64 flags for the xdata header. */
int handler_flags;
int subsection;
 
/* x64 framereg and frame offset information. */
int framereg;
int frameoff;
 
/* Information about x64 specific unwind data fields. */
int elems_count;
int elems_max;
seh_prologue_element *elems;
} seh_context;
 
typedef enum seh_kind {
seh_kind_unknown = 0,
seh_kind_mips = 1, /* Used for MIPS and x86 pdata generation. */
seh_kind_arm = 2, /* Used for ARM, PPC, SH3, and SH4 pdata (PDATA_EH) generation. */
seh_kind_x64 = 3 /* Used for IA64 and x64 pdata/xdata generation. */
} seh_kind;
 
/* Forward declarations. */
static void obj_coff_seh_stackalloc (int);
static void obj_coff_seh_setframe (int);
static void obj_coff_seh_endprologue (int);
static void obj_coff_seh_save (int);
static void obj_coff_seh_pushreg (int);
static void obj_coff_seh_pushframe (int);
static void obj_coff_seh_endproc (int);
static void obj_coff_seh_eh (int);
static void obj_coff_seh_32 (int);
static void obj_coff_seh_proc (int);
static void obj_coff_seh_handler (int);
static void obj_coff_seh_handlerdata (int);
 
#define UNDSEC bfd_und_section_ptr
 
/* Check if x64 UNW_... macros are already defined. */
#ifndef PEX64_FLAG_NHANDLER
/* We can't include here coff/pe.h header. So we have to copy macros
from coff/pe.h here. */
#define PEX64_UNWCODE_CODE(VAL) ((VAL) & 0xf)
#define PEX64_UNWCODE_INFO(VAL) (((VAL) >> 4) & 0xf)
 
/* The unwind info. */
#define UNW_FLAG_NHANDLER 0
#define UNW_FLAG_EHANDLER 1
#define UNW_FLAG_UHANDLER 2
#define UNW_FLAG_FHANDLER 3
#define UNW_FLAG_CHAININFO 4
 
#define UNW_FLAG_MASK 0x1f
 
/* The unwind codes. */
#define UWOP_PUSH_NONVOL 0
#define UWOP_ALLOC_LARGE 1
#define UWOP_ALLOC_SMALL 2
#define UWOP_SET_FPREG 3
#define UWOP_SAVE_NONVOL 4
#define UWOP_SAVE_NONVOL_FAR 5
#define UWOP_SAVE_XMM 6
#define UWOP_SAVE_XMM_FAR 7
#define UWOP_SAVE_XMM128 8
#define UWOP_SAVE_XMM128_FAR 9
#define UWOP_PUSH_MACHFRAME 10
 
#define PEX64_UWI_VERSION(VAL) ((VAL) & 7)
#define PEX64_UWI_FLAGS(VAL) (((VAL) >> 3) & 0x1f)
#define PEX64_UWI_FRAMEREG(VAL) ((VAL) & 0xf)
#define PEX64_UWI_FRAMEOFF(VAL) (((VAL) >> 4) & 0xf)
#define PEX64_UWI_SIZEOF_UWCODE_ARRAY(VAL) \
((((VAL) + 1) & ~1) * 2)
 
#define PEX64_OFFSET_TO_UNWIND_CODE 0x4
 
#define PEX64_OFFSET_TO_HANDLER_RVA (COUNTOFUNWINDCODES) \
(PEX64_OFFSET_TO_UNWIND_CODE + \
PEX64_UWI_SIZEOF_UWCODE_ARRAY(COUNTOFUNWINDCODES))
 
#define PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) \
(PEX64_OFFSET_TO_HANDLER_RVA(COUNTOFUNWINDCODES) + 4)
 
#define PEX64_SCOPE_ENTRY(COUNTOFUNWINDCODES, IDX) \
(PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) + \
PEX64_SCOPE_ENTRY_SIZE * (IDX))
 
#endif
 
/contrib/toolchain/binutils/gas/config/obj-coff.c
0,0 → 1,1957
/* coff object file format
Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010
Free Software Foundation, Inc.
 
This file is part of GAS.
 
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
 
GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
#define OBJ_HEADER "obj-coff.h"
 
#include "as.h"
#include "safe-ctype.h"
#include "obstack.h"
#include "subsegs.h"
#include "struc-symbol.h"
 
#ifdef TE_PE
#include "coff/pe.h"
#endif
 
#ifdef OBJ_XCOFF
#include "coff/xcoff.h"
#endif
 
#define streq(a,b) (strcmp ((a), (b)) == 0)
#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0)
 
/* I think this is probably always correct. */
#ifndef KEEP_RELOC_INFO
#define KEEP_RELOC_INFO
#endif
 
/* obj_coff_section will use this macro to set a new section's
attributes when a directive has no valid flags or the "w" flag is
used. This default should be appropriate for most. */
#ifndef TC_COFF_SECTION_DEFAULT_ATTRIBUTES
#define TC_COFF_SECTION_DEFAULT_ATTRIBUTES (SEC_LOAD | SEC_DATA)
#endif
 
/* This is used to hold the symbol built by a sequence of pseudo-ops
from .def and .endef. */
static symbolS *def_symbol_in_progress;
#ifdef TE_PE
/* PE weak alternate symbols begin with this string. */
static const char weak_altprefix[] = ".weak.";
#endif /* TE_PE */
 
#include "obj-coff-seh.c"
 
typedef struct
{
unsigned long chunk_size;
unsigned long element_size;
unsigned long size;
char *data;
unsigned long pointer;
}
stack;
 
/* Stack stuff. */
 
static stack *
stack_init (unsigned long chunk_size,
unsigned long element_size)
{
stack *st;
 
st = malloc (sizeof (* st));
if (!st)
return NULL;
st->data = malloc (chunk_size);
if (!st->data)
{
free (st);
return NULL;
}
st->pointer = 0;
st->size = chunk_size;
st->chunk_size = chunk_size;
st->element_size = element_size;
return st;
}
 
static char *
stack_push (stack *st, char *element)
{
if (st->pointer + st->element_size >= st->size)
{
st->size += st->chunk_size;
if ((st->data = xrealloc (st->data, st->size)) == NULL)
return NULL;
}
memcpy (st->data + st->pointer, element, st->element_size);
st->pointer += st->element_size;
return st->data + st->pointer;
}
 
static char *
stack_pop (stack *st)
{
if (st->pointer < st->element_size)
{
st->pointer = 0;
return NULL;
}
st->pointer -= st->element_size;
return st->data + st->pointer;
}
/* Maintain a list of the tagnames of the structures. */
 
static struct hash_control *tag_hash;
 
static void
tag_init (void)
{
tag_hash = hash_new ();
}
 
static void
tag_insert (const char *name, symbolS *symbolP)
{
const char *error_string;
 
if ((error_string = hash_jam (tag_hash, name, (char *) symbolP)))
as_fatal (_("Inserting \"%s\" into structure table failed: %s"),
name, error_string);
}
 
static symbolS *
tag_find (char *name)
{
return (symbolS *) hash_find (tag_hash, name);
}
 
static symbolS *
tag_find_or_make (char *name)
{
symbolS *symbolP;
 
if ((symbolP = tag_find (name)) == NULL)
{
symbolP = symbol_new (name, undefined_section,
0, &zero_address_frag);
 
tag_insert (S_GET_NAME (symbolP), symbolP);
symbol_table_insert (symbolP);
}
 
return symbolP;
}
 
/* We accept the .bss directive to set the section for backward
compatibility with earlier versions of gas. */
 
static void
obj_coff_bss (int ignore ATTRIBUTE_UNUSED)
{
if (*input_line_pointer == '\n')
subseg_new (".bss", get_absolute_expression ());
else
s_lcomm (0);
}
 
#ifdef TE_PE
/* Called from read.c:s_comm after we've parsed .comm symbol, size.
Parse a possible alignment value. */
 
static symbolS *
obj_coff_common_parse (int ignore ATTRIBUTE_UNUSED, symbolS *symbolP, addressT size)
{
addressT align = 0;
 
if (*input_line_pointer == ',')
{
align = parse_align (0);
if (align == (addressT) -1)
return NULL;
}
 
S_SET_VALUE (symbolP, size);
S_SET_EXTERNAL (symbolP);
S_SET_SEGMENT (symbolP, bfd_com_section_ptr);
 
symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
 
/* There is no S_SET_ALIGN (symbolP, align) in COFF/PE.
Instead we must add a note to the .drectve section. */
if (align)
{
segT current_seg = now_seg;
subsegT current_subseg = now_subseg;
flagword oldflags;
asection *sec;
size_t pfxlen, numlen;
char *frag;
char numbuff[20];
 
sec = subseg_new (".drectve", 0);
oldflags = bfd_get_section_flags (stdoutput, sec);
if (oldflags == SEC_NO_FLAGS)
{
if (!bfd_set_section_flags (stdoutput, sec,
TC_COFF_SECTION_DEFAULT_ATTRIBUTES))
as_warn (_("error setting flags for \"%s\": %s"),
bfd_section_name (stdoutput, sec),
bfd_errmsg (bfd_get_error ()));
}
 
/* Emit a string. Note no NUL-termination. */
pfxlen = strlen (" -aligncomm:") + 2 + strlen (S_GET_NAME (symbolP)) + 1;
numlen = snprintf (numbuff, sizeof (numbuff), "%d", (int) align);
frag = frag_more (pfxlen + numlen);
(void) sprintf (frag, " -aligncomm:\"%s\",", S_GET_NAME (symbolP));
memcpy (frag + pfxlen, numbuff, numlen);
/* Restore original subseg. */
subseg_set (current_seg, current_subseg);
}
 
return symbolP;
}
 
static void
obj_coff_comm (int ignore ATTRIBUTE_UNUSED)
{
s_comm_internal (ignore, obj_coff_common_parse);
}
#endif /* TE_PE */
 
#define GET_FILENAME_STRING(X) \
((char *) (&((X)->sy_symbol.ost_auxent->x_file.x_n.x_offset))[1])
 
/* @@ Ick. */
static segT
fetch_coff_debug_section (void)
{
static segT debug_section;
 
if (!debug_section)
{
const asymbol *s;
 
s = bfd_make_debug_symbol (stdoutput, NULL, 0);
gas_assert (s != 0);
debug_section = s->section;
}
return debug_section;
}
 
void
SA_SET_SYM_ENDNDX (symbolS *sym, symbolS *val)
{
combined_entry_type *entry, *p;
 
entry = &coffsymbol (symbol_get_bfdsym (sym))->native[1];
p = coffsymbol (symbol_get_bfdsym (val))->native;
entry->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p = p;
entry->fix_end = 1;
}
 
static void
SA_SET_SYM_TAGNDX (symbolS *sym, symbolS *val)
{
combined_entry_type *entry, *p;
 
entry = &coffsymbol (symbol_get_bfdsym (sym))->native[1];
p = coffsymbol (symbol_get_bfdsym (val))->native;
entry->u.auxent.x_sym.x_tagndx.p = p;
entry->fix_tag = 1;
}
 
static int
S_GET_DATA_TYPE (symbolS *sym)
{
return coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_type;
}
 
int
S_SET_DATA_TYPE (symbolS *sym, int val)
{
coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_type = val;
return val;
}
 
int
S_GET_STORAGE_CLASS (symbolS *sym)
{
return coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_sclass;
}
 
int
S_SET_STORAGE_CLASS (symbolS *sym, int val)
{
coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_sclass = val;
return val;
}
 
/* Merge a debug symbol containing debug information into a normal symbol. */
 
static void
c_symbol_merge (symbolS *debug, symbolS *normal)
{
S_SET_DATA_TYPE (normal, S_GET_DATA_TYPE (debug));
S_SET_STORAGE_CLASS (normal, S_GET_STORAGE_CLASS (debug));
 
if (S_GET_NUMBER_AUXILIARY (debug) > S_GET_NUMBER_AUXILIARY (normal))
/* Take the most we have. */
S_SET_NUMBER_AUXILIARY (normal, S_GET_NUMBER_AUXILIARY (debug));
 
if (S_GET_NUMBER_AUXILIARY (debug) > 0)
/* Move all the auxiliary information. */
memcpy (SYM_AUXINFO (normal), SYM_AUXINFO (debug),
(S_GET_NUMBER_AUXILIARY (debug)
* sizeof (*SYM_AUXINFO (debug))));
 
/* Move the debug flags. */
SF_SET_DEBUG_FIELD (normal, SF_GET_DEBUG_FIELD (debug));
}
 
void
c_dot_file_symbol (const char *filename, int appfile ATTRIBUTE_UNUSED)
{
symbolS *symbolP;
 
/* BFD converts filename to a .file symbol with an aux entry. It
also handles chaining. */
symbolP = symbol_new (filename, bfd_abs_section_ptr, 0, &zero_address_frag);
 
S_SET_STORAGE_CLASS (symbolP, C_FILE);
S_SET_NUMBER_AUXILIARY (symbolP, 1);
 
symbol_get_bfdsym (symbolP)->flags = BSF_DEBUGGING;
 
#ifndef NO_LISTING
{
extern int listing;
 
if (listing)
listing_source_file (filename);
}
#endif
 
/* Make sure that the symbol is first on the symbol chain. */
if (symbol_rootP != symbolP)
{
symbol_remove (symbolP, &symbol_rootP, &symbol_lastP);
symbol_insert (symbolP, symbol_rootP, &symbol_rootP, &symbol_lastP);
}
}
 
/* Line number handling. */
 
struct line_no
{
struct line_no *next;
fragS *frag;
alent l;
};
 
int coff_line_base;
 
/* Symbol of last function, which we should hang line#s off of. */
static symbolS *line_fsym;
 
#define in_function() (line_fsym != 0)
#define clear_function() (line_fsym = 0)
#define set_function(F) (line_fsym = (F), coff_add_linesym (F))
 
void
coff_obj_symbol_new_hook (symbolS *symbolP)
{
long sz = (OBJ_COFF_MAX_AUXENTRIES + 1) * sizeof (combined_entry_type);
char * s = xmalloc (sz);
 
memset (s, 0, sz);
coffsymbol (symbol_get_bfdsym (symbolP))->native = (combined_entry_type *) s;
 
S_SET_DATA_TYPE (symbolP, T_NULL);
S_SET_STORAGE_CLASS (symbolP, 0);
S_SET_NUMBER_AUXILIARY (symbolP, 0);
 
if (S_IS_STRING (symbolP))
SF_SET_STRING (symbolP);
 
if (S_IS_LOCAL (symbolP))
SF_SET_LOCAL (symbolP);
}
 
void
coff_obj_symbol_clone_hook (symbolS *newsymP, symbolS *orgsymP)
{
long sz = (OBJ_COFF_MAX_AUXENTRIES + 1) * sizeof (combined_entry_type);
combined_entry_type * s = xmalloc (sz);
 
memcpy (s, coffsymbol (symbol_get_bfdsym (orgsymP))->native, sz);
coffsymbol (symbol_get_bfdsym (newsymP))->native = s;
 
SF_SET (newsymP, SF_GET (orgsymP));
}
 
/* Handle .ln directives. */
 
static symbolS *current_lineno_sym;
static struct line_no *line_nos;
/* FIXME: Blindly assume all .ln directives will be in the .text section. */
int coff_n_line_nos;
 
static void
add_lineno (fragS * frag, addressT offset, int num)
{
struct line_no * new_line = xmalloc (sizeof (* new_line));
 
if (!current_lineno_sym)
abort ();
 
#ifndef OBJ_XCOFF
/* The native aix assembler accepts negative line number. */
 
if (num <= 0)
{
/* Zero is used as an end marker in the file. */
as_warn (_("Line numbers must be positive integers\n"));
num = 1;
}
#endif /* OBJ_XCOFF */
new_line->next = line_nos;
new_line->frag = frag;
new_line->l.line_number = num;
new_line->l.u.offset = offset;
line_nos = new_line;
coff_n_line_nos++;
}
 
void
coff_add_linesym (symbolS *sym)
{
if (line_nos)
{
coffsymbol (symbol_get_bfdsym (current_lineno_sym))->lineno =
(alent *) line_nos;
coff_n_line_nos++;
line_nos = 0;
}
current_lineno_sym = sym;
}
 
static void
obj_coff_ln (int appline)
{
int l;
 
if (! appline && def_symbol_in_progress != NULL)
{
as_warn (_(".ln pseudo-op inside .def/.endef: ignored."));
demand_empty_rest_of_line ();
return;
}
 
l = get_absolute_expression ();
 
/* If there is no lineno symbol, treat a .ln
directive as if it were a .appline directive. */
if (appline || current_lineno_sym == NULL)
new_logical_line ((char *) NULL, l - 1);
else
add_lineno (frag_now, frag_now_fix (), l);
 
#ifndef NO_LISTING
{
extern int listing;
 
if (listing)
{
if (! appline)
l += coff_line_base - 1;
listing_source_line (l);
}
}
#endif
 
demand_empty_rest_of_line ();
}
 
/* .loc is essentially the same as .ln; parse it for assembler
compatibility. */
 
static void
obj_coff_loc (int ignore ATTRIBUTE_UNUSED)
{
int lineno;
 
/* FIXME: Why do we need this check? We need it for ECOFF, but why
do we need it for COFF? */
if (now_seg != text_section)
{
as_warn (_(".loc outside of .text"));
demand_empty_rest_of_line ();
return;
}
 
if (def_symbol_in_progress != NULL)
{
as_warn (_(".loc pseudo-op inside .def/.endef: ignored."));
demand_empty_rest_of_line ();
return;
}
 
/* Skip the file number. */
SKIP_WHITESPACE ();
get_absolute_expression ();
SKIP_WHITESPACE ();
 
lineno = get_absolute_expression ();
 
#ifndef NO_LISTING
{
extern int listing;
 
if (listing)
{
lineno += coff_line_base - 1;
listing_source_line (lineno);
}
}
#endif
 
demand_empty_rest_of_line ();
 
add_lineno (frag_now, frag_now_fix (), lineno);
}
 
/* Handle the .ident pseudo-op. */
 
static void
obj_coff_ident (int ignore ATTRIBUTE_UNUSED)
{
segT current_seg = now_seg;
subsegT current_subseg = now_subseg;
 
#ifdef TE_PE
{
segT sec;
 
/* We could put it in .comment, but that creates an extra section
that shouldn't be loaded into memory, which requires linker
changes... For now, until proven otherwise, use .rdata. */
sec = subseg_new (".rdata$zzz", 0);
bfd_set_section_flags (stdoutput, sec,
((SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA)
& bfd_applicable_section_flags (stdoutput)));
}
#else
subseg_new (".comment", 0);
#endif
 
stringer (8 + 1);
subseg_set (current_seg, current_subseg);
}
 
/* Handle .def directives.
 
One might ask : why can't we symbol_new if the symbol does not
already exist and fill it with debug information. Because of
the C_EFCN special symbol. It would clobber the value of the
function symbol before we have a chance to notice that it is
a C_EFCN. And a second reason is that the code is more clear this
way. (at least I think it is :-). */
 
#define SKIP_SEMI_COLON() while (*input_line_pointer++ != ';')
#define SKIP_WHITESPACES() while (*input_line_pointer == ' ' || \
*input_line_pointer == '\t') \
input_line_pointer++;
 
static void
obj_coff_def (int what ATTRIBUTE_UNUSED)
{
char name_end; /* Char after the end of name. */
char *symbol_name; /* Name of the debug symbol. */
char *symbol_name_copy; /* Temporary copy of the name. */
unsigned int symbol_name_length;
 
if (def_symbol_in_progress != NULL)
{
as_warn (_(".def pseudo-op used inside of .def/.endef: ignored."));
demand_empty_rest_of_line ();
return;
}
 
SKIP_WHITESPACES ();
 
symbol_name = input_line_pointer;
name_end = get_symbol_end ();
symbol_name_length = strlen (symbol_name);
symbol_name_copy = xmalloc (symbol_name_length + 1);
strcpy (symbol_name_copy, symbol_name);
#ifdef tc_canonicalize_symbol_name
symbol_name_copy = tc_canonicalize_symbol_name (symbol_name_copy);
#endif
 
/* Initialize the new symbol. */
def_symbol_in_progress = symbol_make (symbol_name_copy);
symbol_set_frag (def_symbol_in_progress, &zero_address_frag);
S_SET_VALUE (def_symbol_in_progress, 0);
 
if (S_IS_STRING (def_symbol_in_progress))
SF_SET_STRING (def_symbol_in_progress);
 
*input_line_pointer = name_end;
 
demand_empty_rest_of_line ();
}
 
static void
obj_coff_endef (int ignore ATTRIBUTE_UNUSED)
{
symbolS *symbolP = NULL;
 
if (def_symbol_in_progress == NULL)
{
as_warn (_(".endef pseudo-op used outside of .def/.endef: ignored."));
demand_empty_rest_of_line ();
return;
}
 
/* Set the section number according to storage class. */
switch (S_GET_STORAGE_CLASS (def_symbol_in_progress))
{
case C_STRTAG:
case C_ENTAG:
case C_UNTAG:
SF_SET_TAG (def_symbol_in_progress);
/* Fall through. */
case C_FILE:
case C_TPDEF:
SF_SET_DEBUG (def_symbol_in_progress);
S_SET_SEGMENT (def_symbol_in_progress, fetch_coff_debug_section ());
break;
 
case C_EFCN:
SF_SET_LOCAL (def_symbol_in_progress); /* Do not emit this symbol. */
/* Fall through. */
case C_BLOCK:
SF_SET_PROCESS (def_symbol_in_progress); /* Will need processing before writing. */
/* Fall through. */
case C_FCN:
{
const char *name;
 
S_SET_SEGMENT (def_symbol_in_progress, text_section);
 
name = S_GET_NAME (def_symbol_in_progress);
if (name[0] == '.' && name[2] == 'f' && name[3] == '\0')
{
switch (name[1])
{
case 'b':
/* .bf */
if (! in_function ())
as_warn (_("`%s' symbol without preceding function"), name);
/* Will need relocating. */
SF_SET_PROCESS (def_symbol_in_progress);
clear_function ();
break;
#ifdef TE_PE
case 'e':
/* .ef */
/* The MS compilers output the actual endline, not the
function-relative one... we want to match without
changing the assembler input. */
SA_SET_SYM_LNNO (def_symbol_in_progress,
(SA_GET_SYM_LNNO (def_symbol_in_progress)
+ coff_line_base));
break;
#endif
}
}
}
break;
 
#ifdef C_AUTOARG
case C_AUTOARG:
#endif /* C_AUTOARG */
case C_AUTO:
case C_REG:
case C_ARG:
case C_REGPARM:
case C_FIELD:
 
/* According to the COFF documentation:
 
http://osr5doc.sco.com:1996/topics/COFF_SectNumFld.html
 
A special section number (-2) marks symbolic debugging symbols,
including structure/union/enumeration tag names, typedefs, and
the name of the file. A section number of -1 indicates that the
symbol has a value but is not relocatable. Examples of
absolute-valued symbols include automatic and register variables,
function arguments, and .eos symbols.
 
But from Ian Lance Taylor:
 
http://sources.redhat.com/ml/binutils/2000-08/msg00202.html
 
the actual tools all marked them as section -1. So the GNU COFF
assembler follows historical COFF assemblers.
 
However, it causes problems for djgpp
 
http://sources.redhat.com/ml/binutils/2000-08/msg00210.html
 
By defining STRICTCOFF, a COFF port can make the assembler to
follow the documented behavior. */
#ifdef STRICTCOFF
case C_MOS:
case C_MOE:
case C_MOU:
case C_EOS:
#endif
SF_SET_DEBUG (def_symbol_in_progress);
S_SET_SEGMENT (def_symbol_in_progress, absolute_section);
break;
 
#ifndef STRICTCOFF
case C_MOS:
case C_MOE:
case C_MOU:
case C_EOS:
S_SET_SEGMENT (def_symbol_in_progress, absolute_section);
break;
#endif
 
case C_EXT:
case C_WEAKEXT:
#ifdef TE_PE
case C_NT_WEAK:
#endif
case C_STAT:
case C_LABEL:
/* Valid but set somewhere else (s_comm, s_lcomm, colon). */
break;
 
default:
case C_USTATIC:
case C_EXTDEF:
case C_ULABEL:
as_warn (_("unexpected storage class %d"),
S_GET_STORAGE_CLASS (def_symbol_in_progress));
break;
}
 
/* Now that we have built a debug symbol, try to find if we should
merge with an existing symbol or not. If a symbol is C_EFCN or
absolute_section or untagged SEG_DEBUG it never merges. We also
don't merge labels, which are in a different namespace, nor
symbols which have not yet been defined since they are typically
unique, nor do we merge tags with non-tags. */
 
/* Two cases for functions. Either debug followed by definition or
definition followed by debug. For definition first, we will
merge the debug symbol into the definition. For debug first, the
lineno entry MUST point to the definition function or else it
will point off into space when obj_crawl_symbol_chain() merges
the debug symbol into the real symbol. Therefor, let's presume
the debug symbol is a real function reference. */
 
/* FIXME-SOON If for some reason the definition label/symbol is
never seen, this will probably leave an undefined symbol at link
time. */
 
if (S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_EFCN
|| S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_LABEL
|| (streq (bfd_get_section_name (stdoutput,
S_GET_SEGMENT (def_symbol_in_progress)),
"*DEBUG*")
&& !SF_GET_TAG (def_symbol_in_progress))
|| S_GET_SEGMENT (def_symbol_in_progress) == absolute_section
|| ! symbol_constant_p (def_symbol_in_progress)
|| (symbolP = symbol_find (S_GET_NAME (def_symbol_in_progress))) == NULL
|| SF_GET_TAG (def_symbol_in_progress) != SF_GET_TAG (symbolP))
{
/* If it already is at the end of the symbol list, do nothing */
if (def_symbol_in_progress != symbol_lastP)
{
symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP);
symbol_append (def_symbol_in_progress, symbol_lastP, &symbol_rootP,
&symbol_lastP);
}
}
else
{
/* This symbol already exists, merge the newly created symbol
into the old one. This is not mandatory. The linker can
handle duplicate symbols correctly. But I guess that it save
a *lot* of space if the assembly file defines a lot of
symbols. [loic] */
 
/* The debug entry (def_symbol_in_progress) is merged into the
previous definition. */
 
c_symbol_merge (def_symbol_in_progress, symbolP);
symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP);
 
def_symbol_in_progress = symbolP;
 
if (SF_GET_FUNCTION (def_symbol_in_progress)
|| SF_GET_TAG (def_symbol_in_progress)
|| S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_STAT)
{
/* For functions, and tags, and static symbols, the symbol
*must* be where the debug symbol appears. Move the
existing symbol to the current place. */
/* If it already is at the end of the symbol list, do nothing. */
if (def_symbol_in_progress != symbol_lastP)
{
symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP);
symbol_append (def_symbol_in_progress, symbol_lastP, &symbol_rootP, &symbol_lastP);
}
}
}
 
if (SF_GET_TAG (def_symbol_in_progress))
{
symbolS *oldtag;
 
oldtag = symbol_find (S_GET_NAME (def_symbol_in_progress));
if (oldtag == NULL || ! SF_GET_TAG (oldtag))
tag_insert (S_GET_NAME (def_symbol_in_progress),
def_symbol_in_progress);
}
 
if (SF_GET_FUNCTION (def_symbol_in_progress))
{
set_function (def_symbol_in_progress);
SF_SET_PROCESS (def_symbol_in_progress);
 
if (symbolP == NULL)
/* That is, if this is the first time we've seen the
function. */
symbol_table_insert (def_symbol_in_progress);
 
}
 
def_symbol_in_progress = NULL;
demand_empty_rest_of_line ();
}
 
static void
obj_coff_dim (int ignore ATTRIBUTE_UNUSED)
{
int d_index;
 
if (def_symbol_in_progress == NULL)
{
as_warn (_(".dim pseudo-op used outside of .def/.endef: ignored."));
demand_empty_rest_of_line ();
return;
}
 
S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1);
 
for (d_index = 0; d_index < DIMNUM; d_index++)
{
SKIP_WHITESPACES ();
SA_SET_SYM_DIMEN (def_symbol_in_progress, d_index,
get_absolute_expression ());
 
switch (*input_line_pointer)
{
case ',':
input_line_pointer++;
break;
 
default:
as_warn (_("badly formed .dim directive ignored"));
/* Fall through. */
case '\n':
case ';':
d_index = DIMNUM;
break;
}
}
 
demand_empty_rest_of_line ();
}
 
static void
obj_coff_line (int ignore ATTRIBUTE_UNUSED)
{
int this_base;
 
if (def_symbol_in_progress == NULL)
{
/* Probably stabs-style line? */
obj_coff_ln (0);
return;
}
 
this_base = get_absolute_expression ();
if (streq (".bf", S_GET_NAME (def_symbol_in_progress)))
coff_line_base = this_base;
 
S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1);
SA_SET_SYM_LNNO (def_symbol_in_progress, this_base);
 
demand_empty_rest_of_line ();
 
#ifndef NO_LISTING
if (streq (".bf", S_GET_NAME (def_symbol_in_progress)))
{
extern int listing;
 
if (listing)
listing_source_line ((unsigned int) this_base);
}
#endif
}
 
static void
obj_coff_size (int ignore ATTRIBUTE_UNUSED)
{
if (def_symbol_in_progress == NULL)
{
as_warn (_(".size pseudo-op used outside of .def/.endef ignored."));
demand_empty_rest_of_line ();
return;
}
 
S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1);
SA_SET_SYM_SIZE (def_symbol_in_progress, get_absolute_expression ());
demand_empty_rest_of_line ();
}
 
static void
obj_coff_scl (int ignore ATTRIBUTE_UNUSED)
{
if (def_symbol_in_progress == NULL)
{
as_warn (_(".scl pseudo-op used outside of .def/.endef ignored."));
demand_empty_rest_of_line ();
return;
}
 
S_SET_STORAGE_CLASS (def_symbol_in_progress, get_absolute_expression ());
demand_empty_rest_of_line ();
}
 
static void
obj_coff_tag (int ignore ATTRIBUTE_UNUSED)
{
char *symbol_name;
char name_end;
 
if (def_symbol_in_progress == NULL)
{
as_warn (_(".tag pseudo-op used outside of .def/.endef ignored."));
demand_empty_rest_of_line ();
return;
}
 
S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1);
symbol_name = input_line_pointer;
name_end = get_symbol_end ();
 
#ifdef tc_canonicalize_symbol_name
symbol_name = tc_canonicalize_symbol_name (symbol_name);
#endif
 
/* Assume that the symbol referred to by .tag is always defined.
This was a bad assumption. I've added find_or_make. xoxorich. */
SA_SET_SYM_TAGNDX (def_symbol_in_progress,
tag_find_or_make (symbol_name));
if (SA_GET_SYM_TAGNDX (def_symbol_in_progress) == 0L)
as_warn (_("tag not found for .tag %s"), symbol_name);
 
SF_SET_TAGGED (def_symbol_in_progress);
*input_line_pointer = name_end;
 
demand_empty_rest_of_line ();
}
 
static void
obj_coff_type (int ignore ATTRIBUTE_UNUSED)
{
if (def_symbol_in_progress == NULL)
{
as_warn (_(".type pseudo-op used outside of .def/.endef ignored."));
demand_empty_rest_of_line ();
return;
}
 
S_SET_DATA_TYPE (def_symbol_in_progress, get_absolute_expression ());
 
if (ISFCN (S_GET_DATA_TYPE (def_symbol_in_progress)) &&
S_GET_STORAGE_CLASS (def_symbol_in_progress) != C_TPDEF)
SF_SET_FUNCTION (def_symbol_in_progress);
 
demand_empty_rest_of_line ();
}
 
static void
obj_coff_val (int ignore ATTRIBUTE_UNUSED)
{
if (def_symbol_in_progress == NULL)
{
as_warn (_(".val pseudo-op used outside of .def/.endef ignored."));
demand_empty_rest_of_line ();
return;
}
 
if (is_name_beginner (*input_line_pointer))
{
char *symbol_name = input_line_pointer;
char name_end = get_symbol_end ();
 
#ifdef tc_canonicalize_symbol_name
symbol_name = tc_canonicalize_symbol_name (symbol_name);
#endif
if (streq (symbol_name, "."))
{
/* If the .val is != from the .def (e.g. statics). */
symbol_set_frag (def_symbol_in_progress, frag_now);
S_SET_VALUE (def_symbol_in_progress, (valueT) frag_now_fix ());
}
else if (! streq (S_GET_NAME (def_symbol_in_progress), symbol_name))
{
expressionS exp;
 
exp.X_op = O_symbol;
exp.X_add_symbol = symbol_find_or_make (symbol_name);
exp.X_op_symbol = NULL;
exp.X_add_number = 0;
symbol_set_value_expression (def_symbol_in_progress, &exp);
 
/* If the segment is undefined when the forward reference is
resolved, then copy the segment id from the forward
symbol. */
SF_SET_GET_SEGMENT (def_symbol_in_progress);
 
/* FIXME: gcc can generate address expressions here in
unusual cases (search for "obscure" in sdbout.c). We
just ignore the offset here, thus generating incorrect
debugging information. We ignore the rest of the line
just below. */
}
/* Otherwise, it is the name of a non debug symbol and its value
will be calculated later. */
*input_line_pointer = name_end;
}
else
{
S_SET_VALUE (def_symbol_in_progress, get_absolute_expression ());
}
 
demand_empty_rest_of_line ();
}
 
#ifdef TE_PE
 
/* Return nonzero if name begins with weak alternate symbol prefix. */
 
static int
weak_is_altname (const char * name)
{
return strneq (name, weak_altprefix, sizeof (weak_altprefix) - 1);
}
 
/* Return the name of the alternate symbol
name corresponding to a weak symbol's name. */
 
static const char *
weak_name2altname (const char * name)
{
char *alt_name;
 
alt_name = xmalloc (sizeof (weak_altprefix) + strlen (name));
strcpy (alt_name, weak_altprefix);
return strcat (alt_name, name);
}
 
/* Return the name of the weak symbol corresponding to an
alternate symbol. */
 
static const char *
weak_altname2name (const char * name)
{
gas_assert (weak_is_altname (name));
return xstrdup (name + 6);
}
 
/* Make a weak symbol name unique by
appending the name of an external symbol. */
 
static const char *
weak_uniquify (const char * name)
{
char *ret;
const char * unique = "";
 
#ifdef TE_PE
if (an_external_name != NULL)
unique = an_external_name;
#endif
gas_assert (weak_is_altname (name));
 
ret = xmalloc (strlen (name) + strlen (unique) + 2);
strcpy (ret, name);
strcat (ret, ".");
strcat (ret, unique);
return ret;
}
 
void
pecoff_obj_set_weak_hook (symbolS *symbolP)
{
symbolS *alternateP;
 
/* See _Microsoft Portable Executable and Common Object
File Format Specification_, section 5.5.3.
Create a symbol representing the alternate value.
coff_frob_symbol will set the value of this symbol from
the value of the weak symbol itself. */
S_SET_STORAGE_CLASS (symbolP, C_NT_WEAK);
S_SET_NUMBER_AUXILIARY (symbolP, 1);
SA_SET_SYM_FSIZE (symbolP, IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY);
 
alternateP = symbol_find_or_make (weak_name2altname (S_GET_NAME (symbolP)));
S_SET_EXTERNAL (alternateP);
S_SET_STORAGE_CLASS (alternateP, C_NT_WEAK);
 
SA_SET_SYM_TAGNDX (symbolP, alternateP);
}
 
void
pecoff_obj_clear_weak_hook (symbolS *symbolP)
{
symbolS *alternateP;
 
S_SET_STORAGE_CLASS (symbolP, 0);
SA_SET_SYM_FSIZE (symbolP, 0);
 
alternateP = symbol_find (weak_name2altname (S_GET_NAME (symbolP)));
S_CLEAR_EXTERNAL (alternateP);
}
 
#endif /* TE_PE */
 
/* Handle .weak. This is a GNU extension in formats other than PE. */
 
static void
obj_coff_weak (int ignore ATTRIBUTE_UNUSED)
{
char *name;
int c;
symbolS *symbolP;
 
do
{
name = input_line_pointer;
c = get_symbol_end ();
if (*name == 0)
{
as_warn (_("badly formed .weak directive ignored"));
ignore_rest_of_line ();
return;
}
c = 0;
symbolP = symbol_find_or_make (name);
*input_line_pointer = c;
SKIP_WHITESPACE ();
S_SET_WEAK (symbolP);
 
if (c == ',')
{
input_line_pointer++;
SKIP_WHITESPACE ();
if (*input_line_pointer == '\n')
c = '\n';
}
 
}
while (c == ',');
 
demand_empty_rest_of_line ();
}
 
void
coff_obj_read_begin_hook (void)
{
/* These had better be the same. Usually 18 bytes. */
know (sizeof (SYMENT) == sizeof (AUXENT));
know (SYMESZ == AUXESZ);
tag_init ();
}
 
symbolS *coff_last_function;
#ifndef OBJ_XCOFF
static symbolS *coff_last_bf;
#endif
 
void
coff_frob_symbol (symbolS *symp, int *punt)
{
static symbolS *last_tagP;
static stack *block_stack;
static symbolS *set_end;
symbolS *next_set_end = NULL;
 
if (symp == &abs_symbol)
{
*punt = 1;
return;
}
 
if (current_lineno_sym)
coff_add_linesym (NULL);
 
if (!block_stack)
block_stack = stack_init (512, sizeof (symbolS*));
 
#ifdef TE_PE
if (S_GET_STORAGE_CLASS (symp) == C_NT_WEAK
&& ! S_IS_WEAK (symp)
&& weak_is_altname (S_GET_NAME (symp)))
{
/* This is a weak alternate symbol. All processing of
PECOFFweak symbols is done here, through the alternate. */
symbolS *weakp = symbol_find_noref (weak_altname2name
(S_GET_NAME (symp)), 1);
 
gas_assert (weakp);
gas_assert (S_GET_NUMBER_AUXILIARY (weakp) == 1);
 
if (! S_IS_WEAK (weakp))
{
/* The symbol was turned from weak to strong. Discard altname. */
*punt = 1;
return;
}
else if (symbol_equated_p (weakp))
{
/* The weak symbol has an alternate specified; symp is unneeded. */
S_SET_STORAGE_CLASS (weakp, C_NT_WEAK);
SA_SET_SYM_TAGNDX (weakp,
symbol_get_value_expression (weakp)->X_add_symbol);
 
S_CLEAR_EXTERNAL (symp);
*punt = 1;
return;
}
else
{
/* The weak symbol has been assigned an alternate value.
Copy this value to symp, and set symp as weakp's alternate. */
if (S_GET_STORAGE_CLASS (weakp) != C_NT_WEAK)
{
S_SET_STORAGE_CLASS (symp, S_GET_STORAGE_CLASS (weakp));
S_SET_STORAGE_CLASS (weakp, C_NT_WEAK);
}
 
if (S_IS_DEFINED (weakp))
{
/* This is a defined weak symbol. Copy value information
from the weak symbol itself to the alternate symbol. */
symbol_set_value_expression (symp,
symbol_get_value_expression (weakp));
symbol_set_frag (symp, symbol_get_frag (weakp));
S_SET_SEGMENT (symp, S_GET_SEGMENT (weakp));
}
else
{
/* This is an undefined weak symbol.
Define the alternate symbol to zero. */
S_SET_VALUE (symp, 0);
S_SET_SEGMENT (symp, absolute_section);
}
 
S_SET_NAME (symp, weak_uniquify (S_GET_NAME (symp)));
S_SET_STORAGE_CLASS (symp, C_EXT);
 
S_SET_VALUE (weakp, 0);
S_SET_SEGMENT (weakp, undefined_section);
}
}
#else /* TE_PE */
if (S_IS_WEAK (symp))
S_SET_STORAGE_CLASS (symp, C_WEAKEXT);
#endif /* TE_PE */
 
if (!S_IS_DEFINED (symp)
&& !S_IS_WEAK (symp)
&& S_GET_STORAGE_CLASS (symp) != C_STAT)
S_SET_STORAGE_CLASS (symp, C_EXT);
 
if (!SF_GET_DEBUG (symp))
{
symbolS * real;
 
if (!SF_GET_LOCAL (symp)
&& !SF_GET_STATICS (symp)
&& S_GET_STORAGE_CLASS (symp) != C_LABEL
&& symbol_constant_p (symp)
&& (real = symbol_find_noref (S_GET_NAME (symp), 1))
&& S_GET_STORAGE_CLASS (real) == C_NULL
&& real != symp)
{
c_symbol_merge (symp, real);
*punt = 1;
return;
}
 
if (!S_IS_DEFINED (symp) && !SF_GET_LOCAL (symp))
{
gas_assert (S_GET_VALUE (symp) == 0);
if (S_IS_WEAKREFD (symp))
*punt = 1;
else
S_SET_EXTERNAL (symp);
}
else if (S_GET_STORAGE_CLASS (symp) == C_NULL)
{
if (S_GET_SEGMENT (symp) == text_section
&& symp != seg_info (text_section)->sym)
S_SET_STORAGE_CLASS (symp, C_LABEL);
else
S_SET_STORAGE_CLASS (symp, C_STAT);
}
 
if (SF_GET_PROCESS (symp))
{
if (S_GET_STORAGE_CLASS (symp) == C_BLOCK)
{
if (streq (S_GET_NAME (symp), ".bb"))
stack_push (block_stack, (char *) &symp);
else
{
symbolS *begin;
 
begin = *(symbolS **) stack_pop (block_stack);
if (begin == 0)
as_warn (_("mismatched .eb"));
else
next_set_end = begin;
}
}
 
if (coff_last_function == 0 && SF_GET_FUNCTION (symp)
&& S_IS_DEFINED (symp))
{
union internal_auxent *auxp;
 
coff_last_function = symp;
if (S_GET_NUMBER_AUXILIARY (symp) < 1)
S_SET_NUMBER_AUXILIARY (symp, 1);
auxp = SYM_AUXENT (symp);
memset (auxp->x_sym.x_fcnary.x_ary.x_dimen, 0,
sizeof (auxp->x_sym.x_fcnary.x_ary.x_dimen));
}
 
if (S_GET_STORAGE_CLASS (symp) == C_EFCN
&& S_IS_DEFINED (symp))
{
if (coff_last_function == 0)
as_fatal (_("C_EFCN symbol for %s out of scope"),
S_GET_NAME (symp));
SA_SET_SYM_FSIZE (coff_last_function,
(long) (S_GET_VALUE (symp)
- S_GET_VALUE (coff_last_function)));
next_set_end = coff_last_function;
coff_last_function = 0;
}
}
 
if (S_IS_EXTERNAL (symp))
S_SET_STORAGE_CLASS (symp, C_EXT);
else if (SF_GET_LOCAL (symp))
*punt = 1;
 
if (SF_GET_FUNCTION (symp))
symbol_get_bfdsym (symp)->flags |= BSF_FUNCTION;
}
 
/* Double check weak symbols. */
if (S_IS_WEAK (symp) && S_IS_COMMON (symp))
as_bad (_("Symbol `%s' can not be both weak and common"),
S_GET_NAME (symp));
 
if (SF_GET_TAG (symp))
last_tagP = symp;
else if (S_GET_STORAGE_CLASS (symp) == C_EOS)
next_set_end = last_tagP;
 
#ifdef OBJ_XCOFF
/* This is pretty horrible, but we have to set *punt correctly in
order to call SA_SET_SYM_ENDNDX correctly. */
if (! symbol_used_in_reloc_p (symp)
&& ((symbol_get_bfdsym (symp)->flags & BSF_SECTION_SYM) != 0
|| (! (S_IS_EXTERNAL (symp) || S_IS_WEAK (symp))
&& ! symbol_get_tc (symp)->output
&& S_GET_STORAGE_CLASS (symp) != C_FILE)))
*punt = 1;
#endif
 
if (set_end != (symbolS *) NULL
&& ! *punt
&& ((symbol_get_bfdsym (symp)->flags & BSF_NOT_AT_END) != 0
|| (S_IS_DEFINED (symp)
&& ! S_IS_COMMON (symp)
&& (! S_IS_EXTERNAL (symp) || SF_GET_FUNCTION (symp)))))
{
SA_SET_SYM_ENDNDX (set_end, symp);
set_end = NULL;
}
 
if (next_set_end != NULL)
{
if (set_end != NULL)
as_warn (_("Warning: internal error: forgetting to set endndx of %s"),
S_GET_NAME (set_end));
set_end = next_set_end;
}
 
#ifndef OBJ_XCOFF
if (! *punt
&& S_GET_STORAGE_CLASS (symp) == C_FCN
&& streq (S_GET_NAME (symp), ".bf"))
{
if (coff_last_bf != NULL)
SA_SET_SYM_ENDNDX (coff_last_bf, symp);
coff_last_bf = symp;
}
#endif
if (coffsymbol (symbol_get_bfdsym (symp))->lineno)
{
int i;
struct line_no *lptr;
alent *l;
 
lptr = (struct line_no *) coffsymbol (symbol_get_bfdsym (symp))->lineno;
for (i = 0; lptr; lptr = lptr->next)
i++;
lptr = (struct line_no *) coffsymbol (symbol_get_bfdsym (symp))->lineno;
 
/* We need i entries for line numbers, plus 1 for the first
entry which BFD will override, plus 1 for the last zero
entry (a marker for BFD). */
l = xmalloc ((i + 2) * sizeof (* l));
coffsymbol (symbol_get_bfdsym (symp))->lineno = l;
l[i + 1].line_number = 0;
l[i + 1].u.sym = NULL;
for (; i > 0; i--)
{
if (lptr->frag)
lptr->l.u.offset += lptr->frag->fr_address / OCTETS_PER_BYTE;
l[i] = lptr->l;
lptr = lptr->next;
}
}
}
 
void
coff_adjust_section_syms (bfd *abfd ATTRIBUTE_UNUSED,
asection *sec,
void * x ATTRIBUTE_UNUSED)
{
symbolS *secsym;
segment_info_type *seginfo = seg_info (sec);
int nlnno, nrelocs = 0;
 
/* RS/6000 gas creates a .debug section manually in ppc_frob_file in
tc-ppc.c. Do not get confused by it. */
if (seginfo == NULL)
return;
 
if (streq (sec->name, ".text"))
nlnno = coff_n_line_nos;
else
nlnno = 0;
{
/* @@ Hope that none of the fixups expand to more than one reloc
entry... */
fixS *fixp = seginfo->fix_root;
while (fixp)
{
if (! fixp->fx_done)
nrelocs++;
fixp = fixp->fx_next;
}
}
if (bfd_get_section_size (sec) == 0
&& nrelocs == 0
&& nlnno == 0
&& sec != text_section
&& sec != data_section
&& sec != bss_section)
return;
 
secsym = section_symbol (sec);
/* This is an estimate; we'll plug in the real value using
SET_SECTION_RELOCS later */
SA_SET_SCN_NRELOC (secsym, nrelocs);
SA_SET_SCN_NLINNO (secsym, nlnno);
}
 
void
coff_frob_file_after_relocs (void)
{
bfd_map_over_sections (stdoutput, coff_adjust_section_syms, NULL);
}
 
/* Implement the .section pseudo op:
.section name {, "flags"}
^ ^
| +--- optional flags: 'b' for bss
| 'i' for info
+-- section name 'l' for lib
'n' for noload
'o' for over
'w' for data
'd' (apparently m88k for data)
'e' for exclude
'x' for text
'r' for read-only data
's' for shared data (PE)
'y' for noread
'0' - '9' for power-of-two alignment (GNU extension).
But if the argument is not a quoted string, treat it as a
subsegment number.
 
Note the 'a' flag is silently ignored. This allows the same
.section directive to be parsed in both ELF and COFF formats. */
 
void
obj_coff_section (int ignore ATTRIBUTE_UNUSED)
{
/* Strip out the section name. */
char *section_name;
char c;
int alignment = -1;
char *name;
unsigned int exp;
flagword flags, oldflags;
asection *sec;
 
if (flag_mri)
{
char type;
 
s_mri_sect (&type);
return;
}
 
section_name = input_line_pointer;
c = get_symbol_end ();
 
name = xmalloc (input_line_pointer - section_name + 1);
strcpy (name, section_name);
 
*input_line_pointer = c;
 
SKIP_WHITESPACE ();
 
exp = 0;
flags = SEC_NO_FLAGS;
 
if (*input_line_pointer == ',')
{
++input_line_pointer;
SKIP_WHITESPACE ();
if (*input_line_pointer != '"')
exp = get_absolute_expression ();
else
{
unsigned char attr;
int readonly_removed = 0;
int load_removed = 0;
 
while (attr = *++input_line_pointer,
attr != '"'
&& ! is_end_of_line[attr])
{
if (ISDIGIT (attr))
{
alignment = attr - '0';
continue;
}
switch (attr)
{
case 'e':
/* Exclude section from linking. */
flags |= SEC_EXCLUDE;
break;
 
case 'b':
/* Uninitialised data section. */
flags |= SEC_ALLOC;
flags &=~ SEC_LOAD;
break;
 
case 'n':
/* Section not loaded. */
flags &=~ SEC_LOAD;
flags |= SEC_NEVER_LOAD;
load_removed = 1;
break;
 
case 's':
/* Shared section. */
flags |= SEC_COFF_SHARED;
/* Fall through. */
case 'd':
/* Data section. */
flags |= SEC_DATA;
if (! load_removed)
flags |= SEC_LOAD;
flags &=~ SEC_READONLY;
break;
 
case 'w':
/* Writable section. */
flags &=~ SEC_READONLY;
readonly_removed = 1;
break;
 
case 'a':
/* Ignore. Here for compatibility with ELF. */
break;
 
case 'r': /* Read-only section. Implies a data section. */
readonly_removed = 0;
/* Fall through. */
case 'x': /* Executable section. */
/* If we are setting the 'x' attribute or if the 'r'
attribute is being used to restore the readonly status
of a code section (eg "wxr") then set the SEC_CODE flag,
otherwise set the SEC_DATA flag. */
flags |= (attr == 'x' || (flags & SEC_CODE) ? SEC_CODE : SEC_DATA);
if (! load_removed)
flags |= SEC_LOAD;
/* Note - the READONLY flag is set here, even for the 'x'
attribute in order to be compatible with the MSVC
linker. */
if (! readonly_removed)
flags |= SEC_READONLY;
break;
 
case 'y':
flags |= SEC_COFF_NOREAD | SEC_READONLY;
break;
 
case 'i': /* STYP_INFO */
case 'l': /* STYP_LIB */
case 'o': /* STYP_OVER */
as_warn (_("unsupported section attribute '%c'"), attr);
break;
 
default:
as_warn (_("unknown section attribute '%c'"), attr);
break;
}
}
if (attr == '"')
++input_line_pointer;
}
}
 
sec = subseg_new (name, (subsegT) exp);
 
if (alignment >= 0)
sec->alignment_power = alignment;
 
oldflags = bfd_get_section_flags (stdoutput, sec);
if (oldflags == SEC_NO_FLAGS)
{
/* Set section flags for a new section just created by subseg_new.
Provide a default if no flags were parsed. */
if (flags == SEC_NO_FLAGS)
flags = TC_COFF_SECTION_DEFAULT_ATTRIBUTES;
 
#ifdef COFF_LONG_SECTION_NAMES
/* Add SEC_LINK_ONCE and SEC_LINK_DUPLICATES_DISCARD to .gnu.linkonce
sections so adjust_reloc_syms in write.c will correctly handle
relocs which refer to non-local symbols in these sections. */
if (strneq (name, ".gnu.linkonce", sizeof (".gnu.linkonce") - 1))
flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
#endif
 
if (! bfd_set_section_flags (stdoutput, sec, flags))
as_warn (_("error setting flags for \"%s\": %s"),
bfd_section_name (stdoutput, sec),
bfd_errmsg (bfd_get_error ()));
}
else if (flags != SEC_NO_FLAGS)
{
/* This section's attributes have already been set. Warn if the
attributes don't match. */
flagword matchflags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
| SEC_DATA | SEC_COFF_SHARED | SEC_NEVER_LOAD
| SEC_COFF_NOREAD);
if ((flags ^ oldflags) & matchflags)
as_warn (_("Ignoring changed section attributes for %s"), name);
}
 
demand_empty_rest_of_line ();
}
 
void
coff_adjust_symtab (void)
{
if (symbol_rootP == NULL
|| S_GET_STORAGE_CLASS (symbol_rootP) != C_FILE)
c_dot_file_symbol ("fake", 0);
}
 
void
coff_frob_section (segT sec)
{
segT strsec;
char *p;
fragS *fragp;
bfd_vma n_entries;
 
/* The COFF back end in BFD requires that all section sizes be
rounded up to multiples of the corresponding section alignments,
supposedly because standard COFF has no other way of encoding alignment
for sections. If your COFF flavor has a different way of encoding
section alignment, then skip this step, as TICOFF does. */
bfd_vma size = bfd_get_section_size (sec);
#if !defined(TICOFF)
bfd_vma align_power = (bfd_vma) sec->alignment_power + OCTETS_PER_BYTE_POWER;
bfd_vma mask = ((bfd_vma) 1 << align_power) - 1;
 
if (size & mask)
{
bfd_vma new_size;
fragS *last;
 
new_size = (size + mask) & ~mask;
bfd_set_section_size (stdoutput, sec, new_size);
 
/* If the size had to be rounded up, add some padding in
the last non-empty frag. */
fragp = seg_info (sec)->frchainP->frch_root;
last = seg_info (sec)->frchainP->frch_last;
while (fragp->fr_next != last)
fragp = fragp->fr_next;
last->fr_address = size;
fragp->fr_offset += new_size - size;
}
#endif
 
/* If the section size is non-zero, the section symbol needs an aux
entry associated with it, indicating the size. We don't know
all the values yet; coff_frob_symbol will fill them in later. */
#ifndef TICOFF
if (size != 0
|| sec == text_section
|| sec == data_section
|| sec == bss_section)
#endif
{
symbolS *secsym = section_symbol (sec);
unsigned char sclass = C_STAT;
 
#ifdef OBJ_XCOFF
if (bfd_get_section_flags (stdoutput, sec) & SEC_DEBUGGING)
sclass = C_DWARF;
#endif
S_SET_STORAGE_CLASS (secsym, sclass);
S_SET_NUMBER_AUXILIARY (secsym, 1);
SF_SET_STATICS (secsym);
SA_SET_SCN_SCNLEN (secsym, size);
}
/* FIXME: These should be in a "stabs.h" file, or maybe as.h. */
#ifndef STAB_SECTION_NAME
#define STAB_SECTION_NAME ".stab"
#endif
#ifndef STAB_STRING_SECTION_NAME
#define STAB_STRING_SECTION_NAME ".stabstr"
#endif
if (! streq (STAB_STRING_SECTION_NAME, sec->name))
return;
 
strsec = sec;
sec = subseg_get (STAB_SECTION_NAME, 0);
/* size is already rounded up, since other section will be listed first */
size = bfd_get_section_size (strsec);
 
n_entries = bfd_get_section_size (sec) / 12 - 1;
 
/* Find first non-empty frag. It should be large enough. */
fragp = seg_info (sec)->frchainP->frch_root;
while (fragp && fragp->fr_fix == 0)
fragp = fragp->fr_next;
gas_assert (fragp != 0 && fragp->fr_fix >= 12);
 
/* Store the values. */
p = fragp->fr_literal;
bfd_h_put_16 (stdoutput, n_entries, (bfd_byte *) p + 6);
bfd_h_put_32 (stdoutput, size, (bfd_byte *) p + 8);
}
 
void
obj_coff_init_stab_section (segT seg)
{
char *file;
char *p;
char *stabstr_name;
unsigned int stroff;
 
/* Make space for this first symbol. */
p = frag_more (12);
/* Zero it out. */
memset (p, 0, 12);
as_where (&file, (unsigned int *) NULL);
stabstr_name = xmalloc (strlen (seg->name) + 4);
strcpy (stabstr_name, seg->name);
strcat (stabstr_name, "str");
stroff = get_stab_string_offset (file, stabstr_name);
know (stroff == 1);
md_number_to_chars (p, stroff, 4);
}
 
#ifdef DEBUG
const char * s_get_name (symbolS *);
 
const char *
s_get_name (symbolS *s)
{
return ((s == NULL) ? "(NULL)" : S_GET_NAME (s));
}
 
void symbol_dump (void);
 
void
symbol_dump (void)
{
symbolS *symbolP;
 
for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
printf (_("0x%lx: \"%s\" type = %ld, class = %d, segment = %d\n"),
(unsigned long) symbolP,
S_GET_NAME (symbolP),
(long) S_GET_DATA_TYPE (symbolP),
S_GET_STORAGE_CLASS (symbolP),
(int) S_GET_SEGMENT (symbolP));
}
 
#endif /* DEBUG */
 
const pseudo_typeS coff_pseudo_table[] =
{
{"ABORT", s_abort, 0},
{"appline", obj_coff_ln, 1},
/* We accept the .bss directive for backward compatibility with
earlier versions of gas. */
{"bss", obj_coff_bss, 0},
#ifdef TE_PE
/* PE provides an enhanced version of .comm with alignment. */
{"comm", obj_coff_comm, 0},
#endif /* TE_PE */
{"def", obj_coff_def, 0},
{"dim", obj_coff_dim, 0},
{"endef", obj_coff_endef, 0},
{"ident", obj_coff_ident, 0},
{"line", obj_coff_line, 0},
{"ln", obj_coff_ln, 0},
{"scl", obj_coff_scl, 0},
{"sect", obj_coff_section, 0},
{"sect.s", obj_coff_section, 0},
{"section", obj_coff_section, 0},
{"section.s", obj_coff_section, 0},
/* FIXME: We ignore the MRI short attribute. */
{"size", obj_coff_size, 0},
{"tag", obj_coff_tag, 0},
{"type", obj_coff_type, 0},
{"val", obj_coff_val, 0},
{"version", s_ignore, 0},
{"loc", obj_coff_loc, 0},
{"optim", s_ignore, 0}, /* For sun386i cc (?) */
{"weak", obj_coff_weak, 0},
#if defined TC_TIC4X
/* The tic4x uses sdef instead of def. */
{"sdef", obj_coff_def, 0},
#endif
#if defined(SEH_CMDS)
SEH_CMDS
#endif
{NULL, NULL, 0}
};
 
/* Support for a COFF emulation. */
 
static void
coff_pop_insert (void)
{
pop_insert (coff_pseudo_table);
}
 
static int
coff_separate_stab_sections (void)
{
return 1;
}
 
const struct format_ops coff_format_ops =
{
bfd_target_coff_flavour,
0, /* dfl_leading_underscore */
1, /* emit_section_symbols */
0, /* begin */
c_dot_file_symbol,
coff_frob_symbol,
0, /* frob_file */
0, /* frob_file_before_adjust */
0, /* frob_file_before_fix */
coff_frob_file_after_relocs,
0, /* s_get_size */
0, /* s_set_size */
0, /* s_get_align */
0, /* s_set_align */
0, /* s_get_other */
0, /* s_set_other */
0, /* s_get_desc */
0, /* s_set_desc */
0, /* s_get_type */
0, /* s_set_type */
0, /* copy_symbol_attributes */
0, /* generate_asm_lineno */
0, /* process_stab */
coff_separate_stab_sections,
obj_coff_init_stab_section,
0, /* sec_sym_ok_for_reloc */
coff_pop_insert,
0, /* ecoff_set_ext */
coff_obj_read_begin_hook,
coff_obj_symbol_new_hook,
coff_obj_symbol_clone_hook,
coff_adjust_symtab
};
/contrib/toolchain/binutils/gas/config/obj-coff.h
0,0 → 1,415
/* coff object file format
Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009
Free Software Foundation, Inc.
 
This file is part of GAS.
 
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
 
GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
#ifndef OBJ_FORMAT_H
#define OBJ_FORMAT_H
 
#define OBJ_COFF 1
 
#include "targ-cpu.h"
 
/* This internal_lineno crap is to stop namespace pollution from the
bfd internal coff headerfile. */
#define internal_lineno bfd_internal_lineno
#include "coff/internal.h"
#undef internal_lineno
 
/* CPU-specific setup: */
 
#ifdef TC_ARM
#include "coff/arm.h"
#ifndef TARGET_FORMAT
#define TARGET_FORMAT "coff-arm"
#endif
#endif
 
#ifdef TC_PPC
#ifdef TE_PE
#include "coff/powerpc.h"
#else
#include "coff/rs6000.h"
#endif
#endif
 
#ifdef TC_SPARC
#include "coff/sparc.h"
#endif
 
#ifdef TC_I386
#ifdef TE_PEP
#include "coff/x86_64.h"
#else
#include "coff/i386.h"
#endif
 
#ifndef TARGET_FORMAT
#ifdef TE_PEP
#define TARGET_FORMAT "coff-x86-64"
#else
#define TARGET_FORMAT "coff-i386"
#endif
#endif
#endif
 
#ifdef TC_M68K
#include "coff/m68k.h"
#ifndef TARGET_FORMAT
#define TARGET_FORMAT "coff-m68k"
#endif
#endif
 
#ifdef TC_OR32
#include "coff/or32.h"
#define TARGET_FORMAT "coff-or32-big"
#endif
 
#ifdef TC_I960
#include "coff/i960.h"
#define TARGET_FORMAT "coff-Intel-little"
#endif
 
#ifdef TC_Z80
#include "coff/z80.h"
#define TARGET_FORMAT "coff-z80"
#endif
 
#ifdef TC_Z8K
#include "coff/z8k.h"
#define TARGET_FORMAT "coff-z8k"
#endif
 
#ifdef TC_H8300
#include "coff/h8300.h"
#define TARGET_FORMAT "coff-h8300"
#endif
 
#ifdef TC_H8500
#include "coff/h8500.h"
#define TARGET_FORMAT "coff-h8500"
#endif
 
#ifdef TC_SH
 
#ifdef TE_PE
#define COFF_WITH_PE
#endif
 
#include "coff/sh.h"
 
#ifdef TE_PE
#define TARGET_FORMAT "pe-shl"
#else
 
#define TARGET_FORMAT \
(!target_big_endian \
? (sh_small ? "coff-shl-small" : "coff-shl") \
: (sh_small ? "coff-sh-small" : "coff-sh"))
 
#endif
#endif
 
#ifdef TC_MIPS
#define COFF_WITH_PE
#include "coff/mipspe.h"
#undef TARGET_FORMAT
#define TARGET_FORMAT "pe-mips"
#endif
 
#ifdef TC_TIC30
#include "coff/tic30.h"
#define TARGET_FORMAT "coff-tic30"
#endif
 
#ifdef TC_TIC4X
#include "coff/tic4x.h"
#define TARGET_FORMAT "coff2-tic4x"
#endif
 
#ifdef TC_TIC54X
#include "coff/tic54x.h"
#define TARGET_FORMAT "coff1-c54x"
#endif
 
#ifdef TC_MCORE
#include "coff/mcore.h"
#ifndef TARGET_FORMAT
#define TARGET_FORMAT "pe-mcore"
#endif
#endif
 
#ifdef TE_PE
#define obj_set_weak_hook pecoff_obj_set_weak_hook
#define obj_clear_weak_hook pecoff_obj_clear_weak_hook
#endif
 
#ifndef OBJ_COFF_MAX_AUXENTRIES
#define OBJ_COFF_MAX_AUXENTRIES 1
#endif
 
#define obj_symbol_new_hook coff_obj_symbol_new_hook
#define obj_symbol_clone_hook coff_obj_symbol_clone_hook
#define obj_read_begin_hook coff_obj_read_begin_hook
 
#include "bfd/libcoff.h"
 
#define OUTPUT_FLAVOR bfd_target_coff_flavour
 
/* Alter the field names, for now, until we've fixed up the other
references to use the new name. */
#ifdef TC_I960
#define TC_SYMFIELD_TYPE symbolS *
#define sy_tc bal
#endif
 
#define OBJ_SYMFIELD_TYPE unsigned long
#define sy_obj sy_obj_flags
 
/* We can't use the predefined section symbols in bfd/section.c, as
COFF symbols have extra fields. See bfd/libcoff.h:coff_symbol_type. */
#ifndef obj_sec_sym_ok_for_reloc
#define obj_sec_sym_ok_for_reloc(SEC) ((SEC)->owner != 0)
#endif
 
#define SYM_AUXENT(S) \
(&coffsymbol (symbol_get_bfdsym (S))->native[1].u.auxent)
#define SYM_AUXINFO(S) \
(&coffsymbol (symbol_get_bfdsym (S))->native[1])
 
/* The number of auxiliary entries. */
#define S_GET_NUMBER_AUXILIARY(s) \
(coffsymbol (symbol_get_bfdsym (s))->native->u.syment.n_numaux)
/* The number of auxiliary entries. */
#define S_SET_NUMBER_AUXILIARY(s, v) (S_GET_NUMBER_AUXILIARY (s) = (v))
 
/* True if a symbol name is in the string table, i.e. its length is > 8. */
#define S_IS_STRING(s) (strlen (S_GET_NAME (s)) > 8 ? 1 : 0)
 
/* Auxiliary entry macros. SA_ stands for symbol auxiliary. */
/* Omit the tv related fields. */
/* Accessors. */
 
#define SA_GET_SYM_TAGNDX(s) (SYM_AUXENT (s)->x_sym.x_tagndx.l)
#define SA_GET_SYM_LNNO(s) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_lnno)
#define SA_GET_SYM_SIZE(s) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_size)
#define SA_GET_SYM_FSIZE(s) (SYM_AUXENT (s)->x_sym.x_misc.x_fsize)
#define SA_GET_SYM_LNNOPTR(s) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_lnnoptr)
#define SA_GET_SYM_ENDNDX(s) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_endndx)
#define SA_GET_SYM_DIMEN(s,i) (SYM_AUXENT (s)->x_sym.x_fcnary.x_ary.x_dimen[(i)])
#define SA_GET_FILE_FNAME(s) (SYM_AUXENT (s)->x_file.x_fname)
#define SA_GET_SCN_SCNLEN(s) (SYM_AUXENT (s)->x_scn.x_scnlen)
#define SA_GET_SCN_NRELOC(s) (SYM_AUXENT (s)->x_scn.x_nreloc)
#define SA_GET_SCN_NLINNO(s) (SYM_AUXENT (s)->x_scn.x_nlinno)
 
#define SA_SET_SYM_LNNO(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_lnno = (v))
#define SA_SET_SYM_SIZE(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_size = (v))
#define SA_SET_SYM_FSIZE(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_fsize = (v))
#define SA_SET_SYM_LNNOPTR(s,v) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_lnnoptr = (v))
#define SA_SET_SYM_DIMEN(s,i,v) (SYM_AUXENT (s)->x_sym.x_fcnary.x_ary.x_dimen[(i)] = (v))
#define SA_SET_FILE_FNAME(s,v) strncpy (SYM_AUXENT (s)->x_file.x_fname, (v), FILNMLEN)
#define SA_SET_SCN_SCNLEN(s,v) (SYM_AUXENT (s)->x_scn.x_scnlen = (v))
#define SA_SET_SCN_NRELOC(s,v) (SYM_AUXENT (s)->x_scn.x_nreloc = (v))
#define SA_SET_SCN_NLINNO(s,v) (SYM_AUXENT (s)->x_scn.x_nlinno = (v))
 
/* Internal use only definitions. SF_ stands for symbol flags.
 
These values can be assigned to sy_symbol.ost_flags field of a symbolS.
 
You'll break i960 if you shift the SYSPROC bits anywhere else. for
more on the balname/callname hack, see tc-i960.h. b.out is done
differently. */
 
#define SF_I960_MASK 0x000001ff /* Bits 0-8 are used by the i960 port. */
#define SF_SYSPROC 0x0000003f /* bits 0-5 are used to store the sysproc number. */
#define SF_IS_SYSPROC 0x00000040 /* bit 6 marks symbols that are sysprocs. */
#define SF_BALNAME 0x00000080 /* bit 7 marks BALNAME symbols. */
#define SF_CALLNAME 0x00000100 /* bit 8 marks CALLNAME symbols. */
#define SF_NORMAL_MASK 0x0000ffff /* bits 12-15 are general purpose. */
#define SF_STATICS 0x00001000 /* Mark the .text & all symbols. */
#define SF_DEFINED 0x00002000 /* Symbol is defined in this file. */
#define SF_STRING 0x00004000 /* Symbol name length > 8. */
#define SF_LOCAL 0x00008000 /* Symbol must not be emitted. */
#define SF_DEBUG_MASK 0xffff0000 /* bits 16-31 are debug info. */
#define SF_FUNCTION 0x00010000 /* The symbol is a function. */
#define SF_PROCESS 0x00020000 /* Process symbol before write. */
#define SF_TAGGED 0x00040000 /* Is associated with a tag. */
#define SF_TAG 0x00080000 /* Is a tag. */
#define SF_DEBUG 0x00100000 /* Is in debug or abs section. */
#define SF_GET_SEGMENT 0x00200000 /* Get the section of the forward symbol. */
/* All other bits are unused. */
 
/* Accessors. */
#define SF_GET(s) (* symbol_get_obj (s))
#define SF_GET_DEBUG(s) (symbol_get_bfdsym (s)->flags & BSF_DEBUGGING)
#define SF_SET_DEBUG(s) (symbol_get_bfdsym (s)->flags |= BSF_DEBUGGING)
#define SF_GET_NORMAL_FIELD(s) (SF_GET (s) & SF_NORMAL_MASK)
#define SF_GET_DEBUG_FIELD(s) (SF_GET (s) & SF_DEBUG_MASK)
#define SF_GET_FILE(s) (SF_GET (s) & SF_FILE)
#define SF_GET_STATICS(s) (SF_GET (s) & SF_STATICS)
#define SF_GET_DEFINED(s) (SF_GET (s) & SF_DEFINED)
#define SF_GET_STRING(s) (SF_GET (s) & SF_STRING)
#define SF_GET_LOCAL(s) (SF_GET (s) & SF_LOCAL)
#define SF_GET_FUNCTION(s) (SF_GET (s) & SF_FUNCTION)
#define SF_GET_PROCESS(s) (SF_GET (s) & SF_PROCESS)
#define SF_GET_TAGGED(s) (SF_GET (s) & SF_TAGGED)
#define SF_GET_TAG(s) (SF_GET (s) & SF_TAG)
#define SF_GET_GET_SEGMENT(s) (SF_GET (s) & SF_GET_SEGMENT)
#define SF_GET_I960(s) (SF_GET (s) & SF_I960_MASK) /* Used by i960. */
#define SF_GET_BALNAME(s) (SF_GET (s) & SF_BALNAME) /* Used by i960. */
#define SF_GET_CALLNAME(s) (SF_GET (s) & SF_CALLNAME) /* Used by i960. */
#define SF_GET_IS_SYSPROC(s) (SF_GET (s) & SF_IS_SYSPROC) /* Used by i960. */
#define SF_GET_SYSPROC(s) (SF_GET (s) & SF_SYSPROC) /* Used by i960. */
 
/* Modifiers. */
#define SF_SET(s,v) (SF_GET (s) = (v))
#define SF_SET_NORMAL_FIELD(s,v)(SF_GET (s) |= ((v) & SF_NORMAL_MASK))
#define SF_SET_DEBUG_FIELD(s,v) (SF_GET (s) |= ((v) & SF_DEBUG_MASK))
#define SF_SET_FILE(s) (SF_GET (s) |= SF_FILE)
#define SF_SET_STATICS(s) (SF_GET (s) |= SF_STATICS)
#define SF_SET_DEFINED(s) (SF_GET (s) |= SF_DEFINED)
#define SF_SET_STRING(s) (SF_GET (s) |= SF_STRING)
#define SF_SET_LOCAL(s) (SF_GET (s) |= SF_LOCAL)
#define SF_CLEAR_LOCAL(s) (SF_GET (s) &= ~SF_LOCAL)
#define SF_SET_FUNCTION(s) (SF_GET (s) |= SF_FUNCTION)
#define SF_SET_PROCESS(s) (SF_GET (s) |= SF_PROCESS)
#define SF_SET_TAGGED(s) (SF_GET (s) |= SF_TAGGED)
#define SF_SET_TAG(s) (SF_GET (s) |= SF_TAG)
#define SF_SET_GET_SEGMENT(s) (SF_GET (s) |= SF_GET_SEGMENT)
#define SF_SET_I960(s,v) (SF_GET (s) |= ((v) & SF_I960_MASK)) /* Used by i960. */
#define SF_SET_BALNAME(s) (SF_GET (s) |= SF_BALNAME) /* Used by i960. */
#define SF_SET_CALLNAME(s) (SF_GET (s) |= SF_CALLNAME) /* Used by i960. */
#define SF_SET_IS_SYSPROC(s) (SF_GET (s) |= SF_IS_SYSPROC) /* Used by i960. */
#define SF_SET_SYSPROC(s,v) (SF_GET (s) |= ((v) & SF_SYSPROC)) /* Used by i960. */
 
 
/* Line number handling. */
extern int text_lineno_number;
extern int coff_line_base;
extern int coff_n_line_nos;
extern symbolS *coff_last_function;
 
#define obj_emit_lineno(WHERE, LINE, FILE_START) abort ()
#define obj_app_file(name, app) c_dot_file_symbol (name, app)
#define obj_frob_symbol(S,P) coff_frob_symbol (S, & P)
#define obj_frob_section(S) coff_frob_section (S)
#define obj_frob_file_after_relocs() coff_frob_file_after_relocs ()
#ifndef obj_adjust_symtab
#define obj_adjust_symtab() coff_adjust_symtab ()
#endif
 
/* Forward the segment of a forwarded symbol, handle assignments that
just copy symbol values, etc. */
#ifndef OBJ_COPY_SYMBOL_ATTRIBUTES
#ifndef TE_I386AIX
#define OBJ_COPY_SYMBOL_ATTRIBUTES(dest, src) \
(SF_GET_GET_SEGMENT (dest) \
? (S_SET_SEGMENT (dest, S_GET_SEGMENT (src)), 0) \
: 0)
#else
#define OBJ_COPY_SYMBOL_ATTRIBUTES(dest, src) \
(SF_GET_GET_SEGMENT (dest) && S_GET_SEGMENT (dest) == SEG_UNKNOWN \
? (S_SET_SEGMENT (dest, S_GET_SEGMENT (src)), 0) \
: 0)
#endif
#endif
 
/* Sanity check. */
 
#ifdef TC_I960
#ifndef C_LEAFSTAT
hey ! Where is the C_LEAFSTAT definition ? i960 - coff support is depending on it.
#endif /* no C_LEAFSTAT */
#endif /* TC_I960 */
 
extern const pseudo_typeS coff_pseudo_table[];
 
#ifndef obj_pop_insert
#define obj_pop_insert() pop_insert (coff_pseudo_table)
#endif
 
/* In COFF, if a symbol is defined using .def/.val SYM/.endef, it's OK
to redefine the symbol later on. This can happen if C symbols use
a prefix, and a symbol is defined both with and without the prefix,
as in start/_start/__start in gcc/libgcc1-test.c. */
#define RESOLVE_SYMBOL_REDEFINITION(sym) \
(SF_GET_GET_SEGMENT (sym) \
? (sym->sy_frag = frag_now, \
S_SET_VALUE (sym, frag_now_fix ()), \
S_SET_SEGMENT (sym, now_seg), \
0) \
: 0)
 
/* Stabs in a coff file go into their own section. */
#define SEPARATE_STAB_SECTIONS 1
 
/* We need 12 bytes at the start of the section to hold some initial
information. */
#define INIT_STAB_SECTION(seg) obj_coff_init_stab_section (seg)
 
/* Store the number of relocations in the section aux entry. */
#define SET_SECTION_RELOCS(sec, relocs, n) \
SA_SET_SCN_NRELOC (section_symbol (sec), n)
 
#define obj_app_file(name, app) c_dot_file_symbol (name, app)
 
extern int S_SET_DATA_TYPE (symbolS *, int);
extern int S_SET_STORAGE_CLASS (symbolS *, int);
extern int S_GET_STORAGE_CLASS (symbolS *);
extern void SA_SET_SYM_ENDNDX (symbolS *, symbolS *);
extern void coff_add_linesym (symbolS *);
extern void c_dot_file_symbol (const char *, int);
extern void coff_frob_symbol (symbolS *, int *);
extern void coff_adjust_symtab (void);
extern void coff_frob_section (segT);
extern void coff_adjust_section_syms (bfd *, asection *, void *);
extern void coff_frob_file_after_relocs (void);
extern void coff_obj_symbol_new_hook (symbolS *);
extern void coff_obj_symbol_clone_hook (symbolS *, symbolS *);
extern void coff_obj_read_begin_hook (void);
#ifdef TE_PE
extern void pecoff_obj_set_weak_hook (symbolS *);
extern void pecoff_obj_clear_weak_hook (symbolS *);
#endif
extern void obj_coff_section (int);
extern segT obj_coff_add_segment (const char *);
extern void obj_coff_section (int);
extern void c_dot_file_symbol (const char *, int);
extern segT s_get_segment (symbolS *);
#ifndef tc_coff_symbol_emit_hook
extern void tc_coff_symbol_emit_hook (symbolS *);
#endif
extern void obj_coff_pe_handle_link_once (void);
extern void obj_coff_init_stab_section (segT);
extern void c_section_header (struct internal_scnhdr *,
char *, long, long, long, long,
long, long, long, long);
extern void obj_coff_seh_do_final (void);
 
#ifndef obj_coff_generate_pdata
#define obj_coff_generate_pdata obj_coff_seh_do_final
#endif
 
 
#endif /* OBJ_FORMAT_H */
/contrib/toolchain/binutils/gas/config/tc-i386-intel.c
0,0 → 1,1005
/* tc-i386.c -- Assemble Intel syntax code for ix86/x86-64
Copyright 2009, 2010
Free Software Foundation, Inc.
 
This file is part of GAS, the GNU Assembler.
 
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
 
GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
static struct
{
operatorT op_modifier; /* Operand modifier. */
int is_mem; /* 1 if operand is memory reference. */
int is_indirect; /* 1 if operand is indirect reference. */
int has_offset; /* 1 if operand has offset. */
unsigned int in_offset; /* >=1 if processing operand of offset. */
unsigned int in_bracket; /* >=1 if processing operand in brackets. */
unsigned int in_scale; /* >=1 if processing multipication operand
* in brackets. */
i386_operand_type reloc_types; /* Value obtained from lex_got(). */
const reg_entry *base; /* Base register (if any). */
const reg_entry *index; /* Index register (if any). */
offsetT scale_factor; /* Accumulated scale factor. */
symbolS *seg;
}
intel_state;
 
/* offset X_add_symbol */
#define O_offset O_md32
/* offset X_add_symbol */
#define O_short O_md31
/* near ptr X_add_symbol */
#define O_near_ptr O_md30
/* far ptr X_add_symbol */
#define O_far_ptr O_md29
/* byte ptr X_add_symbol */
#define O_byte_ptr O_md28
/* word ptr X_add_symbol */
#define O_word_ptr O_md27
/* dword ptr X_add_symbol */
#define O_dword_ptr O_md26
/* qword ptr X_add_symbol */
#define O_qword_ptr O_md25
/* oword ptr X_add_symbol */
#define O_oword_ptr O_md24
/* fword ptr X_add_symbol */
#define O_fword_ptr O_md23
/* tbyte ptr X_add_symbol */
#define O_tbyte_ptr O_md22
/* xmmword ptr X_add_symbol */
#define O_xmmword_ptr O_md21
/* ymmword ptr X_add_symbol */
#define O_ymmword_ptr O_md20
/* zmmword ptr X_add_symbol */
#define O_zmmword_ptr O_md19
 
static struct
{
const char *name;
operatorT op;
unsigned int operands;
}
const i386_operators[] =
{
{ "and", O_bit_and, 2 },
{ "eq", O_eq, 2 },
{ "ge", O_ge, 2 },
{ "gt", O_gt, 2 },
{ "le", O_le, 2 },
{ "lt", O_lt, 2 },
{ "mod", O_modulus, 2 },
{ "ne", O_ne, 2 },
{ "not", O_bit_not, 1 },
{ "offset", O_offset, 1 },
{ "or", O_bit_inclusive_or, 2 },
{ "shl", O_left_shift, 2 },
{ "short", O_short, 1 },
{ "shr", O_right_shift, 2 },
{ "xor", O_bit_exclusive_or, 2 },
{ NULL, O_illegal, 0 }
};
 
static struct
{
const char *name;
operatorT op;
unsigned short sz[3];
}
const i386_types[] =
{
#define I386_TYPE(t, n) { #t, O_##t##_ptr, { n, n, n } }
I386_TYPE(byte, 1),
I386_TYPE(word, 2),
I386_TYPE(dword, 4),
I386_TYPE(fword, 6),
I386_TYPE(qword, 8),
I386_TYPE(tbyte, 10),
I386_TYPE(oword, 16),
I386_TYPE(xmmword, 16),
I386_TYPE(ymmword, 32),
I386_TYPE(zmmword, 64),
#undef I386_TYPE
{ "near", O_near_ptr, { 0xff04, 0xff02, 0xff08 } },
{ "far", O_far_ptr, { 0xff06, 0xff05, 0xff06 } },
{ NULL, O_illegal, { 0, 0, 0 } }
};
 
operatorT i386_operator (const char *name, unsigned int operands, char *pc)
{
unsigned int j;
 
if (!intel_syntax)
return O_absent;
 
if (!name)
{
if (operands != 2)
return O_illegal;
switch (*input_line_pointer)
{
case ':':
++input_line_pointer;
return O_full_ptr;
case '[':
++input_line_pointer;
return O_index;
case '@':
if (this_operand >= 0 && i.reloc[this_operand] == NO_RELOC)
{
int adjust = 0;
char *gotfree_input_line = lex_got (&i.reloc[this_operand],
&adjust,
&intel_state.reloc_types,
(i.bnd_prefix != NULL
|| add_bnd_prefix));
 
if (!gotfree_input_line)
break;
free (gotfree_input_line);
*input_line_pointer++ = '+';
memset (input_line_pointer, '0', adjust - 1);
input_line_pointer[adjust - 1] = ' ';
return O_add;
}
break;
}
return O_illegal;
}
 
for (j = 0; i386_operators[j].name; ++j)
if (strcasecmp (i386_operators[j].name, name) == 0)
{
if (i386_operators[j].operands
&& i386_operators[j].operands != operands)
return O_illegal;
return i386_operators[j].op;
}
 
for (j = 0; i386_types[j].name; ++j)
if (strcasecmp (i386_types[j].name, name) == 0)
break;
if (i386_types[j].name && *pc == ' ')
{
char *pname = ++input_line_pointer;
char c = get_symbol_end ();
 
if (strcasecmp (pname, "ptr") == 0)
{
pname[-1] = *pc;
*pc = c;
if (intel_syntax > 0 || operands != 1)
return O_illegal;
return i386_types[j].op;
}
 
*input_line_pointer = c;
input_line_pointer = pname - 1;
}
 
return O_absent;
}
 
static int i386_intel_parse_name (const char *name, expressionS *e)
{
unsigned int j;
 
if (! strcmp (name, "$"))
{
current_location (e);
return 1;
}
 
for (j = 0; i386_types[j].name; ++j)
if (strcasecmp(i386_types[j].name, name) == 0)
{
e->X_op = O_constant;
e->X_add_number = i386_types[j].sz[flag_code];
e->X_add_symbol = NULL;
e->X_op_symbol = NULL;
return 1;
}
 
return 0;
}
 
static INLINE int i386_intel_check (const reg_entry *rreg,
const reg_entry *base,
const reg_entry *iindex)
{
if ((this_operand >= 0
&& rreg != i.op[this_operand].regs)
|| base != intel_state.base
|| iindex != intel_state.index)
{
as_bad (_("invalid use of register"));
return 0;
}
return 1;
}
 
static INLINE void i386_intel_fold (expressionS *e, symbolS *sym)
{
expressionS *exp = symbol_get_value_expression (sym);
if (S_GET_SEGMENT (sym) == absolute_section)
{
offsetT val = e->X_add_number;
 
*e = *exp;
e->X_add_number += val;
}
else
{
if (exp->X_op == O_symbol
&& strcmp (S_GET_NAME (exp->X_add_symbol),
GLOBAL_OFFSET_TABLE_NAME) == 0)
sym = exp->X_add_symbol;
e->X_add_symbol = sym;
e->X_op_symbol = NULL;
e->X_op = O_symbol;
}
}
 
static int
i386_intel_simplify_register (expressionS *e)
{
int reg_num;
 
if (this_operand < 0 || intel_state.in_offset)
{
as_bad (_("invalid use of register"));
return 0;
}
 
if (e->X_op == O_register)
reg_num = e->X_add_number;
else
reg_num = e->X_md - 1;
 
if (!intel_state.in_bracket)
{
if (i.op[this_operand].regs)
{
as_bad (_("invalid use of register"));
return 0;
}
if (i386_regtab[reg_num].reg_type.bitfield.sreg3
&& i386_regtab[reg_num].reg_num == RegFlat)
{
as_bad (_("invalid use of pseudo-register"));
return 0;
}
i.op[this_operand].regs = i386_regtab + reg_num;
}
else if (!intel_state.index
&& (i386_regtab[reg_num].reg_type.bitfield.regxmm
|| i386_regtab[reg_num].reg_type.bitfield.regymm
|| i386_regtab[reg_num].reg_type.bitfield.regzmm))
intel_state.index = i386_regtab + reg_num;
else if (!intel_state.base && !intel_state.in_scale)
intel_state.base = i386_regtab + reg_num;
else if (!intel_state.index)
{
if (intel_state.in_scale
|| i386_regtab[reg_num].reg_type.bitfield.baseindex)
intel_state.index = i386_regtab + reg_num;
else
{
/* Convert base to index and make ESP/RSP the base. */
intel_state.index = intel_state.base;
intel_state.base = i386_regtab + reg_num;
}
}
else
{
/* esp is invalid as index */
intel_state.index = i386_regtab + REGNAM_EAX + ESP_REG_NUM;
}
return 2;
}
 
static int i386_intel_simplify (expressionS *);
 
static INLINE int i386_intel_simplify_symbol(symbolS *sym)
{
int ret = i386_intel_simplify (symbol_get_value_expression (sym));
 
if (ret == 2)
{
S_SET_SEGMENT(sym, absolute_section);
ret = 1;
}
return ret;
}
 
static int i386_intel_simplify (expressionS *e)
{
const reg_entry *the_reg = (this_operand >= 0
? i.op[this_operand].regs : NULL);
const reg_entry *base = intel_state.base;
const reg_entry *state_index = intel_state.index;
int ret;
 
if (!intel_syntax)
return 1;
 
switch (e->X_op)
{
case O_index:
if (e->X_add_symbol)
{
if (!i386_intel_simplify_symbol (e->X_add_symbol)
|| !i386_intel_check(the_reg, intel_state.base,
intel_state.index))
return 0;
}
if (!intel_state.in_offset)
++intel_state.in_bracket;
ret = i386_intel_simplify_symbol (e->X_op_symbol);
if (!intel_state.in_offset)
--intel_state.in_bracket;
if (!ret)
return 0;
if (e->X_add_symbol)
e->X_op = O_add;
else
i386_intel_fold (e, e->X_op_symbol);
break;
 
case O_offset:
intel_state.has_offset = 1;
++intel_state.in_offset;
ret = i386_intel_simplify_symbol (e->X_add_symbol);
--intel_state.in_offset;
if (!ret || !i386_intel_check(the_reg, base, state_index))
return 0;
i386_intel_fold (e, e->X_add_symbol);
return ret;
 
case O_byte_ptr:
case O_word_ptr:
case O_dword_ptr:
case O_fword_ptr:
case O_qword_ptr:
case O_tbyte_ptr:
case O_oword_ptr:
case O_xmmword_ptr:
case O_ymmword_ptr:
case O_zmmword_ptr:
case O_near_ptr:
case O_far_ptr:
if (intel_state.op_modifier == O_absent)
intel_state.op_modifier = e->X_op;
/* FALLTHROUGH */
case O_short:
if (symbol_get_value_expression (e->X_add_symbol)->X_op
== O_register)
{
as_bad (_("invalid use of register"));
return 0;
}
if (!i386_intel_simplify_symbol (e->X_add_symbol))
return 0;
i386_intel_fold (e, e->X_add_symbol);
break;
 
case O_full_ptr:
if (symbol_get_value_expression (e->X_op_symbol)->X_op
== O_register)
{
as_bad (_("invalid use of register"));
return 0;
}
if (!i386_intel_simplify_symbol (e->X_op_symbol)
|| !i386_intel_check(the_reg, intel_state.base,
intel_state.index))
return 0;
if (!intel_state.in_offset)
intel_state.seg = e->X_add_symbol;
i386_intel_fold (e, e->X_op_symbol);
break;
 
case O_multiply:
if (this_operand >= 0 && intel_state.in_bracket)
{
expressionS *scale = NULL;
 
if (intel_state.index)
--scale;
 
if (!intel_state.in_scale++)
intel_state.scale_factor = 1;
 
ret = i386_intel_simplify_symbol (e->X_add_symbol);
if (ret && !scale && intel_state.index)
scale = symbol_get_value_expression (e->X_op_symbol);
 
if (ret)
ret = i386_intel_simplify_symbol (e->X_op_symbol);
if (ret && !scale && intel_state.index)
scale = symbol_get_value_expression (e->X_add_symbol);
 
if (ret && scale && (scale + 1))
{
resolve_expression (scale);
if (scale->X_op != O_constant
|| intel_state.index->reg_type.bitfield.reg16)
scale->X_add_number = 0;
intel_state.scale_factor *= scale->X_add_number;
}
 
--intel_state.in_scale;
if (!ret)
return 0;
 
if (!intel_state.in_scale)
switch (intel_state.scale_factor)
{
case 1:
i.log2_scale_factor = 0;
break;
case 2:
i.log2_scale_factor = 1;
break;
case 4:
i.log2_scale_factor = 2;
break;
case 8:
i.log2_scale_factor = 3;
break;
default:
/* esp is invalid as index */
intel_state.index = i386_regtab + REGNAM_EAX + ESP_REG_NUM;
break;
}
 
break;
}
goto fallthrough;
 
case O_register:
ret = i386_intel_simplify_register (e);
if (ret == 2)
{
gas_assert (e->X_add_number < (unsigned short) -1);
e->X_md = (unsigned short) e->X_add_number + 1;
e->X_op = O_constant;
e->X_add_number = 0;
}
return ret;
 
case O_constant:
if (e->X_md)
return i386_intel_simplify_register (e);
 
/* FALLTHROUGH */
default:
fallthrough:
if (e->X_add_symbol
&& !i386_intel_simplify_symbol (e->X_add_symbol))
return 0;
if (e->X_op == O_add || e->X_op == O_subtract)
{
base = intel_state.base;
state_index = intel_state.index;
}
if (!i386_intel_check (the_reg, base, state_index)
|| (e->X_op_symbol
&& !i386_intel_simplify_symbol (e->X_op_symbol))
|| !i386_intel_check (the_reg,
(e->X_op != O_add
? base : intel_state.base),
(e->X_op != O_add
? state_index : intel_state.index)))
return 0;
break;
}
 
if (this_operand >= 0
&& e->X_op == O_symbol
&& !intel_state.in_offset)
{
segT seg = S_GET_SEGMENT (e->X_add_symbol);
 
if (seg != absolute_section
&& seg != reg_section
&& seg != expr_section)
intel_state.is_mem |= 2 - !intel_state.in_bracket;
}
 
return 1;
}
 
int i386_need_index_operator (void)
{
return intel_syntax < 0;
}
 
static int
i386_intel_operand (char *operand_string, int got_a_float)
{
char *saved_input_line_pointer, *buf;
segT exp_seg;
expressionS exp, *expP;
char suffix = 0;
int ret;
 
/* Handle vector immediates. */
if (RC_SAE_immediate (operand_string))
return 1;
 
/* Initialize state structure. */
intel_state.op_modifier = O_absent;
intel_state.is_mem = 0;
intel_state.is_indirect = 0;
intel_state.has_offset = 0;
intel_state.base = NULL;
intel_state.index = NULL;
intel_state.seg = NULL;
operand_type_set (&intel_state.reloc_types, ~0);
gas_assert (!intel_state.in_offset);
gas_assert (!intel_state.in_bracket);
gas_assert (!intel_state.in_scale);
 
saved_input_line_pointer = input_line_pointer;
input_line_pointer = buf = xstrdup (operand_string);
 
intel_syntax = -1;
memset (&exp, 0, sizeof(exp));
exp_seg = expression (&exp);
ret = i386_intel_simplify (&exp);
intel_syntax = 1;
 
SKIP_WHITESPACE ();
 
/* Handle vector operations. */
if (*input_line_pointer == '{')
{
char *end = check_VecOperations (input_line_pointer, NULL);
if (end)
input_line_pointer = end;
else
ret = 0;
}
 
if (!is_end_of_line[(unsigned char) *input_line_pointer])
{
as_bad (_("junk `%s' after expression"), input_line_pointer);
ret = 0;
}
else if (exp.X_op == O_illegal || exp.X_op == O_absent)
{
as_bad (_("invalid expression"));
ret = 0;
}
else if (!intel_state.has_offset
&& input_line_pointer > buf
&& *(input_line_pointer - 1) == ']')
{
intel_state.is_mem |= 1;
intel_state.is_indirect = 1;
}
 
input_line_pointer = saved_input_line_pointer;
free (buf);
 
gas_assert (!intel_state.in_offset);
gas_assert (!intel_state.in_bracket);
gas_assert (!intel_state.in_scale);
 
if (!ret)
return 0;
 
if (intel_state.op_modifier != O_absent
&& current_templates->start->base_opcode != 0x8d /* lea */)
{
i.types[this_operand].bitfield.unspecified = 0;
 
switch (intel_state.op_modifier)
{
case O_byte_ptr:
i.types[this_operand].bitfield.byte = 1;
suffix = BYTE_MNEM_SUFFIX;
break;
 
case O_word_ptr:
i.types[this_operand].bitfield.word = 1;
if ((current_templates->start->name[0] == 'l'
&& current_templates->start->name[2] == 's'
&& current_templates->start->name[3] == 0)
|| current_templates->start->base_opcode == 0x62 /* bound */)
suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
else if (got_a_float == 2) /* "fi..." */
suffix = SHORT_MNEM_SUFFIX;
else
suffix = WORD_MNEM_SUFFIX;
break;
 
case O_dword_ptr:
i.types[this_operand].bitfield.dword = 1;
if ((current_templates->start->name[0] == 'l'
&& current_templates->start->name[2] == 's'
&& current_templates->start->name[3] == 0)
|| current_templates->start->base_opcode == 0x62 /* bound */)
suffix = WORD_MNEM_SUFFIX;
else if (flag_code == CODE_16BIT
&& (current_templates->start->opcode_modifier.jump
|| current_templates->start->opcode_modifier.jumpdword))
suffix = LONG_DOUBLE_MNEM_SUFFIX;
else if (got_a_float == 1) /* "f..." */
suffix = SHORT_MNEM_SUFFIX;
else
suffix = LONG_MNEM_SUFFIX;
break;
 
case O_fword_ptr:
i.types[this_operand].bitfield.fword = 1;
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 (!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 */
break;
 
case O_qword_ptr:
i.types[this_operand].bitfield.qword = 1;
if (current_templates->start->base_opcode == 0x62 /* bound */
|| got_a_float == 1) /* "f..." */
suffix = LONG_MNEM_SUFFIX;
else
suffix = QWORD_MNEM_SUFFIX;
break;
 
case O_tbyte_ptr:
i.types[this_operand].bitfield.tbyte = 1;
if (got_a_float == 1)
suffix = LONG_DOUBLE_MNEM_SUFFIX;
else
suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
break;
 
case O_oword_ptr:
case O_xmmword_ptr:
i.types[this_operand].bitfield.xmmword = 1;
suffix = XMMWORD_MNEM_SUFFIX;
break;
 
case O_ymmword_ptr:
i.types[this_operand].bitfield.ymmword = 1;
suffix = YMMWORD_MNEM_SUFFIX;
break;
 
case O_zmmword_ptr:
i.types[this_operand].bitfield.zmmword = 1;
suffix = ZMMWORD_MNEM_SUFFIX;
break;
 
case O_far_ptr:
suffix = LONG_DOUBLE_MNEM_SUFFIX;
/* FALLTHROUGH */
case O_near_ptr:
if (!current_templates->start->opcode_modifier.jump
&& !current_templates->start->opcode_modifier.jumpdword)
suffix = got_a_float /* so it will cause an error */
? BYTE_MNEM_SUFFIX
: LONG_DOUBLE_MNEM_SUFFIX;
break;
 
default:
BAD_CASE (intel_state.op_modifier);
break;
}
 
if (!i.suffix)
i.suffix = suffix;
else if (i.suffix != suffix)
{
as_bad (_("conflicting operand size modifiers"));
return 0;
}
}
 
/* Operands for jump/call need special consideration. */
if (current_templates->start->opcode_modifier.jump
|| current_templates->start->opcode_modifier.jumpdword
|| current_templates->start->opcode_modifier.jumpintersegment)
{
if (i.op[this_operand].regs
|| intel_state.base
|| intel_state.index
|| intel_state.is_mem > 1)
i.types[this_operand].bitfield.jumpabsolute = 1;
else
switch (intel_state.op_modifier)
{
case O_near_ptr:
if (intel_state.seg)
i.types[this_operand].bitfield.jumpabsolute = 1;
else
intel_state.is_mem = 1;
break;
case O_far_ptr:
case O_absent:
if (!intel_state.seg)
{
intel_state.is_mem = 1;
if (intel_state.op_modifier == O_absent)
{
if (intel_state.is_indirect == 1)
i.types[this_operand].bitfield.jumpabsolute = 1;
break;
}
as_bad (_("cannot infer the segment part of the operand"));
return 0;
}
else if (S_GET_SEGMENT (intel_state.seg) == reg_section)
i.types[this_operand].bitfield.jumpabsolute = 1;
else
{
i386_operand_type types;
 
if (i.imm_operands >= MAX_IMMEDIATE_OPERANDS)
{
as_bad (_("at most %d immediate operands are allowed"),
MAX_IMMEDIATE_OPERANDS);
return 0;
}
expP = &im_expressions[i.imm_operands++];
memset (expP, 0, sizeof(*expP));
expP->X_op = O_symbol;
expP->X_add_symbol = intel_state.seg;
i.op[this_operand].imms = expP;
 
resolve_expression (expP);
operand_type_set (&types, ~0);
if (!i386_finalize_immediate (S_GET_SEGMENT (intel_state.seg),
expP, types, operand_string))
return 0;
if (i.operands < MAX_OPERANDS)
{
this_operand = i.operands++;
i.types[this_operand].bitfield.unspecified = 1;
}
if (suffix == LONG_DOUBLE_MNEM_SUFFIX)
i.suffix = 0;
intel_state.seg = NULL;
intel_state.is_mem = 0;
}
break;
default:
i.types[this_operand].bitfield.jumpabsolute = 1;
break;
}
if (i.types[this_operand].bitfield.jumpabsolute)
intel_state.is_mem |= 1;
}
else if (intel_state.seg)
intel_state.is_mem |= 1;
 
if (i.op[this_operand].regs)
{
i386_operand_type temp;
 
/* Register operand. */
if (intel_state.base || intel_state.index || intel_state.seg)
{
as_bad (_("invalid operand"));
return 0;
}
 
temp = i.op[this_operand].regs->reg_type;
temp.bitfield.baseindex = 0;
i.types[this_operand] = operand_type_or (i.types[this_operand],
temp);
i.types[this_operand].bitfield.unspecified = 0;
++i.reg_operands;
}
else if (intel_state.base
|| intel_state.index
|| intel_state.seg
|| intel_state.is_mem)
{
/* Memory operand. */
if ((int) i.mem_operands
>= 2 - !current_templates->start->opcode_modifier.isstring)
{
/* Handle
 
call 0x9090,0x90909090
lcall 0x9090,0x90909090
jmp 0x9090,0x90909090
ljmp 0x9090,0x90909090
*/
 
if ((current_templates->start->opcode_modifier.jumpintersegment
|| current_templates->start->opcode_modifier.jumpdword
|| current_templates->start->opcode_modifier.jump)
&& this_operand == 1
&& intel_state.seg == NULL
&& i.mem_operands == 1
&& i.disp_operands == 1
&& intel_state.op_modifier == O_absent)
{
/* Try to process the first operand as immediate, */
this_operand = 0;
if (i386_finalize_immediate (exp_seg, i.op[0].imms,
intel_state.reloc_types,
NULL))
{
this_operand = 1;
expP = &im_expressions[0];
i.op[this_operand].imms = expP;
*expP = exp;
 
/* Try to process the second operand as immediate, */
if (i386_finalize_immediate (exp_seg, expP,
intel_state.reloc_types,
NULL))
{
i.mem_operands = 0;
i.disp_operands = 0;
i.imm_operands = 2;
i.types[0].bitfield.mem = 0;
i.types[0].bitfield.disp16 = 0;
i.types[0].bitfield.disp32 = 0;
i.types[0].bitfield.disp32s = 0;
return 1;
}
}
}
 
as_bad (_("too many memory references for `%s'"),
current_templates->start->name);
return 0;
}
 
expP = &disp_expressions[i.disp_operands];
memcpy (expP, &exp, sizeof(exp));
resolve_expression (expP);
 
if (expP->X_op != O_constant
|| expP->X_add_number
|| (!intel_state.base
&& !intel_state.index))
{
i.op[this_operand].disps = expP;
i.disp_operands++;
 
if (flag_code == CODE_64BIT)
{
i.types[this_operand].bitfield.disp32 = 1;
if (!i.prefix[ADDR_PREFIX])
{
i.types[this_operand].bitfield.disp64 = 1;
i.types[this_operand].bitfield.disp32s = 1;
}
}
else if (!i.prefix[ADDR_PREFIX] ^ (flag_code == CODE_16BIT))
i.types[this_operand].bitfield.disp32 = 1;
else
i.types[this_operand].bitfield.disp16 = 1;
 
#if defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)
/*
* exp_seg is used only for verification in
* i386_finalize_displacement, and we can end up seeing reg_section
* here - but we know we removed all registers from the expression
* (or error-ed on any remaining ones) in i386_intel_simplify. I
* consider the check in i386_finalize_displacement bogus anyway, in
* particular because it doesn't allow for expr_section, so I'd
* rather see that check (and the similar one in
* i386_finalize_immediate) use SEG_NORMAL(), but not being an a.out
* expert I can't really say whether that would have other bad side
* effects.
*/
if (OUTPUT_FLAVOR == bfd_target_aout_flavour
&& exp_seg == reg_section)
exp_seg = expP->X_op != O_constant ? undefined_section
: absolute_section;
#endif
 
if (!i386_finalize_displacement (exp_seg, expP,
intel_state.reloc_types,
operand_string))
return 0;
}
 
if (intel_state.base || intel_state.index)
i.types[this_operand].bitfield.baseindex = 1;
 
if (intel_state.seg)
{
for (;;)
{
expP = symbol_get_value_expression (intel_state.seg);
if (expP->X_op != O_full_ptr)
break;
intel_state.seg = expP->X_add_symbol;
}
if (expP->X_op != O_register)
{
as_bad (_("segment register name expected"));
return 0;
}
if (!i386_regtab[expP->X_add_number].reg_type.bitfield.sreg2
&& !i386_regtab[expP->X_add_number].reg_type.bitfield.sreg3)
{
as_bad (_("invalid use of register"));
return 0;
}
switch (i386_regtab[expP->X_add_number].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;
case RegFlat: i.seg[i.mem_operands] = NULL; break;
}
}
 
/* 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 (intel_state.base
&& intel_state.index
&& intel_state.base->reg_type.bitfield.reg16
&& intel_state.index->reg_type.bitfield.reg16
&& intel_state.base->reg_num >= 6
&& intel_state.index->reg_num < 6)
{
i.base_reg = intel_state.index;
i.index_reg = intel_state.base;
}
else
{
i.base_reg = intel_state.base;
i.index_reg = intel_state.index;
}
 
if (!i386_index_check (operand_string))
return 0;
 
i.types[this_operand].bitfield.mem = 1;
++i.mem_operands;
}
else
{
/* Immediate. */
if (i.imm_operands >= MAX_IMMEDIATE_OPERANDS)
{
as_bad (_("at most %d immediate operands are allowed"),
MAX_IMMEDIATE_OPERANDS);
return 0;
}
 
expP = &im_expressions[i.imm_operands++];
i.op[this_operand].imms = expP;
*expP = exp;
 
return i386_finalize_immediate (exp_seg, expP, intel_state.reloc_types,
operand_string);
}
 
return 1;
}
/contrib/toolchain/binutils/gas/config/tc-i386.c
0,0 → 1,10565
/* tc-i386.c -- Assemble code for the Intel 80386
Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
2012
Free Software Foundation, Inc.
 
This file is part of GAS, the GNU Assembler.
 
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
 
GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
/* Intel 80386 machine specific gas.
Written by Eliot Dresselhaus (eliot@mgm.mit.edu).
x86_64 support by Jan Hubicka (jh@suse.cz)
VIA PadLock support by Michal Ludvig (mludvig@suse.cz)
Bugs & suggestions are completely welcome. This is free software.
Please help us make it better. */
 
#include "as.h"
#include "safe-ctype.h"
#include "subsegs.h"
#include "dwarf2dbg.h"
#include "dw2gencfi.h"
#include "elf/x86-64.h"
#include "opcodes/i386-init.h"
 
#ifndef REGISTER_WARNINGS
#define REGISTER_WARNINGS 1
#endif
 
#ifndef INFER_ADDR_PREFIX
#define INFER_ADDR_PREFIX 1
#endif
 
#ifndef DEFAULT_ARCH
#define DEFAULT_ARCH "i386"
#endif
 
#ifndef INLINE
#if __GNUC__ >= 2
#define INLINE __inline__
#else
#define INLINE
#endif
#endif
 
/* Prefixes will be emitted in the order defined below.
WAIT_PREFIX must be the first prefix since FWAIT is really is an
instruction, and so must come before any prefixes.
The preferred prefix order is SEG_PREFIX, ADDR_PREFIX, DATA_PREFIX,
REP_PREFIX/HLE_PREFIX, LOCK_PREFIX. */
#define WAIT_PREFIX 0
#define SEG_PREFIX 1
#define ADDR_PREFIX 2
#define DATA_PREFIX 3
#define REP_PREFIX 4
#define HLE_PREFIX REP_PREFIX
#define BND_PREFIX REP_PREFIX
#define LOCK_PREFIX 5
#define REX_PREFIX 6 /* must come last. */
#define MAX_PREFIXES 7 /* max prefixes per opcode */
 
/* we define the syntax here (modulo base,index,scale syntax) */
#define REGISTER_PREFIX '%'
#define IMMEDIATE_PREFIX '$'
#define ABSOLUTE_PREFIX '*'
 
/* these are the instruction mnemonic suffixes in AT&T syntax or
memory operand size in Intel syntax. */
#define WORD_MNEM_SUFFIX 'w'
#define BYTE_MNEM_SUFFIX 'b'
#define SHORT_MNEM_SUFFIX 's'
#define LONG_MNEM_SUFFIX 'l'
#define QWORD_MNEM_SUFFIX 'q'
#define XMMWORD_MNEM_SUFFIX 'x'
#define YMMWORD_MNEM_SUFFIX 'y'
#define ZMMWORD_MNEM_SUFFIX 'z'
/* Intel Syntax. Use a non-ascii letter since since it never appears
in instructions. */
#define LONG_DOUBLE_MNEM_SUFFIX '\1'
 
#define END_OF_INSN '\0'
 
/*
'templates' is for grouping together 'template' structures for opcodes
of the same name. This is only used for storing the insns in the grand
ole hash table of insns.
The templates themselves start at START and range up to (but not including)
END.
*/
typedef struct
{
const insn_template *start;
const insn_template *end;
}
templates;
 
/* 386 operand encoding bytes: see 386 book for details of this. */
typedef struct
{
unsigned int regmem; /* codes register or memory operand */
unsigned int reg; /* codes register operand (or extended opcode) */
unsigned int mode; /* how to interpret regmem & reg */
}
modrm_byte;
 
/* x86-64 extension prefix. */
typedef int rex_byte;
 
/* 386 opcode byte to code indirect addressing. */
typedef struct
{
unsigned base;
unsigned index;
unsigned scale;
}
sib_byte;
 
/* x86 arch names, types and features */
typedef struct
{
const char *name; /* arch name */
unsigned int len; /* arch string length */
enum processor_type type; /* arch type */
i386_cpu_flags flags; /* cpu feature flags */
unsigned int skip; /* show_arch should skip this. */
unsigned int negated; /* turn off indicated flags. */
}
arch_entry;
 
static void update_code_flag (int, int);
static void set_code_flag (int);
static void set_16bit_gcc_code_flag (int);
static void set_intel_syntax (int);
static void set_intel_mnemonic (int);
static void set_allow_index_reg (int);
static void set_check (int);
static void set_cpu_arch (int);
#ifdef TE_PE
static void pe_directive_secrel (int);
#endif
static void signed_cons (int);
static char *output_invalid (int c);
static int i386_finalize_immediate (segT, expressionS *, i386_operand_type,
const char *);
static int i386_finalize_displacement (segT, expressionS *, i386_operand_type,
const char *);
static int i386_att_operand (char *);
static int i386_intel_operand (char *, int);
static int i386_intel_simplify (expressionS *);
static int i386_intel_parse_name (const char *, expressionS *);
static const reg_entry *parse_register (char *, char **);
static char *parse_insn (char *, char *);
static char *parse_operands (char *, const char *);
static void swap_operands (void);
static void swap_2_operands (int, int);
static void optimize_imm (void);
static void optimize_disp (void);
static const insn_template *match_template (void);
static int check_string (void);
static int process_suffix (void);
static int check_byte_reg (void);
static int check_long_reg (void);
static int check_qword_reg (void);
static int check_word_reg (void);
static int finalize_imm (void);
static int process_operands (void);
static const seg_entry *build_modrm_byte (void);
static void output_insn (void);
static void output_imm (fragS *, offsetT);
static void output_disp (fragS *, offsetT);
#ifndef I386COFF
static void s_bss (int);
#endif
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
static void handle_large_common (int small ATTRIBUTE_UNUSED);
#endif
 
static const char *default_arch = DEFAULT_ARCH;
 
/* This struct describes rounding control and SAE in the instruction. */
struct RC_Operation
{
enum rc_type
{
rne = 0,
rd,
ru,
rz,
saeonly
} type;
int operand;
};
 
static struct RC_Operation rc_op;
 
/* The struct describes masking, applied to OPERAND in the instruction.
MASK is a pointer to the corresponding mask register. ZEROING tells
whether merging or zeroing mask is used. */
struct Mask_Operation
{
const reg_entry *mask;
unsigned int zeroing;
/* The operand where this operation is associated. */
int operand;
};
 
static struct Mask_Operation mask_op;
 
/* The struct describes broadcasting, applied to OPERAND. FACTOR is
broadcast factor. */
struct Broadcast_Operation
{
/* Type of broadcast: no broadcast, {1to8}, or {1to16}. */
int type;
 
/* Index of broadcasted operand. */
int operand;
};
 
static struct Broadcast_Operation broadcast_op;
 
/* VEX prefix. */
typedef struct
{
/* VEX prefix is either 2 byte or 3 byte. EVEX is 4 byte. */
unsigned char bytes[4];
unsigned int length;
/* Destination or source register specifier. */
const reg_entry *register_specifier;
} vex_prefix;
 
/* 'md_assemble ()' gathers together information and puts it into a
i386_insn. */
 
union i386_op
{
expressionS *disps;
expressionS *imms;
const reg_entry *regs;
};
 
enum i386_error
{
operand_size_mismatch,
operand_type_mismatch,
register_type_mismatch,
number_of_operands_mismatch,
invalid_instruction_suffix,
bad_imm4,
old_gcc_only,
unsupported_with_intel_mnemonic,
unsupported_syntax,
unsupported,
invalid_vsib_address,
invalid_vector_register_set,
unsupported_vector_index_register,
unsupported_broadcast,
broadcast_not_on_src_operand,
broadcast_needed,
unsupported_masking,
mask_not_on_destination,
no_default_mask,
unsupported_rc_sae,
rc_sae_operand_not_last_imm,
invalid_register_operand,
try_vector_disp8
};
 
struct _i386_insn
{
/* TM holds the template for the insn were currently assembling. */
insn_template tm;
 
/* SUFFIX holds the instruction size suffix for byte, word, dword
or qword, if given. */
char suffix;
 
/* OPERANDS gives the number of given operands. */
unsigned int operands;
 
/* REG_OPERANDS, DISP_OPERANDS, MEM_OPERANDS, IMM_OPERANDS give the number
of given register, displacement, memory operands and immediate
operands. */
unsigned int reg_operands, disp_operands, mem_operands, imm_operands;
 
/* TYPES [i] is the type (see above #defines) which tells us how to
use OP[i] for the corresponding operand. */
i386_operand_type types[MAX_OPERANDS];
 
/* Displacement expression, immediate expression, or register for each
operand. */
union i386_op op[MAX_OPERANDS];
 
/* Flags for operands. */
unsigned int flags[MAX_OPERANDS];
#define Operand_PCrel 1
 
/* Relocation type for operand */
enum bfd_reloc_code_real reloc[MAX_OPERANDS];
 
/* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode
the base index byte below. */
const reg_entry *base_reg;
const reg_entry *index_reg;
unsigned int log2_scale_factor;
 
/* SEG gives the seg_entries of this insn. They are zero unless
explicit segment overrides are given. */
const seg_entry *seg[2];
 
/* PREFIX holds all the given prefix opcodes (usually null).
PREFIXES is the number of prefix opcodes. */
unsigned int prefixes;
unsigned char prefix[MAX_PREFIXES];
 
/* RM and SIB are the modrm byte and the sib byte where the
addressing modes of this insn are encoded. */
modrm_byte rm;
rex_byte rex;
rex_byte vrex;
sib_byte sib;
vex_prefix vex;
 
/* Masking attributes. */
struct Mask_Operation *mask;
 
/* Rounding control and SAE attributes. */
struct RC_Operation *rounding;
 
/* Broadcasting attributes. */
struct Broadcast_Operation *broadcast;
 
/* Compressed disp8*N attribute. */
unsigned int memshift;
 
/* Swap operand in encoding. */
unsigned int swap_operand;
 
/* Prefer 8bit or 32bit displacement in encoding. */
enum
{
disp_encoding_default = 0,
disp_encoding_8bit,
disp_encoding_32bit
} disp_encoding;
 
/* REP prefix. */
const char *rep_prefix;
 
/* HLE prefix. */
const char *hle_prefix;
 
/* Have BND prefix. */
const char *bnd_prefix;
 
/* Need VREX to support upper 16 registers. */
int need_vrex;
 
/* Error message. */
enum i386_error error;
};
 
typedef struct _i386_insn i386_insn;
 
/* Link RC type with corresponding string, that'll be looked for in
asm. */
struct RC_name
{
enum rc_type type;
const char *name;
unsigned int len;
};
 
static const struct RC_name RC_NamesTable[] =
{
{ rne, STRING_COMMA_LEN ("rn-sae") },
{ rd, STRING_COMMA_LEN ("rd-sae") },
{ ru, STRING_COMMA_LEN ("ru-sae") },
{ rz, STRING_COMMA_LEN ("rz-sae") },
{ saeonly, STRING_COMMA_LEN ("sae") },
};
 
/* List of chars besides those in app.c:symbol_chars that can start an
operand. Used to prevent the scrubber eating vital white-space. */
const char extra_symbol_chars[] = "*%-([{"
#ifdef LEX_AT
"@"
#endif
#ifdef LEX_QM
"?"
#endif
;
 
#if (defined (TE_I386AIX) \
|| ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \
&& !defined (TE_GNU) \
&& !defined (TE_LINUX) \
&& !defined (TE_NACL) \
&& !defined (TE_NETWARE) \
&& !defined (TE_FreeBSD) \
&& !defined (TE_DragonFly) \
&& !defined (TE_NetBSD)))
/* This array holds the chars that always start a comment. If the
pre-processor is disabled, these aren't very useful. The option
--divide will remove '/' from this list. */
const char *i386_comment_chars = "#/";
#define SVR4_COMMENT_CHARS 1
#define PREFIX_SEPARATOR '\\'
 
#else
const char *i386_comment_chars = "#";
#define PREFIX_SEPARATOR '/'
#endif
 
/* This array holds the chars that only start a comment at the beginning of
a line. If the line seems to have the form '# 123 filename'
.line and .file directives will appear in the pre-processed output.
Note that input_file.c hand checks for '#' at the beginning of the
first line of the input file. This is because the compiler outputs
#NO_APP at the beginning of its output.
Also note that comments started like this one will always work if
'/' isn't otherwise defined. */
const char line_comment_chars[] = "#/";
 
const char line_separator_chars[] = ";";
 
/* Chars that can be used to separate mant from exp in floating point
nums. */
const char EXP_CHARS[] = "eE";
 
/* Chars that mean this number is a floating point constant
As in 0f12.456
or 0d1.2345e12. */
const char FLT_CHARS[] = "fFdDxX";
 
/* Tables for lexical analysis. */
static char mnemonic_chars[256];
static char register_chars[256];
static char operand_chars[256];
static char identifier_chars[256];
static char digit_chars[256];
 
/* Lexical macros. */
#define is_mnemonic_char(x) (mnemonic_chars[(unsigned char) x])
#define is_operand_char(x) (operand_chars[(unsigned char) x])
#define is_register_char(x) (register_chars[(unsigned char) x])
#define is_space_char(x) ((x) == ' ')
#define is_identifier_char(x) (identifier_chars[(unsigned char) x])
#define is_digit_char(x) (digit_chars[(unsigned char) x])
 
/* All non-digit non-letter characters that may occur in an operand. */
static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:[@]";
 
/* md_assemble() always leaves the strings it's passed unaltered. To
effect this we maintain a stack of saved characters that we've smashed
with '\0's (indicating end of strings for various sub-fields of the
assembler instruction). */
static char save_stack[32];
static char *save_stack_p;
#define END_STRING_AND_SAVE(s) \
do { *save_stack_p++ = *(s); *(s) = '\0'; } while (0)
#define RESTORE_END_STRING(s) \
do { *(s) = *--save_stack_p; } while (0)
 
/* The instruction we're assembling. */
static i386_insn i;
 
/* Possible templates for current insn. */
static const templates *current_templates;
 
/* Per instruction expressionS buffers: max displacements & immediates. */
static expressionS disp_expressions[MAX_MEMORY_OPERANDS];
static expressionS im_expressions[MAX_IMMEDIATE_OPERANDS];
 
/* Current operand we are working on. */
static int this_operand = -1;
 
/* We support four different modes. FLAG_CODE variable is used to distinguish
these. */
 
enum flag_code {
CODE_32BIT,
CODE_16BIT,
CODE_64BIT };
 
static enum flag_code flag_code;
static unsigned int object_64bit;
static unsigned int disallow_64bit_reloc;
static int use_rela_relocations = 0;
 
#if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \
|| defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \
|| defined (TE_PE) || defined (TE_PEP) || defined (OBJ_MACH_O))
 
/* The ELF ABI to use. */
enum x86_elf_abi
{
I386_ABI,
X86_64_ABI,
X86_64_X32_ABI
};
 
static enum x86_elf_abi x86_elf_abi = I386_ABI;
#endif
 
/* 1 for intel syntax,
0 if att syntax. */
static int intel_syntax = 0;
 
/* 1 for intel mnemonic,
0 if att mnemonic. */
static int intel_mnemonic = !SYSV386_COMPAT;
 
/* 1 if support old (<= 2.8.1) versions of gcc. */
static int old_gcc = OLDGCC_COMPAT;
 
/* 1 if pseudo registers are permitted. */
static int allow_pseudo_reg = 0;
 
/* 1 if register prefix % not required. */
static int allow_naked_reg = 0;
 
/* 1 if the assembler should add BND prefix for all control-tranferring
instructions supporting it, even if this prefix wasn't specified
explicitly. */
static int add_bnd_prefix = 0;
 
/* 1 if pseudo index register, eiz/riz, is allowed . */
static int allow_index_reg = 0;
 
static enum check_kind
{
check_none = 0,
check_warning,
check_error
}
sse_check, operand_check = check_warning;
 
/* Register prefix used for error message. */
static const char *register_prefix = "%";
 
/* Used in 16 bit gcc mode to add an l suffix to call, ret, enter,
leave, push, and pop instructions so that gcc has the same stack
frame as in 32 bit mode. */
static char stackop_size = '\0';
 
/* Non-zero to optimize code alignment. */
int optimize_align_code = 1;
 
/* Non-zero to quieten some warnings. */
static int quiet_warnings = 0;
 
/* CPU name. */
static const char *cpu_arch_name = NULL;
static char *cpu_sub_arch_name = NULL;
 
/* CPU feature flags. */
static i386_cpu_flags cpu_arch_flags = CPU_UNKNOWN_FLAGS;
 
/* If we have selected a cpu we are generating instructions for. */
static int cpu_arch_tune_set = 0;
 
/* Cpu we are generating instructions for. */
enum processor_type cpu_arch_tune = PROCESSOR_UNKNOWN;
 
/* CPU feature flags of cpu we are generating instructions for. */
static i386_cpu_flags cpu_arch_tune_flags;
 
/* CPU instruction set architecture used. */
enum processor_type cpu_arch_isa = PROCESSOR_UNKNOWN;
 
/* CPU feature flags of instruction set architecture used. */
i386_cpu_flags cpu_arch_isa_flags;
 
/* If set, conditional jumps are not automatically promoted to handle
larger than a byte offset. */
static unsigned int no_cond_jump_promotion = 0;
 
/* Encode SSE instructions with VEX prefix. */
static unsigned int sse2avx;
 
/* Encode scalar AVX instructions with specific vector length. */
static enum
{
vex128 = 0,
vex256
} avxscalar;
 
/* Encode scalar EVEX LIG instructions with specific vector length. */
static enum
{
evexl128 = 0,
evexl256,
evexl512
} evexlig;
 
/* Encode EVEX WIG instructions with specific evex.w. */
static enum
{
evexw0 = 0,
evexw1
} evexwig;
 
/* Pre-defined "_GLOBAL_OFFSET_TABLE_". */
static symbolS *GOT_symbol;
 
/* The dwarf2 return column, adjusted for 32 or 64 bit. */
unsigned int x86_dwarf2_return_column;
 
/* The dwarf2 data alignment, adjusted for 32 or 64 bit. */
int x86_cie_data_alignment;
 
/* Interface to relax_segment.
There are 3 major relax states for 386 jump insns because the
different types of jumps add different sizes to frags when we're
figuring out what sort of jump to choose to reach a given label. */
 
/* Types. */
#define UNCOND_JUMP 0
#define COND_JUMP 1
#define COND_JUMP86 2
 
/* Sizes. */
#define CODE16 1
#define SMALL 0
#define SMALL16 (SMALL | CODE16)
#define BIG 2
#define BIG16 (BIG | CODE16)
 
#ifndef INLINE
#ifdef __GNUC__
#define INLINE __inline__
#else
#define INLINE
#endif
#endif
 
#define ENCODE_RELAX_STATE(type, size) \
((relax_substateT) (((type) << 2) | (size)))
#define TYPE_FROM_RELAX_STATE(s) \
((s) >> 2)
#define DISP_SIZE_FROM_RELAX_STATE(s) \
((((s) & 3) == BIG ? 4 : (((s) & 3) == BIG16 ? 2 : 1)))
 
/* This table is used by relax_frag to promote short jumps to long
ones where necessary. SMALL (short) jumps may be promoted to BIG
(32 bit long) ones, and SMALL16 jumps to BIG16 (16 bit long). We
don't allow a short jump in a 32 bit code segment to be promoted to
a 16 bit offset jump because it's slower (requires data size
prefix), and doesn't work, unless the destination is in the bottom
64k of the code segment (The top 16 bits of eip are zeroed). */
 
const relax_typeS md_relax_table[] =
{
/* The fields are:
1) most positive reach of this state,
2) most negative reach of this state,
3) how many bytes this mode will have in the variable part of the frag
4) which index into the table to try if we can't fit into this one. */
 
/* UNCOND_JUMP states. */
{127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG)},
{127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16)},
/* dword jmp adds 4 bytes to frag:
0 extra opcode bytes, 4 displacement bytes. */
{0, 0, 4, 0},
/* word jmp adds 2 byte2 to frag:
0 extra opcode bytes, 2 displacement bytes. */
{0, 0, 2, 0},
 
/* COND_JUMP states. */
{127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP, BIG)},
{127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP, BIG16)},
/* dword conditionals adds 5 bytes to frag:
1 extra opcode byte, 4 displacement bytes. */
{0, 0, 5, 0},
/* word conditionals add 3 bytes to frag:
1 extra opcode byte, 2 displacement bytes. */
{0, 0, 3, 0},
 
/* COND_JUMP86 states. */
{127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP86, BIG)},
{127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP86, BIG16)},
/* dword conditionals adds 5 bytes to frag:
1 extra opcode byte, 4 displacement bytes. */
{0, 0, 5, 0},
/* word conditionals add 4 bytes to frag:
1 displacement byte and a 3 byte long branch insn. */
{0, 0, 4, 0}
};
 
static const arch_entry cpu_arch[] =
{
/* Do not replace the first two entries - i386_target_format()
relies on them being there in this order. */
{ STRING_COMMA_LEN ("generic32"), PROCESSOR_GENERIC32,
CPU_GENERIC32_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("generic64"), PROCESSOR_GENERIC64,
CPU_GENERIC64_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("i8086"), PROCESSOR_UNKNOWN,
CPU_NONE_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("i186"), PROCESSOR_UNKNOWN,
CPU_I186_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("i286"), PROCESSOR_UNKNOWN,
CPU_I286_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("i386"), PROCESSOR_I386,
CPU_I386_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("i486"), PROCESSOR_I486,
CPU_I486_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("i586"), PROCESSOR_PENTIUM,
CPU_I586_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("i686"), PROCESSOR_PENTIUMPRO,
CPU_I686_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("pentium"), PROCESSOR_PENTIUM,
CPU_I586_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("pentiumpro"), PROCESSOR_PENTIUMPRO,
CPU_PENTIUMPRO_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("pentiumii"), PROCESSOR_PENTIUMPRO,
CPU_P2_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("pentiumiii"),PROCESSOR_PENTIUMPRO,
CPU_P3_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("pentium4"), PROCESSOR_PENTIUM4,
CPU_P4_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("prescott"), PROCESSOR_NOCONA,
CPU_CORE_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("nocona"), PROCESSOR_NOCONA,
CPU_NOCONA_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("yonah"), PROCESSOR_CORE,
CPU_CORE_FLAGS, 1, 0 },
{ STRING_COMMA_LEN ("core"), PROCESSOR_CORE,
CPU_CORE_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("merom"), PROCESSOR_CORE2,
CPU_CORE2_FLAGS, 1, 0 },
{ STRING_COMMA_LEN ("core2"), PROCESSOR_CORE2,
CPU_CORE2_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("corei7"), PROCESSOR_COREI7,
CPU_COREI7_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("l1om"), PROCESSOR_L1OM,
CPU_L1OM_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("k1om"), PROCESSOR_K1OM,
CPU_K1OM_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("k6"), PROCESSOR_K6,
CPU_K6_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("k6_2"), PROCESSOR_K6,
CPU_K6_2_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("athlon"), PROCESSOR_ATHLON,
CPU_ATHLON_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("sledgehammer"), PROCESSOR_K8,
CPU_K8_FLAGS, 1, 0 },
{ STRING_COMMA_LEN ("opteron"), PROCESSOR_K8,
CPU_K8_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("k8"), PROCESSOR_K8,
CPU_K8_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("amdfam10"), PROCESSOR_AMDFAM10,
CPU_AMDFAM10_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("bdver1"), PROCESSOR_BD,
CPU_BDVER1_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("bdver2"), PROCESSOR_BD,
CPU_BDVER2_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("bdver3"), PROCESSOR_BD,
CPU_BDVER3_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("btver1"), PROCESSOR_BT,
CPU_BTVER1_FLAGS, 0, 0 },
{ STRING_COMMA_LEN ("btver2"), PROCESSOR_BT,
CPU_BTVER2_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".8087"), PROCESSOR_UNKNOWN,
CPU_8087_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".287"), PROCESSOR_UNKNOWN,
CPU_287_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".387"), PROCESSOR_UNKNOWN,
CPU_387_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".no87"), PROCESSOR_UNKNOWN,
CPU_ANY87_FLAGS, 0, 1 },
{ STRING_COMMA_LEN (".mmx"), PROCESSOR_UNKNOWN,
CPU_MMX_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".nommx"), PROCESSOR_UNKNOWN,
CPU_3DNOWA_FLAGS, 0, 1 },
{ STRING_COMMA_LEN (".sse"), PROCESSOR_UNKNOWN,
CPU_SSE_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".sse2"), PROCESSOR_UNKNOWN,
CPU_SSE2_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".sse3"), PROCESSOR_UNKNOWN,
CPU_SSE3_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".ssse3"), PROCESSOR_UNKNOWN,
CPU_SSSE3_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".sse4.1"), PROCESSOR_UNKNOWN,
CPU_SSE4_1_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".sse4.2"), PROCESSOR_UNKNOWN,
CPU_SSE4_2_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".sse4"), PROCESSOR_UNKNOWN,
CPU_SSE4_2_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".nosse"), PROCESSOR_UNKNOWN,
CPU_ANY_SSE_FLAGS, 0, 1 },
{ STRING_COMMA_LEN (".avx"), PROCESSOR_UNKNOWN,
CPU_AVX_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".avx2"), PROCESSOR_UNKNOWN,
CPU_AVX2_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".avx512f"), PROCESSOR_UNKNOWN,
CPU_AVX512F_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".avx512cd"), PROCESSOR_UNKNOWN,
CPU_AVX512CD_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".avx512er"), PROCESSOR_UNKNOWN,
CPU_AVX512ER_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".avx512pf"), PROCESSOR_UNKNOWN,
CPU_AVX512PF_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".noavx"), PROCESSOR_UNKNOWN,
CPU_ANY_AVX_FLAGS, 0, 1 },
{ STRING_COMMA_LEN (".vmx"), PROCESSOR_UNKNOWN,
CPU_VMX_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".vmfunc"), PROCESSOR_UNKNOWN,
CPU_VMFUNC_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".smx"), PROCESSOR_UNKNOWN,
CPU_SMX_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".xsave"), PROCESSOR_UNKNOWN,
CPU_XSAVE_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".xsaveopt"), PROCESSOR_UNKNOWN,
CPU_XSAVEOPT_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".aes"), PROCESSOR_UNKNOWN,
CPU_AES_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".pclmul"), PROCESSOR_UNKNOWN,
CPU_PCLMUL_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".clmul"), PROCESSOR_UNKNOWN,
CPU_PCLMUL_FLAGS, 1, 0 },
{ STRING_COMMA_LEN (".fsgsbase"), PROCESSOR_UNKNOWN,
CPU_FSGSBASE_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".rdrnd"), PROCESSOR_UNKNOWN,
CPU_RDRND_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".f16c"), PROCESSOR_UNKNOWN,
CPU_F16C_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".bmi2"), PROCESSOR_UNKNOWN,
CPU_BMI2_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".fma"), PROCESSOR_UNKNOWN,
CPU_FMA_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".fma4"), PROCESSOR_UNKNOWN,
CPU_FMA4_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".xop"), PROCESSOR_UNKNOWN,
CPU_XOP_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".lwp"), PROCESSOR_UNKNOWN,
CPU_LWP_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".movbe"), PROCESSOR_UNKNOWN,
CPU_MOVBE_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".cx16"), PROCESSOR_UNKNOWN,
CPU_CX16_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".ept"), PROCESSOR_UNKNOWN,
CPU_EPT_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".lzcnt"), PROCESSOR_UNKNOWN,
CPU_LZCNT_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".hle"), PROCESSOR_UNKNOWN,
CPU_HLE_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".rtm"), PROCESSOR_UNKNOWN,
CPU_RTM_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".invpcid"), PROCESSOR_UNKNOWN,
CPU_INVPCID_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".clflush"), PROCESSOR_UNKNOWN,
CPU_CLFLUSH_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".nop"), PROCESSOR_UNKNOWN,
CPU_NOP_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".syscall"), PROCESSOR_UNKNOWN,
CPU_SYSCALL_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".rdtscp"), PROCESSOR_UNKNOWN,
CPU_RDTSCP_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".3dnow"), PROCESSOR_UNKNOWN,
CPU_3DNOW_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".3dnowa"), PROCESSOR_UNKNOWN,
CPU_3DNOWA_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".padlock"), PROCESSOR_UNKNOWN,
CPU_PADLOCK_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".pacifica"), PROCESSOR_UNKNOWN,
CPU_SVME_FLAGS, 1, 0 },
{ STRING_COMMA_LEN (".svme"), PROCESSOR_UNKNOWN,
CPU_SVME_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".sse4a"), PROCESSOR_UNKNOWN,
CPU_SSE4A_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".abm"), PROCESSOR_UNKNOWN,
CPU_ABM_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".bmi"), PROCESSOR_UNKNOWN,
CPU_BMI_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".tbm"), PROCESSOR_UNKNOWN,
CPU_TBM_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".adx"), PROCESSOR_UNKNOWN,
CPU_ADX_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".rdseed"), PROCESSOR_UNKNOWN,
CPU_RDSEED_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".prfchw"), PROCESSOR_UNKNOWN,
CPU_PRFCHW_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".smap"), PROCESSOR_UNKNOWN,
CPU_SMAP_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".mpx"), PROCESSOR_UNKNOWN,
CPU_MPX_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".sha"), PROCESSOR_UNKNOWN,
CPU_SHA_FLAGS, 0, 0 },
};
 
#ifdef I386COFF
/* Like s_lcomm_internal in gas/read.c but the alignment string
is allowed to be optional. */
 
static symbolS *
pe_lcomm_internal (int needs_align, symbolS *symbolP, addressT size)
{
addressT align = 0;
 
SKIP_WHITESPACE ();
 
if (needs_align
&& *input_line_pointer == ',')
{
align = parse_align (needs_align - 1);
 
if (align == (addressT) -1)
return NULL;
}
else
{
if (size >= 8)
align = 3;
else if (size >= 4)
align = 2;
else if (size >= 2)
align = 1;
else
align = 0;
}
 
bss_alloc (symbolP, size, align);
return symbolP;
}
 
static void
pe_lcomm (int needs_align)
{
s_comm_internal (needs_align * 2, pe_lcomm_internal);
}
#endif
 
const pseudo_typeS md_pseudo_table[] =
{
#if !defined(OBJ_AOUT) && !defined(USE_ALIGN_PTWO)
{"align", s_align_bytes, 0},
#else
{"align", s_align_ptwo, 0},
#endif
{"arch", set_cpu_arch, 0},
#ifndef I386COFF
{"bss", s_bss, 0},
#else
{"lcomm", pe_lcomm, 1},
#endif
{"ffloat", float_cons, 'f'},
{"dfloat", float_cons, 'd'},
{"tfloat", float_cons, 'x'},
{"value", cons, 2},
{"slong", signed_cons, 4},
{"noopt", s_ignore, 0},
{"optim", s_ignore, 0},
{"code16gcc", set_16bit_gcc_code_flag, CODE_16BIT},
{"code16", set_code_flag, CODE_16BIT},
{"code32", set_code_flag, CODE_32BIT},
{"code64", set_code_flag, CODE_64BIT},
{"intel_syntax", set_intel_syntax, 1},
{"att_syntax", set_intel_syntax, 0},
{"intel_mnemonic", set_intel_mnemonic, 1},
{"att_mnemonic", set_intel_mnemonic, 0},
{"allow_index_reg", set_allow_index_reg, 1},
{"disallow_index_reg", set_allow_index_reg, 0},
{"sse_check", set_check, 0},
{"operand_check", set_check, 1},
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
{"largecomm", handle_large_common, 0},
#else
{"file", (void (*) (int)) dwarf2_directive_file, 0},
{"loc", dwarf2_directive_loc, 0},
{"loc_mark_labels", dwarf2_directive_loc_mark_labels, 0},
#endif
#ifdef TE_PE
{"secrel32", pe_directive_secrel, 0},
#endif
{0, 0, 0}
};
 
/* For interface with expression (). */
extern char *input_line_pointer;
 
/* Hash table for instruction mnemonic lookup. */
static struct hash_control *op_hash;
 
/* Hash table for register lookup. */
static struct hash_control *reg_hash;
void
i386_align_code (fragS *fragP, int count)
{
/* Various efficient no-op patterns for aligning code labels.
Note: Don't try to assemble the instructions in the comments.
0L and 0w are not legal. */
static const char f32_1[] =
{0x90}; /* nop */
static const char f32_2[] =
{0x66,0x90}; /* xchg %ax,%ax */
static const char f32_3[] =
{0x8d,0x76,0x00}; /* leal 0(%esi),%esi */
static const char f32_4[] =
{0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */
static const char f32_5[] =
{0x90, /* nop */
0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */
static const char f32_6[] =
{0x8d,0xb6,0x00,0x00,0x00,0x00}; /* leal 0L(%esi),%esi */
static const char f32_7[] =
{0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */
static const char f32_8[] =
{0x90, /* nop */
0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */
static const char f32_9[] =
{0x89,0xf6, /* movl %esi,%esi */
0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */
static const char f32_10[] =
{0x8d,0x76,0x00, /* leal 0(%esi),%esi */
0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */
static const char f32_11[] =
{0x8d,0x74,0x26,0x00, /* leal 0(%esi,1),%esi */
0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */
static const char f32_12[] =
{0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */
0x8d,0xbf,0x00,0x00,0x00,0x00}; /* leal 0L(%edi),%edi */
static const char f32_13[] =
{0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */
0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */
static const char f32_14[] =
{0x8d,0xb4,0x26,0x00,0x00,0x00,0x00, /* leal 0L(%esi,1),%esi */
0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */
static const char f16_3[] =
{0x8d,0x74,0x00}; /* lea 0(%esi),%esi */
static const char f16_4[] =
{0x8d,0xb4,0x00,0x00}; /* lea 0w(%si),%si */
static const char f16_5[] =
{0x90, /* nop */
0x8d,0xb4,0x00,0x00}; /* lea 0w(%si),%si */
static const char f16_6[] =
{0x89,0xf6, /* mov %si,%si */
0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */
static const char f16_7[] =
{0x8d,0x74,0x00, /* lea 0(%si),%si */
0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */
static const char f16_8[] =
{0x8d,0xb4,0x00,0x00, /* lea 0w(%si),%si */
0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */
static const char jump_31[] =
{0xeb,0x1d,0x90,0x90,0x90,0x90,0x90, /* jmp .+31; lotsa nops */
0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,
0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,
0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90};
static const char *const f32_patt[] = {
f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8,
f32_9, f32_10, f32_11, f32_12, f32_13, f32_14
};
static const char *const f16_patt[] = {
f32_1, f32_2, f16_3, f16_4, f16_5, f16_6, f16_7, f16_8
};
/* nopl (%[re]ax) */
static const char alt_3[] =
{0x0f,0x1f,0x00};
/* nopl 0(%[re]ax) */
static const char alt_4[] =
{0x0f,0x1f,0x40,0x00};
/* nopl 0(%[re]ax,%[re]ax,1) */
static const char alt_5[] =
{0x0f,0x1f,0x44,0x00,0x00};
/* nopw 0(%[re]ax,%[re]ax,1) */
static const char alt_6[] =
{0x66,0x0f,0x1f,0x44,0x00,0x00};
/* nopl 0L(%[re]ax) */
static const char alt_7[] =
{0x0f,0x1f,0x80,0x00,0x00,0x00,0x00};
/* nopl 0L(%[re]ax,%[re]ax,1) */
static const char alt_8[] =
{0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
/* nopw 0L(%[re]ax,%[re]ax,1) */
static const char alt_9[] =
{0x66,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
/* nopw %cs:0L(%[re]ax,%[re]ax,1) */
static const char alt_10[] =
{0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
/* data16
nopw %cs:0L(%[re]ax,%[re]ax,1) */
static const char alt_long_11[] =
{0x66,
0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
/* data16
data16
nopw %cs:0L(%[re]ax,%[re]ax,1) */
static const char alt_long_12[] =
{0x66,
0x66,
0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
/* data16
data16
data16
nopw %cs:0L(%[re]ax,%[re]ax,1) */
static const char alt_long_13[] =
{0x66,
0x66,
0x66,
0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
/* data16
data16
data16
data16
nopw %cs:0L(%[re]ax,%[re]ax,1) */
static const char alt_long_14[] =
{0x66,
0x66,
0x66,
0x66,
0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
/* data16
data16
data16
data16
data16
nopw %cs:0L(%[re]ax,%[re]ax,1) */
static const char alt_long_15[] =
{0x66,
0x66,
0x66,
0x66,
0x66,
0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
/* nopl 0(%[re]ax,%[re]ax,1)
nopw 0(%[re]ax,%[re]ax,1) */
static const char alt_short_11[] =
{0x0f,0x1f,0x44,0x00,0x00,
0x66,0x0f,0x1f,0x44,0x00,0x00};
/* nopw 0(%[re]ax,%[re]ax,1)
nopw 0(%[re]ax,%[re]ax,1) */
static const char alt_short_12[] =
{0x66,0x0f,0x1f,0x44,0x00,0x00,
0x66,0x0f,0x1f,0x44,0x00,0x00};
/* nopw 0(%[re]ax,%[re]ax,1)
nopl 0L(%[re]ax) */
static const char alt_short_13[] =
{0x66,0x0f,0x1f,0x44,0x00,0x00,
0x0f,0x1f,0x80,0x00,0x00,0x00,0x00};
/* nopl 0L(%[re]ax)
nopl 0L(%[re]ax) */
static const char alt_short_14[] =
{0x0f,0x1f,0x80,0x00,0x00,0x00,0x00,
0x0f,0x1f,0x80,0x00,0x00,0x00,0x00};
/* nopl 0L(%[re]ax)
nopl 0L(%[re]ax,%[re]ax,1) */
static const char alt_short_15[] =
{0x0f,0x1f,0x80,0x00,0x00,0x00,0x00,
0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
static const char *const alt_short_patt[] = {
f32_1, f32_2, alt_3, alt_4, alt_5, alt_6, alt_7, alt_8,
alt_9, alt_10, alt_short_11, alt_short_12, alt_short_13,
alt_short_14, alt_short_15
};
static const char *const alt_long_patt[] = {
f32_1, f32_2, alt_3, alt_4, alt_5, alt_6, alt_7, alt_8,
alt_9, alt_10, alt_long_11, alt_long_12, alt_long_13,
alt_long_14, alt_long_15
};
 
/* Only align for at least a positive non-zero boundary. */
if (count <= 0 || count > MAX_MEM_FOR_RS_ALIGN_CODE)
return;
 
/* We need to decide which NOP sequence to use for 32bit and
64bit. When -mtune= is used:
 
1. For PROCESSOR_I386, PROCESSOR_I486, PROCESSOR_PENTIUM and
PROCESSOR_GENERIC32, f32_patt will be used.
2. For PROCESSOR_PENTIUMPRO, PROCESSOR_PENTIUM4, PROCESSOR_NOCONA,
PROCESSOR_CORE, PROCESSOR_CORE2, PROCESSOR_COREI7, and
PROCESSOR_GENERIC64, alt_long_patt will be used.
3. For PROCESSOR_ATHLON, PROCESSOR_K6, PROCESSOR_K8 and
PROCESSOR_AMDFAM10, PROCESSOR_BD and PROCESSOR_BT, alt_short_patt
will be used.
 
When -mtune= isn't used, alt_long_patt will be used if
cpu_arch_isa_flags has CpuNop. Otherwise, f32_patt will
be used.
 
When -march= or .arch is used, we can't use anything beyond
cpu_arch_isa_flags. */
 
if (flag_code == CODE_16BIT)
{
if (count > 8)
{
memcpy (fragP->fr_literal + fragP->fr_fix,
jump_31, count);
/* Adjust jump offset. */
fragP->fr_literal[fragP->fr_fix + 1] = count - 2;
}
else
memcpy (fragP->fr_literal + fragP->fr_fix,
f16_patt[count - 1], count);
}
else
{
const char *const *patt = NULL;
 
if (fragP->tc_frag_data.isa == PROCESSOR_UNKNOWN)
{
/* PROCESSOR_UNKNOWN means that all ISAs may be used. */
switch (cpu_arch_tune)
{
case PROCESSOR_UNKNOWN:
/* We use cpu_arch_isa_flags to check if we SHOULD
optimize with nops. */
if (fragP->tc_frag_data.isa_flags.bitfield.cpunop)
patt = alt_long_patt;
else
patt = f32_patt;
break;
case PROCESSOR_PENTIUM4:
case PROCESSOR_NOCONA:
case PROCESSOR_CORE:
case PROCESSOR_CORE2:
case PROCESSOR_COREI7:
case PROCESSOR_L1OM:
case PROCESSOR_K1OM:
case PROCESSOR_GENERIC64:
patt = alt_long_patt;
break;
case PROCESSOR_K6:
case PROCESSOR_ATHLON:
case PROCESSOR_K8:
case PROCESSOR_AMDFAM10:
case PROCESSOR_BD:
case PROCESSOR_BT:
patt = alt_short_patt;
break;
case PROCESSOR_I386:
case PROCESSOR_I486:
case PROCESSOR_PENTIUM:
case PROCESSOR_PENTIUMPRO:
case PROCESSOR_GENERIC32:
patt = f32_patt;
break;
}
}
else
{
switch (fragP->tc_frag_data.tune)
{
case PROCESSOR_UNKNOWN:
/* When cpu_arch_isa is set, cpu_arch_tune shouldn't be
PROCESSOR_UNKNOWN. */
abort ();
break;
 
case PROCESSOR_I386:
case PROCESSOR_I486:
case PROCESSOR_PENTIUM:
case PROCESSOR_K6:
case PROCESSOR_ATHLON:
case PROCESSOR_K8:
case PROCESSOR_AMDFAM10:
case PROCESSOR_BD:
case PROCESSOR_BT:
case PROCESSOR_GENERIC32:
/* We use cpu_arch_isa_flags to check if we CAN optimize
with nops. */
if (fragP->tc_frag_data.isa_flags.bitfield.cpunop)
patt = alt_short_patt;
else
patt = f32_patt;
break;
case PROCESSOR_PENTIUMPRO:
case PROCESSOR_PENTIUM4:
case PROCESSOR_NOCONA:
case PROCESSOR_CORE:
case PROCESSOR_CORE2:
case PROCESSOR_COREI7:
case PROCESSOR_L1OM:
case PROCESSOR_K1OM:
if (fragP->tc_frag_data.isa_flags.bitfield.cpunop)
patt = alt_long_patt;
else
patt = f32_patt;
break;
case PROCESSOR_GENERIC64:
patt = alt_long_patt;
break;
}
}
 
if (patt == f32_patt)
{
/* If the padding is less than 15 bytes, we use the normal
ones. Otherwise, we use a jump instruction and adjust
its offset. */
int limit;
 
/* For 64bit, the limit is 3 bytes. */
if (flag_code == CODE_64BIT
&& fragP->tc_frag_data.isa_flags.bitfield.cpulm)
limit = 3;
else
limit = 15;
if (count < limit)
memcpy (fragP->fr_literal + fragP->fr_fix,
patt[count - 1], count);
else
{
memcpy (fragP->fr_literal + fragP->fr_fix,
jump_31, count);
/* Adjust jump offset. */
fragP->fr_literal[fragP->fr_fix + 1] = count - 2;
}
}
else
{
/* Maximum length of an instruction is 15 byte. If the
padding is greater than 15 bytes and we don't use jump,
we have to break it into smaller pieces. */
int padding = count;
while (padding > 15)
{
padding -= 15;
memcpy (fragP->fr_literal + fragP->fr_fix + padding,
patt [14], 15);
}
 
if (padding)
memcpy (fragP->fr_literal + fragP->fr_fix,
patt [padding - 1], padding);
}
}
fragP->fr_var = count;
}
 
static INLINE int
operand_type_all_zero (const union i386_operand_type *x)
{
switch (ARRAY_SIZE(x->array))
{
case 3:
if (x->array[2])
return 0;
case 2:
if (x->array[1])
return 0;
case 1:
return !x->array[0];
default:
abort ();
}
}
 
static INLINE void
operand_type_set (union i386_operand_type *x, unsigned int v)
{
switch (ARRAY_SIZE(x->array))
{
case 3:
x->array[2] = v;
case 2:
x->array[1] = v;
case 1:
x->array[0] = v;
break;
default:
abort ();
}
}
 
static INLINE int
operand_type_equal (const union i386_operand_type *x,
const union i386_operand_type *y)
{
switch (ARRAY_SIZE(x->array))
{
case 3:
if (x->array[2] != y->array[2])
return 0;
case 2:
if (x->array[1] != y->array[1])
return 0;
case 1:
return x->array[0] == y->array[0];
break;
default:
abort ();
}
}
 
static INLINE int
cpu_flags_all_zero (const union i386_cpu_flags *x)
{
switch (ARRAY_SIZE(x->array))
{
case 3:
if (x->array[2])
return 0;
case 2:
if (x->array[1])
return 0;
case 1:
return !x->array[0];
default:
abort ();
}
}
 
static INLINE void
cpu_flags_set (union i386_cpu_flags *x, unsigned int v)
{
switch (ARRAY_SIZE(x->array))
{
case 3:
x->array[2] = v;
case 2:
x->array[1] = v;
case 1:
x->array[0] = v;
break;
default:
abort ();
}
}
 
static INLINE int
cpu_flags_equal (const union i386_cpu_flags *x,
const union i386_cpu_flags *y)
{
switch (ARRAY_SIZE(x->array))
{
case 3:
if (x->array[2] != y->array[2])
return 0;
case 2:
if (x->array[1] != y->array[1])
return 0;
case 1:
return x->array[0] == y->array[0];
break;
default:
abort ();
}
}
 
static INLINE int
cpu_flags_check_cpu64 (i386_cpu_flags f)
{
return !((flag_code == CODE_64BIT && f.bitfield.cpuno64)
|| (flag_code != CODE_64BIT && f.bitfield.cpu64));
}
 
static INLINE i386_cpu_flags
cpu_flags_and (i386_cpu_flags x, i386_cpu_flags y)
{
switch (ARRAY_SIZE (x.array))
{
case 3:
x.array [2] &= y.array [2];
case 2:
x.array [1] &= y.array [1];
case 1:
x.array [0] &= y.array [0];
break;
default:
abort ();
}
return x;
}
 
static INLINE i386_cpu_flags
cpu_flags_or (i386_cpu_flags x, i386_cpu_flags y)
{
switch (ARRAY_SIZE (x.array))
{
case 3:
x.array [2] |= y.array [2];
case 2:
x.array [1] |= y.array [1];
case 1:
x.array [0] |= y.array [0];
break;
default:
abort ();
}
return x;
}
 
static INLINE i386_cpu_flags
cpu_flags_and_not (i386_cpu_flags x, i386_cpu_flags y)
{
switch (ARRAY_SIZE (x.array))
{
case 3:
x.array [2] &= ~y.array [2];
case 2:
x.array [1] &= ~y.array [1];
case 1:
x.array [0] &= ~y.array [0];
break;
default:
abort ();
}
return x;
}
 
#define CPU_FLAGS_ARCH_MATCH 0x1
#define CPU_FLAGS_64BIT_MATCH 0x2
#define CPU_FLAGS_AES_MATCH 0x4
#define CPU_FLAGS_PCLMUL_MATCH 0x8
#define CPU_FLAGS_AVX_MATCH 0x10
 
#define CPU_FLAGS_32BIT_MATCH \
(CPU_FLAGS_ARCH_MATCH | CPU_FLAGS_AES_MATCH \
| CPU_FLAGS_PCLMUL_MATCH | CPU_FLAGS_AVX_MATCH)
#define CPU_FLAGS_PERFECT_MATCH \
(CPU_FLAGS_32BIT_MATCH | CPU_FLAGS_64BIT_MATCH)
 
/* Return CPU flags match bits. */
 
static int
cpu_flags_match (const insn_template *t)
{
i386_cpu_flags x = t->cpu_flags;
int match = cpu_flags_check_cpu64 (x) ? CPU_FLAGS_64BIT_MATCH : 0;
 
x.bitfield.cpu64 = 0;
x.bitfield.cpuno64 = 0;
 
if (cpu_flags_all_zero (&x))
{
/* This instruction is available on all archs. */
match |= CPU_FLAGS_32BIT_MATCH;
}
else
{
/* This instruction is available only on some archs. */
i386_cpu_flags cpu = cpu_arch_flags;
 
cpu.bitfield.cpu64 = 0;
cpu.bitfield.cpuno64 = 0;
cpu = cpu_flags_and (x, cpu);
if (!cpu_flags_all_zero (&cpu))
{
if (x.bitfield.cpuavx)
{
/* We only need to check AES/PCLMUL/SSE2AVX with AVX. */
if (cpu.bitfield.cpuavx)
{
/* Check SSE2AVX. */
if (!t->opcode_modifier.sse2avx|| sse2avx)
{
match |= (CPU_FLAGS_ARCH_MATCH
| CPU_FLAGS_AVX_MATCH);
/* Check AES. */
if (!x.bitfield.cpuaes || cpu.bitfield.cpuaes)
match |= CPU_FLAGS_AES_MATCH;
/* Check PCLMUL. */
if (!x.bitfield.cpupclmul
|| cpu.bitfield.cpupclmul)
match |= CPU_FLAGS_PCLMUL_MATCH;
}
}
else
match |= CPU_FLAGS_ARCH_MATCH;
}
else
match |= CPU_FLAGS_32BIT_MATCH;
}
}
return match;
}
 
static INLINE i386_operand_type
operand_type_and (i386_operand_type x, i386_operand_type y)
{
switch (ARRAY_SIZE (x.array))
{
case 3:
x.array [2] &= y.array [2];
case 2:
x.array [1] &= y.array [1];
case 1:
x.array [0] &= y.array [0];
break;
default:
abort ();
}
return x;
}
 
static INLINE i386_operand_type
operand_type_or (i386_operand_type x, i386_operand_type y)
{
switch (ARRAY_SIZE (x.array))
{
case 3:
x.array [2] |= y.array [2];
case 2:
x.array [1] |= y.array [1];
case 1:
x.array [0] |= y.array [0];
break;
default:
abort ();
}
return x;
}
 
static INLINE i386_operand_type
operand_type_xor (i386_operand_type x, i386_operand_type y)
{
switch (ARRAY_SIZE (x.array))
{
case 3:
x.array [2] ^= y.array [2];
case 2:
x.array [1] ^= y.array [1];
case 1:
x.array [0] ^= y.array [0];
break;
default:
abort ();
}
return x;
}
 
static const i386_operand_type acc32 = OPERAND_TYPE_ACC32;
static const i386_operand_type acc64 = OPERAND_TYPE_ACC64;
static const i386_operand_type control = OPERAND_TYPE_CONTROL;
static const i386_operand_type inoutportreg
= OPERAND_TYPE_INOUTPORTREG;
static const i386_operand_type reg16_inoutportreg
= OPERAND_TYPE_REG16_INOUTPORTREG;
static const i386_operand_type disp16 = OPERAND_TYPE_DISP16;
static const i386_operand_type disp32 = OPERAND_TYPE_DISP32;
static const i386_operand_type disp32s = OPERAND_TYPE_DISP32S;
static const i386_operand_type disp16_32 = OPERAND_TYPE_DISP16_32;
static const i386_operand_type anydisp
= OPERAND_TYPE_ANYDISP;
static const i386_operand_type regxmm = OPERAND_TYPE_REGXMM;
static const i386_operand_type regymm = OPERAND_TYPE_REGYMM;
static const i386_operand_type regzmm = OPERAND_TYPE_REGZMM;
static const i386_operand_type regmask = OPERAND_TYPE_REGMASK;
static const i386_operand_type imm8 = OPERAND_TYPE_IMM8;
static const i386_operand_type imm8s = OPERAND_TYPE_IMM8S;
static const i386_operand_type imm16 = OPERAND_TYPE_IMM16;
static const i386_operand_type imm32 = OPERAND_TYPE_IMM32;
static const i386_operand_type imm32s = OPERAND_TYPE_IMM32S;
static const i386_operand_type imm64 = OPERAND_TYPE_IMM64;
static const i386_operand_type imm16_32 = OPERAND_TYPE_IMM16_32;
static const i386_operand_type imm16_32s = OPERAND_TYPE_IMM16_32S;
static const i386_operand_type imm16_32_32s = OPERAND_TYPE_IMM16_32_32S;
static const i386_operand_type vec_imm4 = OPERAND_TYPE_VEC_IMM4;
static const i386_operand_type regbnd = OPERAND_TYPE_REGBND;
static const i386_operand_type vec_disp8 = OPERAND_TYPE_VEC_DISP8;
 
enum operand_type
{
reg,
imm,
disp,
anymem
};
 
static INLINE int
operand_type_check (i386_operand_type t, enum operand_type c)
{
switch (c)
{
case reg:
return (t.bitfield.reg8
|| t.bitfield.reg16
|| t.bitfield.reg32
|| t.bitfield.reg64);
 
case imm:
return (t.bitfield.imm8
|| t.bitfield.imm8s
|| t.bitfield.imm16
|| t.bitfield.imm32
|| t.bitfield.imm32s
|| t.bitfield.imm64);
 
case disp:
return (t.bitfield.disp8
|| t.bitfield.disp16
|| t.bitfield.disp32
|| t.bitfield.disp32s
|| t.bitfield.disp64);
 
case anymem:
return (t.bitfield.disp8
|| t.bitfield.disp16
|| t.bitfield.disp32
|| t.bitfield.disp32s
|| t.bitfield.disp64
|| t.bitfield.baseindex);
 
default:
abort ();
}
 
return 0;
}
 
/* Return 1 if there is no conflict in 8bit/16bit/32bit/64bit on
operand J for instruction template T. */
 
static INLINE int
match_reg_size (const insn_template *t, unsigned int j)
{
return !((i.types[j].bitfield.byte
&& !t->operand_types[j].bitfield.byte)
|| (i.types[j].bitfield.word
&& !t->operand_types[j].bitfield.word)
|| (i.types[j].bitfield.dword
&& !t->operand_types[j].bitfield.dword)
|| (i.types[j].bitfield.qword
&& !t->operand_types[j].bitfield.qword));
}
 
/* Return 1 if there is no conflict in any size on operand J for
instruction template T. */
 
static INLINE int
match_mem_size (const insn_template *t, unsigned int j)
{
return (match_reg_size (t, j)
&& !((i.types[j].bitfield.unspecified
&& !t->operand_types[j].bitfield.unspecified)
|| (i.types[j].bitfield.fword
&& !t->operand_types[j].bitfield.fword)
|| (i.types[j].bitfield.tbyte
&& !t->operand_types[j].bitfield.tbyte)
|| (i.types[j].bitfield.xmmword
&& !t->operand_types[j].bitfield.xmmword)
|| (i.types[j].bitfield.ymmword
&& !t->operand_types[j].bitfield.ymmword)
|| (i.types[j].bitfield.zmmword
&& !t->operand_types[j].bitfield.zmmword)));
}
 
/* Return 1 if there is no size conflict on any operands for
instruction template T. */
 
static INLINE int
operand_size_match (const insn_template *t)
{
unsigned int j;
int match = 1;
 
/* Don't check jump instructions. */
if (t->opcode_modifier.jump
|| t->opcode_modifier.jumpbyte
|| t->opcode_modifier.jumpdword
|| t->opcode_modifier.jumpintersegment)
return match;
 
/* Check memory and accumulator operand size. */
for (j = 0; j < i.operands; j++)
{
if (t->operand_types[j].bitfield.anysize)
continue;
 
if (t->operand_types[j].bitfield.acc && !match_reg_size (t, j))
{
match = 0;
break;
}
 
if (i.types[j].bitfield.mem && !match_mem_size (t, j))
{
match = 0;
break;
}
}
 
if (match)
return match;
else if (!t->opcode_modifier.d && !t->opcode_modifier.floatd)
{
mismatch:
i.error = operand_size_mismatch;
return 0;
}
 
/* Check reverse. */
gas_assert (i.operands == 2);
 
match = 1;
for (j = 0; j < 2; j++)
{
if (t->operand_types[j].bitfield.acc
&& !match_reg_size (t, j ? 0 : 1))
goto mismatch;
 
if (i.types[j].bitfield.mem
&& !match_mem_size (t, j ? 0 : 1))
goto mismatch;
}
 
return match;
}
 
static INLINE int
operand_type_match (i386_operand_type overlap,
i386_operand_type given)
{
i386_operand_type temp = overlap;
 
temp.bitfield.jumpabsolute = 0;
temp.bitfield.unspecified = 0;
temp.bitfield.byte = 0;
temp.bitfield.word = 0;
temp.bitfield.dword = 0;
temp.bitfield.fword = 0;
temp.bitfield.qword = 0;
temp.bitfield.tbyte = 0;
temp.bitfield.xmmword = 0;
temp.bitfield.ymmword = 0;
temp.bitfield.zmmword = 0;
if (operand_type_all_zero (&temp))
goto mismatch;
 
if (given.bitfield.baseindex == overlap.bitfield.baseindex
&& given.bitfield.jumpabsolute == overlap.bitfield.jumpabsolute)
return 1;
 
mismatch:
i.error = operand_type_mismatch;
return 0;
}
 
/* If given types g0 and g1 are registers they must be of the same type
unless the expected operand type register overlap is null.
Note that Acc in a template matches every size of reg. */
 
static INLINE int
operand_type_register_match (i386_operand_type m0,
i386_operand_type g0,
i386_operand_type t0,
i386_operand_type m1,
i386_operand_type g1,
i386_operand_type t1)
{
if (!operand_type_check (g0, reg))
return 1;
 
if (!operand_type_check (g1, reg))
return 1;
 
if (g0.bitfield.reg8 == g1.bitfield.reg8
&& g0.bitfield.reg16 == g1.bitfield.reg16
&& g0.bitfield.reg32 == g1.bitfield.reg32
&& g0.bitfield.reg64 == g1.bitfield.reg64)
return 1;
 
if (m0.bitfield.acc)
{
t0.bitfield.reg8 = 1;
t0.bitfield.reg16 = 1;
t0.bitfield.reg32 = 1;
t0.bitfield.reg64 = 1;
}
 
if (m1.bitfield.acc)
{
t1.bitfield.reg8 = 1;
t1.bitfield.reg16 = 1;
t1.bitfield.reg32 = 1;
t1.bitfield.reg64 = 1;
}
 
if (!(t0.bitfield.reg8 & t1.bitfield.reg8)
&& !(t0.bitfield.reg16 & t1.bitfield.reg16)
&& !(t0.bitfield.reg32 & t1.bitfield.reg32)
&& !(t0.bitfield.reg64 & t1.bitfield.reg64))
return 1;
 
i.error = register_type_mismatch;
 
return 0;
}
 
static INLINE unsigned int
register_number (const reg_entry *r)
{
unsigned int nr = r->reg_num;
 
if (r->reg_flags & RegRex)
nr += 8;
 
return nr;
}
 
static INLINE unsigned int
mode_from_disp_size (i386_operand_type t)
{
if (t.bitfield.disp8 || t.bitfield.vec_disp8)
return 1;
else if (t.bitfield.disp16
|| t.bitfield.disp32
|| t.bitfield.disp32s)
return 2;
else
return 0;
}
 
static INLINE int
fits_in_signed_byte (offsetT num)
{
return (num >= -128) && (num <= 127);
}
 
static INLINE int
fits_in_unsigned_byte (offsetT num)
{
return (num & 0xff) == num;
}
 
static INLINE int
fits_in_unsigned_word (offsetT num)
{
return (num & 0xffff) == num;
}
 
static INLINE int
fits_in_signed_word (offsetT num)
{
return (-32768 <= num) && (num <= 32767);
}
 
static INLINE int
fits_in_signed_long (offsetT num ATTRIBUTE_UNUSED)
{
#ifndef BFD64
return 1;
#else
return (!(((offsetT) -1 << 31) & num)
|| (((offsetT) -1 << 31) & num) == ((offsetT) -1 << 31));
#endif
} /* fits_in_signed_long() */
 
static INLINE int
fits_in_unsigned_long (offsetT num ATTRIBUTE_UNUSED)
{
#ifndef BFD64
return 1;
#else
return (num & (((offsetT) 2 << 31) - 1)) == num;
#endif
} /* fits_in_unsigned_long() */
 
static INLINE int
fits_in_vec_disp8 (offsetT num)
{
int shift = i.memshift;
unsigned int mask;
 
if (shift == -1)
abort ();
 
mask = (1 << shift) - 1;
 
/* Return 0 if NUM isn't properly aligned. */
if ((num & mask))
return 0;
 
/* Check if NUM will fit in 8bit after shift. */
return fits_in_signed_byte (num >> shift);
}
 
static INLINE int
fits_in_imm4 (offsetT num)
{
return (num & 0xf) == num;
}
 
static i386_operand_type
smallest_imm_type (offsetT num)
{
i386_operand_type t;
 
operand_type_set (&t, 0);
t.bitfield.imm64 = 1;
 
if (cpu_arch_tune != PROCESSOR_I486 && num == 1)
{
/* This code is disabled on the 486 because all the Imm1 forms
in the opcode table are slower on the i486. They're the
versions with the implicitly specified single-position
displacement, which has another syntax if you really want to
use that form. */
t.bitfield.imm1 = 1;
t.bitfield.imm8 = 1;
t.bitfield.imm8s = 1;
t.bitfield.imm16 = 1;
t.bitfield.imm32 = 1;
t.bitfield.imm32s = 1;
}
else if (fits_in_signed_byte (num))
{
t.bitfield.imm8 = 1;
t.bitfield.imm8s = 1;
t.bitfield.imm16 = 1;
t.bitfield.imm32 = 1;
t.bitfield.imm32s = 1;
}
else if (fits_in_unsigned_byte (num))
{
t.bitfield.imm8 = 1;
t.bitfield.imm16 = 1;
t.bitfield.imm32 = 1;
t.bitfield.imm32s = 1;
}
else if (fits_in_signed_word (num) || fits_in_unsigned_word (num))
{
t.bitfield.imm16 = 1;
t.bitfield.imm32 = 1;
t.bitfield.imm32s = 1;
}
else if (fits_in_signed_long (num))
{
t.bitfield.imm32 = 1;
t.bitfield.imm32s = 1;
}
else if (fits_in_unsigned_long (num))
t.bitfield.imm32 = 1;
 
return t;
}
 
static offsetT
offset_in_range (offsetT val, int size)
{
addressT mask;
 
switch (size)
{
case 1: mask = ((addressT) 1 << 8) - 1; break;
case 2: mask = ((addressT) 1 << 16) - 1; break;
case 4: mask = ((addressT) 2 << 31) - 1; break;
#ifdef BFD64
case 8: mask = ((addressT) 2 << 63) - 1; break;
#endif
default: abort ();
}
 
#ifdef BFD64
/* If BFD64, sign extend val for 32bit address mode. */
if (flag_code != CODE_64BIT
|| i.prefix[ADDR_PREFIX])
if ((val & ~(((addressT) 2 << 31) - 1)) == 0)
val = (val ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31);
#endif
 
if ((val & ~mask) != 0 && (val & ~mask) != ~mask)
{
char buf1[40], buf2[40];
 
sprint_value (buf1, val);
sprint_value (buf2, val & mask);
as_warn (_("%s shortened to %s"), buf1, buf2);
}
return val & mask;
}
 
enum PREFIX_GROUP
{
PREFIX_EXIST = 0,
PREFIX_LOCK,
PREFIX_REP,
PREFIX_OTHER
};
 
/* Returns
a. PREFIX_EXIST if attempting to add a prefix where one from the
same class already exists.
b. PREFIX_LOCK if lock prefix is added.
c. PREFIX_REP if rep/repne prefix is added.
d. PREFIX_OTHER if other prefix is added.
*/
 
static enum PREFIX_GROUP
add_prefix (unsigned int prefix)
{
enum PREFIX_GROUP ret = PREFIX_OTHER;
unsigned int q;
 
if (prefix >= REX_OPCODE && prefix < REX_OPCODE + 16
&& flag_code == CODE_64BIT)
{
if ((i.prefix[REX_PREFIX] & prefix & REX_W)
|| ((i.prefix[REX_PREFIX] & (REX_R | REX_X | REX_B))
&& (prefix & (REX_R | REX_X | REX_B))))
ret = PREFIX_EXIST;
q = REX_PREFIX;
}
else
{
switch (prefix)
{
default:
abort ();
 
case CS_PREFIX_OPCODE:
case DS_PREFIX_OPCODE:
case ES_PREFIX_OPCODE:
case FS_PREFIX_OPCODE:
case GS_PREFIX_OPCODE:
case SS_PREFIX_OPCODE:
q = SEG_PREFIX;
break;
 
case REPNE_PREFIX_OPCODE:
case REPE_PREFIX_OPCODE:
q = REP_PREFIX;
ret = PREFIX_REP;
break;
 
case LOCK_PREFIX_OPCODE:
q = LOCK_PREFIX;
ret = PREFIX_LOCK;
break;
 
case FWAIT_OPCODE:
q = WAIT_PREFIX;
break;
 
case ADDR_PREFIX_OPCODE:
q = ADDR_PREFIX;
break;
 
case DATA_PREFIX_OPCODE:
q = DATA_PREFIX;
break;
}
if (i.prefix[q] != 0)
ret = PREFIX_EXIST;
}
 
if (ret)
{
if (!i.prefix[q])
++i.prefixes;
i.prefix[q] |= prefix;
}
else
as_bad (_("same type of prefix used twice"));
 
return ret;
}
 
static void
update_code_flag (int value, int check)
{
PRINTF_LIKE ((*as_error));
 
flag_code = (enum flag_code) value;
if (flag_code == CODE_64BIT)
{
cpu_arch_flags.bitfield.cpu64 = 1;
cpu_arch_flags.bitfield.cpuno64 = 0;
}
else
{
cpu_arch_flags.bitfield.cpu64 = 0;
cpu_arch_flags.bitfield.cpuno64 = 1;
}
if (value == CODE_64BIT && !cpu_arch_flags.bitfield.cpulm )
{
if (check)
as_error = as_fatal;
else
as_error = as_bad;
(*as_error) (_("64bit mode not supported on `%s'."),
cpu_arch_name ? cpu_arch_name : default_arch);
}
if (value == CODE_32BIT && !cpu_arch_flags.bitfield.cpui386)
{
if (check)
as_error = as_fatal;
else
as_error = as_bad;
(*as_error) (_("32bit mode not supported on `%s'."),
cpu_arch_name ? cpu_arch_name : default_arch);
}
stackop_size = '\0';
}
 
static void
set_code_flag (int value)
{
update_code_flag (value, 0);
}
 
static void
set_16bit_gcc_code_flag (int new_code_flag)
{
flag_code = (enum flag_code) new_code_flag;
if (flag_code != CODE_16BIT)
abort ();
cpu_arch_flags.bitfield.cpu64 = 0;
cpu_arch_flags.bitfield.cpuno64 = 1;
stackop_size = LONG_MNEM_SUFFIX;
}
 
static void
set_intel_syntax (int syntax_flag)
{
/* Find out if register prefixing is specified. */
int ask_naked_reg = 0;
 
SKIP_WHITESPACE ();
if (!is_end_of_line[(unsigned char) *input_line_pointer])
{
char *string = input_line_pointer;
int e = get_symbol_end ();
 
if (strcmp (string, "prefix") == 0)
ask_naked_reg = 1;
else if (strcmp (string, "noprefix") == 0)
ask_naked_reg = -1;
else
as_bad (_("bad argument to syntax directive."));
*input_line_pointer = e;
}
demand_empty_rest_of_line ();
 
intel_syntax = syntax_flag;
 
if (ask_naked_reg == 0)
allow_naked_reg = (intel_syntax
&& (bfd_get_symbol_leading_char (stdoutput) != '\0'));
else
allow_naked_reg = (ask_naked_reg < 0);
 
expr_set_rank (O_full_ptr, syntax_flag ? 10 : 0);
 
identifier_chars['%'] = intel_syntax && allow_naked_reg ? '%' : 0;
identifier_chars['$'] = intel_syntax ? '$' : 0;
register_prefix = allow_naked_reg ? "" : "%";
}
 
static void
set_intel_mnemonic (int mnemonic_flag)
{
intel_mnemonic = mnemonic_flag;
}
 
static void
set_allow_index_reg (int flag)
{
allow_index_reg = flag;
}
 
static void
set_check (int what)
{
enum check_kind *kind;
const char *str;
 
if (what)
{
kind = &operand_check;
str = "operand";
}
else
{
kind = &sse_check;
str = "sse";
}
 
SKIP_WHITESPACE ();
 
if (!is_end_of_line[(unsigned char) *input_line_pointer])
{
char *string = input_line_pointer;
int e = get_symbol_end ();
 
if (strcmp (string, "none") == 0)
*kind = check_none;
else if (strcmp (string, "warning") == 0)
*kind = check_warning;
else if (strcmp (string, "error") == 0)
*kind = check_error;
else
as_bad (_("bad argument to %s_check directive."), str);
*input_line_pointer = e;
}
else
as_bad (_("missing argument for %s_check directive"), str);
 
demand_empty_rest_of_line ();
}
 
static void
check_cpu_arch_compatible (const char *name ATTRIBUTE_UNUSED,
i386_cpu_flags new_flag ATTRIBUTE_UNUSED)
{
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
static const char *arch;
 
/* Intel LIOM is only supported on ELF. */
if (!IS_ELF)
return;
 
if (!arch)
{
/* Use cpu_arch_name if it is set in md_parse_option. Otherwise
use default_arch. */
arch = cpu_arch_name;
if (!arch)
arch = default_arch;
}
 
/* If we are targeting Intel L1OM, we must enable it. */
if (get_elf_backend_data (stdoutput)->elf_machine_code != EM_L1OM
|| new_flag.bitfield.cpul1om)
return;
 
/* If we are targeting Intel K1OM, we must enable it. */
if (get_elf_backend_data (stdoutput)->elf_machine_code != EM_K1OM
|| new_flag.bitfield.cpuk1om)
return;
 
as_bad (_("`%s' is not supported on `%s'"), name, arch);
#endif
}
 
static void
set_cpu_arch (int dummy ATTRIBUTE_UNUSED)
{
SKIP_WHITESPACE ();
 
if (!is_end_of_line[(unsigned char) *input_line_pointer])
{
char *string = input_line_pointer;
int e = get_symbol_end ();
unsigned int j;
i386_cpu_flags flags;
 
for (j = 0; j < ARRAY_SIZE (cpu_arch); j++)
{
if (strcmp (string, cpu_arch[j].name) == 0)
{
check_cpu_arch_compatible (string, cpu_arch[j].flags);
 
if (*string != '.')
{
cpu_arch_name = cpu_arch[j].name;
cpu_sub_arch_name = NULL;
cpu_arch_flags = cpu_arch[j].flags;
if (flag_code == CODE_64BIT)
{
cpu_arch_flags.bitfield.cpu64 = 1;
cpu_arch_flags.bitfield.cpuno64 = 0;
}
else
{
cpu_arch_flags.bitfield.cpu64 = 0;
cpu_arch_flags.bitfield.cpuno64 = 1;
}
cpu_arch_isa = cpu_arch[j].type;
cpu_arch_isa_flags = cpu_arch[j].flags;
if (!cpu_arch_tune_set)
{
cpu_arch_tune = cpu_arch_isa;
cpu_arch_tune_flags = cpu_arch_isa_flags;
}
break;
}
 
if (!cpu_arch[j].negated)
flags = cpu_flags_or (cpu_arch_flags,
cpu_arch[j].flags);
else
flags = cpu_flags_and_not (cpu_arch_flags,
cpu_arch[j].flags);
if (!cpu_flags_equal (&flags, &cpu_arch_flags))
{
if (cpu_sub_arch_name)
{
char *name = cpu_sub_arch_name;
cpu_sub_arch_name = concat (name,
cpu_arch[j].name,
(const char *) NULL);
free (name);
}
else
cpu_sub_arch_name = xstrdup (cpu_arch[j].name);
cpu_arch_flags = flags;
cpu_arch_isa_flags = flags;
}
*input_line_pointer = e;
demand_empty_rest_of_line ();
return;
}
}
if (j >= ARRAY_SIZE (cpu_arch))
as_bad (_("no such architecture: `%s'"), string);
 
*input_line_pointer = e;
}
else
as_bad (_("missing cpu architecture"));
 
no_cond_jump_promotion = 0;
if (*input_line_pointer == ','
&& !is_end_of_line[(unsigned char) input_line_pointer[1]])
{
char *string = ++input_line_pointer;
int e = get_symbol_end ();
 
if (strcmp (string, "nojumps") == 0)
no_cond_jump_promotion = 1;
else if (strcmp (string, "jumps") == 0)
;
else
as_bad (_("no such architecture modifier: `%s'"), string);
 
*input_line_pointer = e;
}
 
demand_empty_rest_of_line ();
}
 
enum bfd_architecture
i386_arch (void)
{
if (cpu_arch_isa == PROCESSOR_L1OM)
{
if (OUTPUT_FLAVOR != bfd_target_elf_flavour
|| flag_code != CODE_64BIT)
as_fatal (_("Intel L1OM is 64bit ELF only"));
return bfd_arch_l1om;
}
else if (cpu_arch_isa == PROCESSOR_K1OM)
{
if (OUTPUT_FLAVOR != bfd_target_elf_flavour
|| flag_code != CODE_64BIT)
as_fatal (_("Intel K1OM is 64bit ELF only"));
return bfd_arch_k1om;
}
else
return bfd_arch_i386;
}
 
unsigned long
i386_mach (void)
{
if (!strncmp (default_arch, "x86_64", 6))
{
if (cpu_arch_isa == PROCESSOR_L1OM)
{
if (OUTPUT_FLAVOR != bfd_target_elf_flavour
|| default_arch[6] != '\0')
as_fatal (_("Intel L1OM is 64bit ELF only"));
return bfd_mach_l1om;
}
else if (cpu_arch_isa == PROCESSOR_K1OM)
{
if (OUTPUT_FLAVOR != bfd_target_elf_flavour
|| default_arch[6] != '\0')
as_fatal (_("Intel K1OM is 64bit ELF only"));
return bfd_mach_k1om;
}
else if (default_arch[6] == '\0')
return bfd_mach_x86_64;
else
return bfd_mach_x64_32;
}
else if (!strcmp (default_arch, "i386"))
return bfd_mach_i386_i386;
else
as_fatal (_("unknown architecture"));
}
void
md_begin (void)
{
const char *hash_err;
 
/* Initialize op_hash hash table. */
op_hash = hash_new ();
 
{
const insn_template *optab;
templates *core_optab;
 
/* Setup for loop. */
optab = i386_optab;
core_optab = (templates *) xmalloc (sizeof (templates));
core_optab->start = optab;
 
while (1)
{
++optab;
if (optab->name == NULL
|| strcmp (optab->name, (optab - 1)->name) != 0)
{
/* different name --> ship out current template list;
add to hash table; & begin anew. */
core_optab->end = optab;
hash_err = hash_insert (op_hash,
(optab - 1)->name,
(void *) core_optab);
if (hash_err)
{
as_fatal (_("can't hash %s: %s"),
(optab - 1)->name,
hash_err);
}
if (optab->name == NULL)
break;
core_optab = (templates *) xmalloc (sizeof (templates));
core_optab->start = optab;
}
}
}
 
/* Initialize reg_hash hash table. */
reg_hash = hash_new ();
{
const reg_entry *regtab;
unsigned int regtab_size = i386_regtab_size;
 
for (regtab = i386_regtab; regtab_size--; regtab++)
{
hash_err = hash_insert (reg_hash, regtab->reg_name, (void *) regtab);
if (hash_err)
as_fatal (_("can't hash %s: %s"),
regtab->reg_name,
hash_err);
}
}
 
/* Fill in lexical tables: mnemonic_chars, operand_chars. */
{
int c;
char *p;
 
for (c = 0; c < 256; c++)
{
if (ISDIGIT (c))
{
digit_chars[c] = c;
mnemonic_chars[c] = c;
register_chars[c] = c;
operand_chars[c] = c;
}
else if (ISLOWER (c))
{
mnemonic_chars[c] = c;
register_chars[c] = c;
operand_chars[c] = c;
}
else if (ISUPPER (c))
{
mnemonic_chars[c] = TOLOWER (c);
register_chars[c] = mnemonic_chars[c];
operand_chars[c] = c;
}
else if (c == '{' || c == '}')
operand_chars[c] = c;
 
if (ISALPHA (c) || ISDIGIT (c))
identifier_chars[c] = c;
else if (c >= 128)
{
identifier_chars[c] = c;
operand_chars[c] = c;
}
}
 
#ifdef LEX_AT
identifier_chars['@'] = '@';
#endif
#ifdef LEX_QM
identifier_chars['?'] = '?';
operand_chars['?'] = '?';
#endif
digit_chars['-'] = '-';
mnemonic_chars['_'] = '_';
mnemonic_chars['-'] = '-';
mnemonic_chars['.'] = '.';
identifier_chars['_'] = '_';
identifier_chars['.'] = '.';
 
for (p = operand_special_chars; *p != '\0'; p++)
operand_chars[(unsigned char) *p] = *p;
}
 
if (flag_code == CODE_64BIT)
{
#if defined (OBJ_COFF) && defined (TE_PE)
x86_dwarf2_return_column = (OUTPUT_FLAVOR == bfd_target_coff_flavour
? 32 : 16);
#else
x86_dwarf2_return_column = 16;
#endif
x86_cie_data_alignment = -8;
}
else
{
x86_dwarf2_return_column = 8;
x86_cie_data_alignment = -4;
}
}
 
void
i386_print_statistics (FILE *file)
{
hash_print_statistics (file, "i386 opcode", op_hash);
hash_print_statistics (file, "i386 register", reg_hash);
}
#ifdef DEBUG386
 
/* Debugging routines for md_assemble. */
static void pte (insn_template *);
static void pt (i386_operand_type);
static void pe (expressionS *);
static void ps (symbolS *);
 
static void
pi (char *line, i386_insn *x)
{
unsigned int j;
 
fprintf (stdout, "%s: template ", line);
pte (&x->tm);
fprintf (stdout, " address: base %s index %s scale %x\n",
x->base_reg ? x->base_reg->reg_name : "none",
x->index_reg ? x->index_reg->reg_name : "none",
x->log2_scale_factor);
fprintf (stdout, " modrm: mode %x reg %x reg/mem %x\n",
x->rm.mode, x->rm.reg, x->rm.regmem);
fprintf (stdout, " sib: base %x index %x scale %x\n",
x->sib.base, x->sib.index, x->sib.scale);
fprintf (stdout, " rex: 64bit %x extX %x extY %x extZ %x\n",
(x->rex & REX_W) != 0,
(x->rex & REX_R) != 0,
(x->rex & REX_X) != 0,
(x->rex & REX_B) != 0);
for (j = 0; j < x->operands; j++)
{
fprintf (stdout, " #%d: ", j + 1);
pt (x->types[j]);
fprintf (stdout, "\n");
if (x->types[j].bitfield.reg8
|| x->types[j].bitfield.reg16
|| x->types[j].bitfield.reg32
|| x->types[j].bitfield.reg64
|| x->types[j].bitfield.regmmx
|| x->types[j].bitfield.regxmm
|| x->types[j].bitfield.regymm
|| x->types[j].bitfield.regzmm
|| x->types[j].bitfield.sreg2
|| x->types[j].bitfield.sreg3
|| x->types[j].bitfield.control
|| x->types[j].bitfield.debug
|| x->types[j].bitfield.test)
fprintf (stdout, "%s\n", x->op[j].regs->reg_name);
if (operand_type_check (x->types[j], imm))
pe (x->op[j].imms);
if (operand_type_check (x->types[j], disp))
pe (x->op[j].disps);
}
}
 
static void
pte (insn_template *t)
{
unsigned int j;
fprintf (stdout, " %d operands ", t->operands);
fprintf (stdout, "opcode %x ", t->base_opcode);
if (t->extension_opcode != None)
fprintf (stdout, "ext %x ", t->extension_opcode);
if (t->opcode_modifier.d)
fprintf (stdout, "D");
if (t->opcode_modifier.w)
fprintf (stdout, "W");
fprintf (stdout, "\n");
for (j = 0; j < t->operands; j++)
{
fprintf (stdout, " #%d type ", j + 1);
pt (t->operand_types[j]);
fprintf (stdout, "\n");
}
}
 
static void
pe (expressionS *e)
{
fprintf (stdout, " operation %d\n", e->X_op);
fprintf (stdout, " add_number %ld (%lx)\n",
(long) e->X_add_number, (long) e->X_add_number);
if (e->X_add_symbol)
{
fprintf (stdout, " add_symbol ");
ps (e->X_add_symbol);
fprintf (stdout, "\n");
}
if (e->X_op_symbol)
{
fprintf (stdout, " op_symbol ");
ps (e->X_op_symbol);
fprintf (stdout, "\n");
}
}
 
static void
ps (symbolS *s)
{
fprintf (stdout, "%s type %s%s",
S_GET_NAME (s),
S_IS_EXTERNAL (s) ? "EXTERNAL " : "",
segment_name (S_GET_SEGMENT (s)));
}
 
static struct type_name
{
i386_operand_type mask;
const char *name;
}
const type_names[] =
{
{ OPERAND_TYPE_REG8, "r8" },
{ OPERAND_TYPE_REG16, "r16" },
{ OPERAND_TYPE_REG32, "r32" },
{ OPERAND_TYPE_REG64, "r64" },
{ OPERAND_TYPE_IMM8, "i8" },
{ OPERAND_TYPE_IMM8, "i8s" },
{ OPERAND_TYPE_IMM16, "i16" },
{ OPERAND_TYPE_IMM32, "i32" },
{ OPERAND_TYPE_IMM32S, "i32s" },
{ OPERAND_TYPE_IMM64, "i64" },
{ OPERAND_TYPE_IMM1, "i1" },
{ OPERAND_TYPE_BASEINDEX, "BaseIndex" },
{ OPERAND_TYPE_DISP8, "d8" },
{ OPERAND_TYPE_DISP16, "d16" },
{ OPERAND_TYPE_DISP32, "d32" },
{ OPERAND_TYPE_DISP32S, "d32s" },
{ OPERAND_TYPE_DISP64, "d64" },
{ OPERAND_TYPE_VEC_DISP8, "Vector d8" },
{ OPERAND_TYPE_INOUTPORTREG, "InOutPortReg" },
{ OPERAND_TYPE_SHIFTCOUNT, "ShiftCount" },
{ OPERAND_TYPE_CONTROL, "control reg" },
{ OPERAND_TYPE_TEST, "test reg" },
{ OPERAND_TYPE_DEBUG, "debug reg" },
{ OPERAND_TYPE_FLOATREG, "FReg" },
{ OPERAND_TYPE_FLOATACC, "FAcc" },
{ OPERAND_TYPE_SREG2, "SReg2" },
{ OPERAND_TYPE_SREG3, "SReg3" },
{ OPERAND_TYPE_ACC, "Acc" },
{ OPERAND_TYPE_JUMPABSOLUTE, "Jump Absolute" },
{ OPERAND_TYPE_REGMMX, "rMMX" },
{ OPERAND_TYPE_REGXMM, "rXMM" },
{ OPERAND_TYPE_REGYMM, "rYMM" },
{ OPERAND_TYPE_REGZMM, "rZMM" },
{ OPERAND_TYPE_REGMASK, "Mask reg" },
{ OPERAND_TYPE_ESSEG, "es" },
};
 
static void
pt (i386_operand_type t)
{
unsigned int j;
i386_operand_type a;
 
for (j = 0; j < ARRAY_SIZE (type_names); j++)
{
a = operand_type_and (t, type_names[j].mask);
if (!operand_type_all_zero (&a))
fprintf (stdout, "%s, ", type_names[j].name);
}
fflush (stdout);
}
 
#endif /* DEBUG386 */
static bfd_reloc_code_real_type
reloc (unsigned int size,
int pcrel,
int sign,
int bnd_prefix,
bfd_reloc_code_real_type other)
{
if (other != NO_RELOC)
{
reloc_howto_type *rel;
 
if (size == 8)
switch (other)
{
case BFD_RELOC_X86_64_GOT32:
return BFD_RELOC_X86_64_GOT64;
break;
case BFD_RELOC_X86_64_PLTOFF64:
return BFD_RELOC_X86_64_PLTOFF64;
break;
case BFD_RELOC_X86_64_GOTPC32:
other = BFD_RELOC_X86_64_GOTPC64;
break;
case BFD_RELOC_X86_64_GOTPCREL:
other = BFD_RELOC_X86_64_GOTPCREL64;
break;
case BFD_RELOC_X86_64_TPOFF32:
other = BFD_RELOC_X86_64_TPOFF64;
break;
case BFD_RELOC_X86_64_DTPOFF32:
other = BFD_RELOC_X86_64_DTPOFF64;
break;
default:
break;
}
 
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
if (other == BFD_RELOC_SIZE32)
{
if (size == 8)
return BFD_RELOC_SIZE64;
if (pcrel)
as_bad (_("there are no pc-relative size relocations"));
}
#endif
 
/* Sign-checking 4-byte relocations in 16-/32-bit code is pointless. */
if (size == 4 && (flag_code != CODE_64BIT || disallow_64bit_reloc))
sign = -1;
 
rel = bfd_reloc_type_lookup (stdoutput, other);
if (!rel)
as_bad (_("unknown relocation (%u)"), other);
else if (size != bfd_get_reloc_size (rel))
as_bad (_("%u-byte relocation cannot be applied to %u-byte field"),
bfd_get_reloc_size (rel),
size);
else if (pcrel && !rel->pc_relative)
as_bad (_("non-pc-relative relocation for pc-relative field"));
else if ((rel->complain_on_overflow == complain_overflow_signed
&& !sign)
|| (rel->complain_on_overflow == complain_overflow_unsigned
&& sign > 0))
as_bad (_("relocated field and relocation type differ in signedness"));
else
return other;
return NO_RELOC;
}
 
if (pcrel)
{
if (!sign)
as_bad (_("there are no unsigned pc-relative relocations"));
switch (size)
{
case 1: return BFD_RELOC_8_PCREL;
case 2: return BFD_RELOC_16_PCREL;
case 4: return (bnd_prefix && object_64bit
? BFD_RELOC_X86_64_PC32_BND
: BFD_RELOC_32_PCREL);
case 8: return BFD_RELOC_64_PCREL;
}
as_bad (_("cannot do %u byte pc-relative relocation"), size);
}
else
{
if (sign > 0)
switch (size)
{
case 4: return BFD_RELOC_X86_64_32S;
}
else
switch (size)
{
case 1: return BFD_RELOC_8;
case 2: return BFD_RELOC_16;
case 4: return BFD_RELOC_32;
case 8: return BFD_RELOC_64;
}
as_bad (_("cannot do %s %u byte relocation"),
sign > 0 ? "signed" : "unsigned", size);
}
 
return NO_RELOC;
}
 
/* Here we decide which fixups can be adjusted to make them relative to
the beginning of the section instead of the symbol. Basically we need
to make sure that the dynamic relocations are done correctly, so in
some cases we force the original symbol to be used. */
 
int
tc_i386_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED)
{
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
if (!IS_ELF)
return 1;
 
/* Don't adjust pc-relative references to merge sections in 64-bit
mode. */
if (use_rela_relocations
&& (S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) != 0
&& fixP->fx_pcrel)
return 0;
 
/* The x86_64 GOTPCREL are represented as 32bit PCrel relocations
and changed later by validate_fix. */
if (GOT_symbol && fixP->fx_subsy == GOT_symbol
&& fixP->fx_r_type == BFD_RELOC_32_PCREL)
return 0;
 
/* Adjust_reloc_syms doesn't know about the GOT. Need to keep symbol
for size relocations. */
if (fixP->fx_r_type == BFD_RELOC_SIZE32
|| fixP->fx_r_type == BFD_RELOC_SIZE64
|| fixP->fx_r_type == BFD_RELOC_386_GOTOFF
|| fixP->fx_r_type == BFD_RELOC_386_PLT32
|| fixP->fx_r_type == BFD_RELOC_386_GOT32
|| fixP->fx_r_type == BFD_RELOC_386_TLS_GD
|| fixP->fx_r_type == BFD_RELOC_386_TLS_LDM
|| fixP->fx_r_type == BFD_RELOC_386_TLS_LDO_32
|| fixP->fx_r_type == BFD_RELOC_386_TLS_IE_32
|| fixP->fx_r_type == BFD_RELOC_386_TLS_IE
|| fixP->fx_r_type == BFD_RELOC_386_TLS_GOTIE
|| fixP->fx_r_type == BFD_RELOC_386_TLS_LE_32
|| fixP->fx_r_type == BFD_RELOC_386_TLS_LE
|| fixP->fx_r_type == BFD_RELOC_386_TLS_GOTDESC
|| fixP->fx_r_type == BFD_RELOC_386_TLS_DESC_CALL
|| fixP->fx_r_type == BFD_RELOC_X86_64_PLT32
|| fixP->fx_r_type == BFD_RELOC_X86_64_GOT32
|| fixP->fx_r_type == BFD_RELOC_X86_64_GOTPCREL
|| fixP->fx_r_type == BFD_RELOC_X86_64_TLSGD
|| fixP->fx_r_type == BFD_RELOC_X86_64_TLSLD
|| fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF32
|| fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF64
|| fixP->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF
|| fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF32
|| fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF64
|| fixP->fx_r_type == BFD_RELOC_X86_64_GOTOFF64
|| fixP->fx_r_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC
|| fixP->fx_r_type == BFD_RELOC_X86_64_TLSDESC_CALL
|| fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
return 0;
#endif
return 1;
}
 
static int
intel_float_operand (const char *mnemonic)
{
/* Note that the value returned is meaningful only for opcodes with (memory)
operands, hence the code here is free to improperly handle opcodes that
have no operands (for better performance and smaller code). */
 
if (mnemonic[0] != 'f')
return 0; /* non-math */
 
switch (mnemonic[1])
{
/* fclex, fdecstp, fdisi, femms, feni, fincstp, finit, fsetpm, and
the fs segment override prefix not currently handled because no
call path can make opcodes without operands get here */
case 'i':
return 2 /* integer op */;
case 'l':
if (mnemonic[2] == 'd' && (mnemonic[3] == 'c' || mnemonic[3] == 'e'))
return 3; /* fldcw/fldenv */
break;
case 'n':
if (mnemonic[2] != 'o' /* fnop */)
return 3; /* non-waiting control op */
break;
case 'r':
if (mnemonic[2] == 's')
return 3; /* frstor/frstpm */
break;
case 's':
if (mnemonic[2] == 'a')
return 3; /* fsave */
if (mnemonic[2] == 't')
{
switch (mnemonic[3])
{
case 'c': /* fstcw */
case 'd': /* fstdw */
case 'e': /* fstenv */
case 's': /* fsts[gw] */
return 3;
}
}
break;
case 'x':
if (mnemonic[2] == 'r' || mnemonic[2] == 's')
return 0; /* fxsave/fxrstor are not really math ops */
break;
}
 
return 1;
}
 
/* Build the VEX prefix. */
 
static void
build_vex_prefix (const insn_template *t)
{
unsigned int register_specifier;
unsigned int implied_prefix;
unsigned int vector_length;
 
/* Check register specifier. */
if (i.vex.register_specifier)
{
register_specifier =
~register_number (i.vex.register_specifier) & 0xf;
gas_assert ((i.vex.register_specifier->reg_flags & RegVRex) == 0);
}
else
register_specifier = 0xf;
 
/* Use 2-byte VEX prefix by swappping destination and source
operand. */
if (!i.swap_operand
&& i.operands == i.reg_operands
&& i.tm.opcode_modifier.vexopcode == VEX0F
&& i.tm.opcode_modifier.s
&& i.rex == REX_B)
{
unsigned int xchg = i.operands - 1;
union i386_op temp_op;
i386_operand_type temp_type;
 
temp_type = i.types[xchg];
i.types[xchg] = i.types[0];
i.types[0] = temp_type;
temp_op = i.op[xchg];
i.op[xchg] = i.op[0];
i.op[0] = temp_op;
 
gas_assert (i.rm.mode == 3);
 
i.rex = REX_R;
xchg = i.rm.regmem;
i.rm.regmem = i.rm.reg;
i.rm.reg = xchg;
 
/* Use the next insn. */
i.tm = t[1];
}
 
if (i.tm.opcode_modifier.vex == VEXScalar)
vector_length = avxscalar;
else
vector_length = i.tm.opcode_modifier.vex == VEX256 ? 1 : 0;
 
switch ((i.tm.base_opcode >> 8) & 0xff)
{
case 0:
implied_prefix = 0;
break;
case DATA_PREFIX_OPCODE:
implied_prefix = 1;
break;
case REPE_PREFIX_OPCODE:
implied_prefix = 2;
break;
case REPNE_PREFIX_OPCODE:
implied_prefix = 3;
break;
default:
abort ();
}
 
/* Use 2-byte VEX prefix if possible. */
if (i.tm.opcode_modifier.vexopcode == VEX0F
&& i.tm.opcode_modifier.vexw != VEXW1
&& (i.rex & (REX_W | REX_X | REX_B)) == 0)
{
/* 2-byte VEX prefix. */
unsigned int r;
 
i.vex.length = 2;
i.vex.bytes[0] = 0xc5;
 
/* Check the REX.R bit. */
r = (i.rex & REX_R) ? 0 : 1;
i.vex.bytes[1] = (r << 7
| register_specifier << 3
| vector_length << 2
| implied_prefix);
}
else
{
/* 3-byte VEX prefix. */
unsigned int m, w;
 
i.vex.length = 3;
 
switch (i.tm.opcode_modifier.vexopcode)
{
case VEX0F:
m = 0x1;
i.vex.bytes[0] = 0xc4;
break;
case VEX0F38:
m = 0x2;
i.vex.bytes[0] = 0xc4;
break;
case VEX0F3A:
m = 0x3;
i.vex.bytes[0] = 0xc4;
break;
case XOP08:
m = 0x8;
i.vex.bytes[0] = 0x8f;
break;
case XOP09:
m = 0x9;
i.vex.bytes[0] = 0x8f;
break;
case XOP0A:
m = 0xa;
i.vex.bytes[0] = 0x8f;
break;
default:
abort ();
}
 
/* The high 3 bits of the second VEX byte are 1's compliment
of RXB bits from REX. */
i.vex.bytes[1] = (~i.rex & 0x7) << 5 | m;
 
/* Check the REX.W bit. */
w = (i.rex & REX_W) ? 1 : 0;
if (i.tm.opcode_modifier.vexw)
{
if (w)
abort ();
 
if (i.tm.opcode_modifier.vexw == VEXW1)
w = 1;
}
 
i.vex.bytes[2] = (w << 7
| register_specifier << 3
| vector_length << 2
| implied_prefix);
}
}
 
/* Build the EVEX prefix. */
 
static void
build_evex_prefix (void)
{
unsigned int register_specifier;
unsigned int implied_prefix;
unsigned int m, w;
rex_byte vrex_used = 0;
 
/* Check register specifier. */
if (i.vex.register_specifier)
{
gas_assert ((i.vrex & REX_X) == 0);
 
register_specifier = i.vex.register_specifier->reg_num;
if ((i.vex.register_specifier->reg_flags & RegRex))
register_specifier += 8;
/* The upper 16 registers are encoded in the fourth byte of the
EVEX prefix. */
if (!(i.vex.register_specifier->reg_flags & RegVRex))
i.vex.bytes[3] = 0x8;
register_specifier = ~register_specifier & 0xf;
}
else
{
register_specifier = 0xf;
 
/* Encode upper 16 vector index register in the fourth byte of
the EVEX prefix. */
if (!(i.vrex & REX_X))
i.vex.bytes[3] = 0x8;
else
vrex_used |= REX_X;
}
 
switch ((i.tm.base_opcode >> 8) & 0xff)
{
case 0:
implied_prefix = 0;
break;
case DATA_PREFIX_OPCODE:
implied_prefix = 1;
break;
case REPE_PREFIX_OPCODE:
implied_prefix = 2;
break;
case REPNE_PREFIX_OPCODE:
implied_prefix = 3;
break;
default:
abort ();
}
 
/* 4 byte EVEX prefix. */
i.vex.length = 4;
i.vex.bytes[0] = 0x62;
 
/* mmmm bits. */
switch (i.tm.opcode_modifier.vexopcode)
{
case VEX0F:
m = 1;
break;
case VEX0F38:
m = 2;
break;
case VEX0F3A:
m = 3;
break;
default:
abort ();
break;
}
 
/* The high 3 bits of the second EVEX byte are 1's compliment of RXB
bits from REX. */
i.vex.bytes[1] = (~i.rex & 0x7) << 5 | m;
 
/* The fifth bit of the second EVEX byte is 1's compliment of the
REX_R bit in VREX. */
if (!(i.vrex & REX_R))
i.vex.bytes[1] |= 0x10;
else
vrex_used |= REX_R;
 
if ((i.reg_operands + i.imm_operands) == i.operands)
{
/* When all operands are registers, the REX_X bit in REX is not
used. We reuse it to encode the upper 16 registers, which is
indicated by the REX_B bit in VREX. The REX_X bit is encoded
as 1's compliment. */
if ((i.vrex & REX_B))
{
vrex_used |= REX_B;
i.vex.bytes[1] &= ~0x40;
}
}
 
/* EVEX instructions shouldn't need the REX prefix. */
i.vrex &= ~vrex_used;
gas_assert (i.vrex == 0);
 
/* Check the REX.W bit. */
w = (i.rex & REX_W) ? 1 : 0;
if (i.tm.opcode_modifier.vexw)
{
if (i.tm.opcode_modifier.vexw == VEXW1)
w = 1;
}
/* If w is not set it means we are dealing with WIG instruction. */
else if (!w)
{
if (evexwig == evexw1)
w = 1;
}
 
/* Encode the U bit. */
implied_prefix |= 0x4;
 
/* The third byte of the EVEX prefix. */
i.vex.bytes[2] = (w << 7 | register_specifier << 3 | implied_prefix);
 
/* The fourth byte of the EVEX prefix. */
/* The zeroing-masking bit. */
if (i.mask && i.mask->zeroing)
i.vex.bytes[3] |= 0x80;
 
/* Don't always set the broadcast bit if there is no RC. */
if (!i.rounding)
{
/* Encode the vector length. */
unsigned int vec_length;
 
switch (i.tm.opcode_modifier.evex)
{
case EVEXLIG: /* LL' is ignored */
vec_length = evexlig << 5;
break;
case EVEX128:
vec_length = 0 << 5;
break;
case EVEX256:
vec_length = 1 << 5;
break;
case EVEX512:
vec_length = 2 << 5;
break;
default:
abort ();
break;
}
i.vex.bytes[3] |= vec_length;
/* Encode the broadcast bit. */
if (i.broadcast)
i.vex.bytes[3] |= 0x10;
}
else
{
if (i.rounding->type != saeonly)
i.vex.bytes[3] |= 0x10 | (i.rounding->type << 5);
else
i.vex.bytes[3] |= 0x10;
}
 
if (i.mask && i.mask->mask)
i.vex.bytes[3] |= i.mask->mask->reg_num;
}
 
static void
process_immext (void)
{
expressionS *exp;
 
if ((i.tm.cpu_flags.bitfield.cpusse3 || i.tm.cpu_flags.bitfield.cpusvme)
&& i.operands > 0)
{
/* MONITOR/MWAIT as well as SVME instructions have fixed operands
with an opcode suffix which is coded in the same place as an
8-bit immediate field would be.
Here we check those operands and remove them afterwards. */
unsigned int x;
 
for (x = 0; x < i.operands; x++)
if (register_number (i.op[x].regs) != x)
as_bad (_("can't use register '%s%s' as operand %d in '%s'."),
register_prefix, i.op[x].regs->reg_name, x + 1,
i.tm.name);
 
i.operands = 0;
}
 
/* These AMD 3DNow! and SSE2 instructions have an opcode suffix
which is coded in the same place as an 8-bit immediate field
would be. Here we fake an 8-bit immediate operand from the
opcode suffix stored in tm.extension_opcode.
 
AVX instructions also use this encoding, for some of
3 argument instructions. */
 
gas_assert (i.imm_operands <= 1
&& (i.operands <= 2
|| ((i.tm.opcode_modifier.vex
|| i.tm.opcode_modifier.evex)
&& i.operands <= 4)));
 
exp = &im_expressions[i.imm_operands++];
i.op[i.operands].imms = exp;
i.types[i.operands] = imm8;
i.operands++;
exp->X_op = O_constant;
exp->X_add_number = i.tm.extension_opcode;
i.tm.extension_opcode = None;
}
 
 
static int
check_hle (void)
{
switch (i.tm.opcode_modifier.hleprefixok)
{
default:
abort ();
case HLEPrefixNone:
as_bad (_("invalid instruction `%s' after `%s'"),
i.tm.name, i.hle_prefix);
return 0;
case HLEPrefixLock:
if (i.prefix[LOCK_PREFIX])
return 1;
as_bad (_("missing `lock' with `%s'"), i.hle_prefix);
return 0;
case HLEPrefixAny:
return 1;
case HLEPrefixRelease:
if (i.prefix[HLE_PREFIX] != XRELEASE_PREFIX_OPCODE)
{
as_bad (_("instruction `%s' after `xacquire' not allowed"),
i.tm.name);
return 0;
}
if (i.mem_operands == 0
|| !operand_type_check (i.types[i.operands - 1], anymem))
{
as_bad (_("memory destination needed for instruction `%s'"
" after `xrelease'"), i.tm.name);
return 0;
}
return 1;
}
}
 
/* This is the guts of the machine-dependent assembler. LINE points to a
machine dependent instruction. This function is supposed to emit
the frags/bytes it assembles to. */
 
void
md_assemble (char *line)
{
unsigned int j;
char mnemonic[MAX_MNEM_SIZE];
const insn_template *t;
 
/* Initialize globals. */
memset (&i, '\0', sizeof (i));
for (j = 0; j < MAX_OPERANDS; j++)
i.reloc[j] = NO_RELOC;
memset (disp_expressions, '\0', sizeof (disp_expressions));
memset (im_expressions, '\0', sizeof (im_expressions));
save_stack_p = save_stack;
 
/* First parse an instruction mnemonic & call i386_operand for the operands.
We assume that the scrubber has arranged it so that line[0] is the valid
start of a (possibly prefixed) mnemonic. */
 
line = parse_insn (line, mnemonic);
if (line == NULL)
return;
 
line = parse_operands (line, mnemonic);
this_operand = -1;
if (line == NULL)
return;
 
/* Now we've parsed the mnemonic into a set of templates, and have the
operands at hand. */
 
/* All intel opcodes have reversed operands except for "bound" and
"enter". We also don't reverse intersegment "jmp" and "call"
instructions with 2 immediate operands so that the immediate segment
precedes the offset, as it does when in AT&T mode. */
if (intel_syntax
&& i.operands > 1
&& (strcmp (mnemonic, "bound") != 0)
&& (strcmp (mnemonic, "invlpga") != 0)
&& !(operand_type_check (i.types[0], imm)
&& operand_type_check (i.types[1], imm)))
swap_operands ();
 
/* The order of the immediates should be reversed
for 2 immediates extrq and insertq instructions */
if (i.imm_operands == 2
&& (strcmp (mnemonic, "extrq") == 0
|| strcmp (mnemonic, "insertq") == 0))
swap_2_operands (0, 1);
 
if (i.imm_operands)
optimize_imm ();
 
/* Don't optimize displacement for movabs since it only takes 64bit
displacement. */
if (i.disp_operands
&& i.disp_encoding != disp_encoding_32bit
&& (flag_code != CODE_64BIT
|| strcmp (mnemonic, "movabs") != 0))
optimize_disp ();
 
/* Next, we find a template that matches the given insn,
making sure the overlap of the given operands types is consistent
with the template operand types. */
 
if (!(t = match_template ()))
return;
 
if (sse_check != check_none
&& !i.tm.opcode_modifier.noavx
&& (i.tm.cpu_flags.bitfield.cpusse
|| i.tm.cpu_flags.bitfield.cpusse2
|| i.tm.cpu_flags.bitfield.cpusse3
|| i.tm.cpu_flags.bitfield.cpussse3
|| i.tm.cpu_flags.bitfield.cpusse4_1
|| i.tm.cpu_flags.bitfield.cpusse4_2))
{
(sse_check == check_warning
? as_warn
: as_bad) (_("SSE instruction `%s' is used"), i.tm.name);
}
 
/* Zap movzx and movsx suffix. The suffix has been set from
"word ptr" or "byte ptr" on the source operand in Intel syntax
or extracted from mnemonic in AT&T syntax. But we'll use
the destination register to choose the suffix for encoding. */
if ((i.tm.base_opcode & ~9) == 0x0fb6)
{
/* In Intel syntax, there must be a suffix. In AT&T syntax, if
there is no suffix, the default will be byte extension. */
if (i.reg_operands != 2
&& !i.suffix
&& intel_syntax)
as_bad (_("ambiguous operand size for `%s'"), i.tm.name);
 
i.suffix = 0;
}
 
if (i.tm.opcode_modifier.fwait)
if (!add_prefix (FWAIT_OPCODE))
return;
 
/* Check if REP prefix is OK. */
if (i.rep_prefix && !i.tm.opcode_modifier.repprefixok)
{
as_bad (_("invalid instruction `%s' after `%s'"),
i.tm.name, i.rep_prefix);
return;
}
 
/* Check for lock without a lockable instruction. Destination operand
must be memory unless it is xchg (0x86). */
if (i.prefix[LOCK_PREFIX]
&& (!i.tm.opcode_modifier.islockable
|| i.mem_operands == 0
|| (i.tm.base_opcode != 0x86
&& !operand_type_check (i.types[i.operands - 1], anymem))))
{
as_bad (_("expecting lockable instruction after `lock'"));
return;
}
 
/* Check if HLE prefix is OK. */
if (i.hle_prefix && !check_hle ())
return;
 
/* Check BND prefix. */
if (i.bnd_prefix && !i.tm.opcode_modifier.bndprefixok)
as_bad (_("expecting valid branch instruction after `bnd'"));
 
if (i.tm.cpu_flags.bitfield.cpumpx
&& flag_code == CODE_64BIT
&& i.prefix[ADDR_PREFIX])
as_bad (_("32-bit address isn't allowed in 64-bit MPX instructions."));
 
/* Insert BND prefix. */
if (add_bnd_prefix
&& i.tm.opcode_modifier.bndprefixok
&& !i.prefix[BND_PREFIX])
add_prefix (BND_PREFIX_OPCODE);
 
/* Check string instruction segment overrides. */
if (i.tm.opcode_modifier.isstring && i.mem_operands != 0)
{
if (!check_string ())
return;
i.disp_operands = 0;
}
 
if (!process_suffix ())
return;
 
/* Update operand types. */
for (j = 0; j < i.operands; j++)
i.types[j] = operand_type_and (i.types[j], i.tm.operand_types[j]);
 
/* Make still unresolved immediate matches conform to size of immediate
given in i.suffix. */
if (!finalize_imm ())
return;
 
if (i.types[0].bitfield.imm1)
i.imm_operands = 0; /* kludge for shift insns. */
 
/* We only need to check those implicit registers for instructions
with 3 operands or less. */
if (i.operands <= 3)
for (j = 0; j < i.operands; j++)
if (i.types[j].bitfield.inoutportreg
|| i.types[j].bitfield.shiftcount
|| i.types[j].bitfield.acc
|| i.types[j].bitfield.floatacc)
i.reg_operands--;
 
/* ImmExt should be processed after SSE2AVX. */
if (!i.tm.opcode_modifier.sse2avx
&& i.tm.opcode_modifier.immext)
process_immext ();
 
/* For insns with operands there are more diddles to do to the opcode. */
if (i.operands)
{
if (!process_operands ())
return;
}
else if (!quiet_warnings && i.tm.opcode_modifier.ugh)
{
/* UnixWare fsub no args is alias for fsubp, fadd -> faddp, etc. */
as_warn (_("translating to `%sp'"), i.tm.name);
}
 
if (i.tm.opcode_modifier.vex)
build_vex_prefix (t);
 
if (i.tm.opcode_modifier.evex)
build_evex_prefix ();
 
/* Handle conversion of 'int $3' --> special int3 insn. XOP or FMA4
instructions may define INT_OPCODE as well, so avoid this corner
case for those instructions that use MODRM. */
if (i.tm.base_opcode == INT_OPCODE
&& !i.tm.opcode_modifier.modrm
&& i.op[0].imms->X_add_number == 3)
{
i.tm.base_opcode = INT3_OPCODE;
i.imm_operands = 0;
}
 
if ((i.tm.opcode_modifier.jump
|| i.tm.opcode_modifier.jumpbyte
|| i.tm.opcode_modifier.jumpdword)
&& i.op[0].disps->X_op == O_constant)
{
/* Convert "jmp constant" (and "call constant") to a jump (call) to
the absolute address given by the constant. Since ix86 jumps and
calls are pc relative, we need to generate a reloc. */
i.op[0].disps->X_add_symbol = &abs_symbol;
i.op[0].disps->X_op = O_symbol;
}
 
if (i.tm.opcode_modifier.rex64)
i.rex |= REX_W;
 
/* For 8 bit registers we need an empty rex prefix. Also if the
instruction already has a prefix, we need to convert old
registers to new ones. */
 
if ((i.types[0].bitfield.reg8
&& (i.op[0].regs->reg_flags & RegRex64) != 0)
|| (i.types[1].bitfield.reg8
&& (i.op[1].regs->reg_flags & RegRex64) != 0)
|| ((i.types[0].bitfield.reg8
|| i.types[1].bitfield.reg8)
&& i.rex != 0))
{
int x;
 
i.rex |= REX_OPCODE;
for (x = 0; x < 2; x++)
{
/* Look for 8 bit operand that uses old registers. */
if (i.types[x].bitfield.reg8
&& (i.op[x].regs->reg_flags & RegRex64) == 0)
{
/* In case it is "hi" register, give up. */
if (i.op[x].regs->reg_num > 3)
as_bad (_("can't encode register '%s%s' in an "
"instruction requiring REX prefix."),
register_prefix, i.op[x].regs->reg_name);
 
/* Otherwise it is equivalent to the extended register.
Since the encoding doesn't change this is merely
cosmetic cleanup for debug output. */
 
i.op[x].regs = i.op[x].regs + 8;
}
}
}
 
if (i.rex != 0)
add_prefix (REX_OPCODE | i.rex);
 
/* We are ready to output the insn. */
output_insn ();
}
 
static char *
parse_insn (char *line, char *mnemonic)
{
char *l = line;
char *token_start = l;
char *mnem_p;
int supported;
const insn_template *t;
char *dot_p = NULL;
 
while (1)
{
mnem_p = mnemonic;
while ((*mnem_p = mnemonic_chars[(unsigned char) *l]) != 0)
{
if (*mnem_p == '.')
dot_p = mnem_p;
mnem_p++;
if (mnem_p >= mnemonic + MAX_MNEM_SIZE)
{
as_bad (_("no such instruction: `%s'"), token_start);
return NULL;
}
l++;
}
if (!is_space_char (*l)
&& *l != END_OF_INSN
&& (intel_syntax
|| (*l != PREFIX_SEPARATOR
&& *l != ',')))
{
as_bad (_("invalid character %s in mnemonic"),
output_invalid (*l));
return NULL;
}
if (token_start == l)
{
if (!intel_syntax && *l == PREFIX_SEPARATOR)
as_bad (_("expecting prefix; got nothing"));
else
as_bad (_("expecting mnemonic; got nothing"));
return NULL;
}
 
/* Look up instruction (or prefix) via hash table. */
current_templates = (const templates *) hash_find (op_hash, mnemonic);
 
if (*l != END_OF_INSN
&& (!is_space_char (*l) || l[1] != END_OF_INSN)
&& current_templates
&& current_templates->start->opcode_modifier.isprefix)
{
if (!cpu_flags_check_cpu64 (current_templates->start->cpu_flags))
{
as_bad ((flag_code != CODE_64BIT
? _("`%s' is only supported in 64-bit mode")
: _("`%s' is not supported in 64-bit mode")),
current_templates->start->name);
return NULL;
}
/* If we are in 16-bit mode, do not allow addr16 or data16.
Similarly, in 32-bit mode, do not allow addr32 or data32. */
if ((current_templates->start->opcode_modifier.size16
|| current_templates->start->opcode_modifier.size32)
&& flag_code != CODE_64BIT
&& (current_templates->start->opcode_modifier.size32
^ (flag_code == CODE_16BIT)))
{
as_bad (_("redundant %s prefix"),
current_templates->start->name);
return NULL;
}
/* Add prefix, checking for repeated prefixes. */
switch (add_prefix (current_templates->start->base_opcode))
{
case PREFIX_EXIST:
return NULL;
case PREFIX_REP:
if (current_templates->start->cpu_flags.bitfield.cpuhle)
i.hle_prefix = current_templates->start->name;
else if (current_templates->start->cpu_flags.bitfield.cpumpx)
i.bnd_prefix = current_templates->start->name;
else
i.rep_prefix = current_templates->start->name;
break;
default:
break;
}
/* Skip past PREFIX_SEPARATOR and reset token_start. */
token_start = ++l;
}
else
break;
}
 
if (!current_templates)
{
/* Check if we should swap operand or force 32bit displacement in
encoding. */
if (mnem_p - 2 == dot_p && dot_p[1] == 's')
i.swap_operand = 1;
else if (mnem_p - 3 == dot_p
&& dot_p[1] == 'd'
&& dot_p[2] == '8')
i.disp_encoding = disp_encoding_8bit;
else if (mnem_p - 4 == dot_p
&& dot_p[1] == 'd'
&& dot_p[2] == '3'
&& dot_p[3] == '2')
i.disp_encoding = disp_encoding_32bit;
else
goto check_suffix;
mnem_p = dot_p;
*dot_p = '\0';
current_templates = (const templates *) hash_find (op_hash, mnemonic);
}
 
if (!current_templates)
{
check_suffix:
/* See if we can get a match by trimming off a suffix. */
switch (mnem_p[-1])
{
case WORD_MNEM_SUFFIX:
if (intel_syntax && (intel_float_operand (mnemonic) & 2))
i.suffix = SHORT_MNEM_SUFFIX;
else
case BYTE_MNEM_SUFFIX:
case QWORD_MNEM_SUFFIX:
i.suffix = mnem_p[-1];
mnem_p[-1] = '\0';
current_templates = (const templates *) hash_find (op_hash,
mnemonic);
break;
case SHORT_MNEM_SUFFIX:
case LONG_MNEM_SUFFIX:
if (!intel_syntax)
{
i.suffix = mnem_p[-1];
mnem_p[-1] = '\0';
current_templates = (const templates *) hash_find (op_hash,
mnemonic);
}
break;
 
/* Intel Syntax. */
case 'd':
if (intel_syntax)
{
if (intel_float_operand (mnemonic) == 1)
i.suffix = SHORT_MNEM_SUFFIX;
else
i.suffix = LONG_MNEM_SUFFIX;
mnem_p[-1] = '\0';
current_templates = (const templates *) hash_find (op_hash,
mnemonic);
}
break;
}
if (!current_templates)
{
as_bad (_("no such instruction: `%s'"), token_start);
return NULL;
}
}
 
if (current_templates->start->opcode_modifier.jump
|| current_templates->start->opcode_modifier.jumpbyte)
{
/* Check for a branch hint. We allow ",pt" and ",pn" for
predict taken and predict not taken respectively.
I'm not sure that branch hints actually do anything on loop
and jcxz insns (JumpByte) for current Pentium4 chips. They
may work in the future and it doesn't hurt to accept them
now. */
if (l[0] == ',' && l[1] == 'p')
{
if (l[2] == 't')
{
if (!add_prefix (DS_PREFIX_OPCODE))
return NULL;
l += 3;
}
else if (l[2] == 'n')
{
if (!add_prefix (CS_PREFIX_OPCODE))
return NULL;
l += 3;
}
}
}
/* Any other comma loses. */
if (*l == ',')
{
as_bad (_("invalid character %s in mnemonic"),
output_invalid (*l));
return NULL;
}
 
/* Check if instruction is supported on specified architecture. */
supported = 0;
for (t = current_templates->start; t < current_templates->end; ++t)
{
supported |= cpu_flags_match (t);
if (supported == CPU_FLAGS_PERFECT_MATCH)
goto skip;
}
 
if (!(supported & CPU_FLAGS_64BIT_MATCH))
{
as_bad (flag_code == CODE_64BIT
? _("`%s' is not supported in 64-bit mode")
: _("`%s' is only supported in 64-bit mode"),
current_templates->start->name);
return NULL;
}
if (supported != CPU_FLAGS_PERFECT_MATCH)
{
as_bad (_("`%s' is not supported on `%s%s'"),
current_templates->start->name,
cpu_arch_name ? cpu_arch_name : default_arch,
cpu_sub_arch_name ? cpu_sub_arch_name : "");
return NULL;
}
 
skip:
if (!cpu_arch_flags.bitfield.cpui386
&& (flag_code != CODE_16BIT))
{
as_warn (_("use .code16 to ensure correct addressing mode"));
}
 
return l;
}
 
static char *
parse_operands (char *l, const char *mnemonic)
{
char *token_start;
 
/* 1 if operand is pending after ','. */
unsigned int expecting_operand = 0;
 
/* Non-zero if operand parens not balanced. */
unsigned int paren_not_balanced;
 
while (*l != END_OF_INSN)
{
/* Skip optional white space before operand. */
if (is_space_char (*l))
++l;
if (!is_operand_char (*l) && *l != END_OF_INSN)
{
as_bad (_("invalid character %s before operand %d"),
output_invalid (*l),
i.operands + 1);
return NULL;
}
token_start = l; /* after white space */
paren_not_balanced = 0;
while (paren_not_balanced || *l != ',')
{
if (*l == END_OF_INSN)
{
if (paren_not_balanced)
{
if (!intel_syntax)
as_bad (_("unbalanced parenthesis in operand %d."),
i.operands + 1);
else
as_bad (_("unbalanced brackets in operand %d."),
i.operands + 1);
return NULL;
}
else
break; /* we are done */
}
else if (!is_operand_char (*l) && !is_space_char (*l))
{
as_bad (_("invalid character %s in operand %d"),
output_invalid (*l),
i.operands + 1);
return NULL;
}
if (!intel_syntax)
{
if (*l == '(')
++paren_not_balanced;
if (*l == ')')
--paren_not_balanced;
}
else
{
if (*l == '[')
++paren_not_balanced;
if (*l == ']')
--paren_not_balanced;
}
l++;
}
if (l != token_start)
{ /* Yes, we've read in another operand. */
unsigned int operand_ok;
this_operand = i.operands++;
i.types[this_operand].bitfield.unspecified = 1;
if (i.operands > MAX_OPERANDS)
{
as_bad (_("spurious operands; (%d operands/instruction max)"),
MAX_OPERANDS);
return NULL;
}
/* Now parse operand adding info to 'i' as we go along. */
END_STRING_AND_SAVE (l);
 
if (intel_syntax)
operand_ok =
i386_intel_operand (token_start,
intel_float_operand (mnemonic));
else
operand_ok = i386_att_operand (token_start);
 
RESTORE_END_STRING (l);
if (!operand_ok)
return NULL;
}
else
{
if (expecting_operand)
{
expecting_operand_after_comma:
as_bad (_("expecting operand after ','; got nothing"));
return NULL;
}
if (*l == ',')
{
as_bad (_("expecting operand before ','; got nothing"));
return NULL;
}
}
 
/* Now *l must be either ',' or END_OF_INSN. */
if (*l == ',')
{
if (*++l == END_OF_INSN)
{
/* Just skip it, if it's \n complain. */
goto expecting_operand_after_comma;
}
expecting_operand = 1;
}
}
return l;
}
 
static void
swap_2_operands (int xchg1, int xchg2)
{
union i386_op temp_op;
i386_operand_type temp_type;
enum bfd_reloc_code_real temp_reloc;
 
temp_type = i.types[xchg2];
i.types[xchg2] = i.types[xchg1];
i.types[xchg1] = temp_type;
temp_op = i.op[xchg2];
i.op[xchg2] = i.op[xchg1];
i.op[xchg1] = temp_op;
temp_reloc = i.reloc[xchg2];
i.reloc[xchg2] = i.reloc[xchg1];
i.reloc[xchg1] = temp_reloc;
 
if (i.mask)
{
if (i.mask->operand == xchg1)
i.mask->operand = xchg2;
else if (i.mask->operand == xchg2)
i.mask->operand = xchg1;
}
if (i.broadcast)
{
if (i.broadcast->operand == xchg1)
i.broadcast->operand = xchg2;
else if (i.broadcast->operand == xchg2)
i.broadcast->operand = xchg1;
}
if (i.rounding)
{
if (i.rounding->operand == xchg1)
i.rounding->operand = xchg2;
else if (i.rounding->operand == xchg2)
i.rounding->operand = xchg1;
}
}
 
static void
swap_operands (void)
{
switch (i.operands)
{
case 5:
case 4:
swap_2_operands (1, i.operands - 2);
case 3:
case 2:
swap_2_operands (0, i.operands - 1);
break;
default:
abort ();
}
 
if (i.mem_operands == 2)
{
const seg_entry *temp_seg;
temp_seg = i.seg[0];
i.seg[0] = i.seg[1];
i.seg[1] = temp_seg;
}
}
 
/* Try to ensure constant immediates are represented in the smallest
opcode possible. */
static void
optimize_imm (void)
{
char guess_suffix = 0;
int op;
 
if (i.suffix)
guess_suffix = i.suffix;
else if (i.reg_operands)
{
/* Figure out a suffix from the last register operand specified.
We can't do this properly yet, ie. excluding InOutPortReg,
but the following works for instructions with immediates.
In any case, we can't set i.suffix yet. */
for (op = i.operands; --op >= 0;)
if (i.types[op].bitfield.reg8)
{
guess_suffix = BYTE_MNEM_SUFFIX;
break;
}
else if (i.types[op].bitfield.reg16)
{
guess_suffix = WORD_MNEM_SUFFIX;
break;
}
else if (i.types[op].bitfield.reg32)
{
guess_suffix = LONG_MNEM_SUFFIX;
break;
}
else if (i.types[op].bitfield.reg64)
{
guess_suffix = QWORD_MNEM_SUFFIX;
break;
}
}
else if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0))
guess_suffix = WORD_MNEM_SUFFIX;
 
for (op = i.operands; --op >= 0;)
if (operand_type_check (i.types[op], imm))
{
switch (i.op[op].imms->X_op)
{
case O_constant:
/* If a suffix is given, this operand may be shortened. */
switch (guess_suffix)
{
case LONG_MNEM_SUFFIX:
i.types[op].bitfield.imm32 = 1;
i.types[op].bitfield.imm64 = 1;
break;
case WORD_MNEM_SUFFIX:
i.types[op].bitfield.imm16 = 1;
i.types[op].bitfield.imm32 = 1;
i.types[op].bitfield.imm32s = 1;
i.types[op].bitfield.imm64 = 1;
break;
case BYTE_MNEM_SUFFIX:
i.types[op].bitfield.imm8 = 1;
i.types[op].bitfield.imm8s = 1;
i.types[op].bitfield.imm16 = 1;
i.types[op].bitfield.imm32 = 1;
i.types[op].bitfield.imm32s = 1;
i.types[op].bitfield.imm64 = 1;
break;
}
 
/* If this operand is at most 16 bits, convert it
to a signed 16 bit number before trying to see
whether it will fit in an even smaller size.
This allows a 16-bit operand such as $0xffe0 to
be recognised as within Imm8S range. */
if ((i.types[op].bitfield.imm16)
&& (i.op[op].imms->X_add_number & ~(offsetT) 0xffff) == 0)
{
i.op[op].imms->X_add_number =
(((i.op[op].imms->X_add_number & 0xffff) ^ 0x8000) - 0x8000);
}
if ((i.types[op].bitfield.imm32)
&& ((i.op[op].imms->X_add_number & ~(((offsetT) 2 << 31) - 1))
== 0))
{
i.op[op].imms->X_add_number = ((i.op[op].imms->X_add_number
^ ((offsetT) 1 << 31))
- ((offsetT) 1 << 31));
}
i.types[op]
= operand_type_or (i.types[op],
smallest_imm_type (i.op[op].imms->X_add_number));
 
/* We must avoid matching of Imm32 templates when 64bit
only immediate is available. */
if (guess_suffix == QWORD_MNEM_SUFFIX)
i.types[op].bitfield.imm32 = 0;
break;
 
case O_absent:
case O_register:
abort ();
 
/* Symbols and expressions. */
default:
/* Convert symbolic operand to proper sizes for matching, but don't
prevent matching a set of insns that only supports sizes other
than those matching the insn suffix. */
{
i386_operand_type mask, allowed;
const insn_template *t;
 
operand_type_set (&mask, 0);
operand_type_set (&allowed, 0);
 
for (t = current_templates->start;
t < current_templates->end;
++t)
allowed = operand_type_or (allowed,
t->operand_types[op]);
switch (guess_suffix)
{
case QWORD_MNEM_SUFFIX:
mask.bitfield.imm64 = 1;
mask.bitfield.imm32s = 1;
break;
case LONG_MNEM_SUFFIX:
mask.bitfield.imm32 = 1;
break;
case WORD_MNEM_SUFFIX:
mask.bitfield.imm16 = 1;
break;
case BYTE_MNEM_SUFFIX:
mask.bitfield.imm8 = 1;
break;
default:
break;
}
allowed = operand_type_and (mask, allowed);
if (!operand_type_all_zero (&allowed))
i.types[op] = operand_type_and (i.types[op], mask);
}
break;
}
}
}
 
/* Try to use the smallest displacement type too. */
static void
optimize_disp (void)
{
int op;
 
for (op = i.operands; --op >= 0;)
if (operand_type_check (i.types[op], disp))
{
if (i.op[op].disps->X_op == O_constant)
{
offsetT op_disp = i.op[op].disps->X_add_number;
 
if (i.types[op].bitfield.disp16
&& (op_disp & ~(offsetT) 0xffff) == 0)
{
/* If this operand is at most 16 bits, convert
to a signed 16 bit number and don't use 64bit
displacement. */
op_disp = (((op_disp & 0xffff) ^ 0x8000) - 0x8000);
i.types[op].bitfield.disp64 = 0;
}
if (i.types[op].bitfield.disp32
&& (op_disp & ~(((offsetT) 2 << 31) - 1)) == 0)
{
/* If this operand is at most 32 bits, convert
to a signed 32 bit number and don't use 64bit
displacement. */
op_disp &= (((offsetT) 2 << 31) - 1);
op_disp = (op_disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31);
i.types[op].bitfield.disp64 = 0;
}
if (!op_disp && i.types[op].bitfield.baseindex)
{
i.types[op].bitfield.disp8 = 0;
i.types[op].bitfield.disp16 = 0;
i.types[op].bitfield.disp32 = 0;
i.types[op].bitfield.disp32s = 0;
i.types[op].bitfield.disp64 = 0;
i.op[op].disps = 0;
i.disp_operands--;
}
else if (flag_code == CODE_64BIT)
{
if (fits_in_signed_long (op_disp))
{
i.types[op].bitfield.disp64 = 0;
i.types[op].bitfield.disp32s = 1;
}
if (i.prefix[ADDR_PREFIX]
&& fits_in_unsigned_long (op_disp))
i.types[op].bitfield.disp32 = 1;
}
if ((i.types[op].bitfield.disp32
|| i.types[op].bitfield.disp32s
|| i.types[op].bitfield.disp16)
&& fits_in_signed_byte (op_disp))
i.types[op].bitfield.disp8 = 1;
}
else if (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL
|| i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL)
{
fix_new_exp (frag_now, frag_more (0) - frag_now->fr_literal, 0,
i.op[op].disps, 0, i.reloc[op]);
i.types[op].bitfield.disp8 = 0;
i.types[op].bitfield.disp16 = 0;
i.types[op].bitfield.disp32 = 0;
i.types[op].bitfield.disp32s = 0;
i.types[op].bitfield.disp64 = 0;
}
else
/* We only support 64bit displacement on constants. */
i.types[op].bitfield.disp64 = 0;
}
}
 
/* Check if operands are valid for the instruction. */
 
static int
check_VecOperands (const insn_template *t)
{
unsigned int op;
 
/* Without VSIB byte, we can't have a vector register for index. */
if (!t->opcode_modifier.vecsib
&& i.index_reg
&& (i.index_reg->reg_type.bitfield.regxmm
|| i.index_reg->reg_type.bitfield.regymm
|| i.index_reg->reg_type.bitfield.regzmm))
{
i.error = unsupported_vector_index_register;
return 1;
}
 
/* Check if default mask is allowed. */
if (t->opcode_modifier.nodefmask
&& (!i.mask || i.mask->mask->reg_num == 0))
{
i.error = no_default_mask;
return 1;
}
 
/* For VSIB byte, we need a vector register for index, and all vector
registers must be distinct. */
if (t->opcode_modifier.vecsib)
{
if (!i.index_reg
|| !((t->opcode_modifier.vecsib == VecSIB128
&& i.index_reg->reg_type.bitfield.regxmm)
|| (t->opcode_modifier.vecsib == VecSIB256
&& i.index_reg->reg_type.bitfield.regymm)
|| (t->opcode_modifier.vecsib == VecSIB512
&& i.index_reg->reg_type.bitfield.regzmm)))
{
i.error = invalid_vsib_address;
return 1;
}
 
gas_assert (i.reg_operands == 2 || i.mask);
if (i.reg_operands == 2 && !i.mask)
{
gas_assert (i.types[0].bitfield.regxmm
|| i.types[0].bitfield.regymm
|| i.types[0].bitfield.regzmm);
gas_assert (i.types[2].bitfield.regxmm
|| i.types[2].bitfield.regymm
|| i.types[2].bitfield.regzmm);
if (operand_check == check_none)
return 0;
if (register_number (i.op[0].regs)
!= register_number (i.index_reg)
&& register_number (i.op[2].regs)
!= register_number (i.index_reg)
&& register_number (i.op[0].regs)
!= register_number (i.op[2].regs))
return 0;
if (operand_check == check_error)
{
i.error = invalid_vector_register_set;
return 1;
}
as_warn (_("mask, index, and destination registers should be distinct"));
}
}
 
/* Check if broadcast is supported by the instruction and is applied
to the memory operand. */
if (i.broadcast)
{
int broadcasted_opnd_size;
 
/* Check if specified broadcast is supported in this instruction,
and it's applied to memory operand of DWORD or QWORD type,
depending on VecESize. */
if (i.broadcast->type != t->opcode_modifier.broadcast
|| !i.types[i.broadcast->operand].bitfield.mem
|| (t->opcode_modifier.vecesize == 0
&& !i.types[i.broadcast->operand].bitfield.dword
&& !i.types[i.broadcast->operand].bitfield.unspecified)
|| (t->opcode_modifier.vecesize == 1
&& !i.types[i.broadcast->operand].bitfield.qword
&& !i.types[i.broadcast->operand].bitfield.unspecified))
goto bad_broadcast;
 
broadcasted_opnd_size = t->opcode_modifier.vecesize ? 64 : 32;
if (i.broadcast->type == BROADCAST_1TO16)
broadcasted_opnd_size <<= 4; /* Broadcast 1to16. */
else if (i.broadcast->type == BROADCAST_1TO8)
broadcasted_opnd_size <<= 3; /* Broadcast 1to8. */
else
goto bad_broadcast;
 
if ((broadcasted_opnd_size == 256
&& !t->operand_types[i.broadcast->operand].bitfield.ymmword)
|| (broadcasted_opnd_size == 512
&& !t->operand_types[i.broadcast->operand].bitfield.zmmword))
{
bad_broadcast:
i.error = unsupported_broadcast;
return 1;
}
}
/* If broadcast is supported in this instruction, we need to check if
operand of one-element size isn't specified without broadcast. */
else if (t->opcode_modifier.broadcast && i.mem_operands)
{
/* Find memory operand. */
for (op = 0; op < i.operands; op++)
if (operand_type_check (i.types[op], anymem))
break;
gas_assert (op < i.operands);
/* Check size of the memory operand. */
if ((t->opcode_modifier.vecesize == 0
&& i.types[op].bitfield.dword)
|| (t->opcode_modifier.vecesize == 1
&& i.types[op].bitfield.qword))
{
i.error = broadcast_needed;
return 1;
}
}
 
/* Check if requested masking is supported. */
if (i.mask
&& (!t->opcode_modifier.masking
|| (i.mask->zeroing
&& t->opcode_modifier.masking == MERGING_MASKING)))
{
i.error = unsupported_masking;
return 1;
}
 
/* Check if masking is applied to dest operand. */
if (i.mask && (i.mask->operand != (int) (i.operands - 1)))
{
i.error = mask_not_on_destination;
return 1;
}
 
/* Check RC/SAE. */
if (i.rounding)
{
if ((i.rounding->type != saeonly
&& !t->opcode_modifier.staticrounding)
|| (i.rounding->type == saeonly
&& (t->opcode_modifier.staticrounding
|| !t->opcode_modifier.sae)))
{
i.error = unsupported_rc_sae;
return 1;
}
/* If the instruction has several immediate operands and one of
them is rounding, the rounding operand should be the last
immediate operand. */
if (i.imm_operands > 1
&& i.rounding->operand != (int) (i.imm_operands - 1))
{
i.error = rc_sae_operand_not_last_imm;
return 1;
}
}
 
/* Check vector Disp8 operand. */
if (t->opcode_modifier.disp8memshift)
{
if (i.broadcast)
i.memshift = t->opcode_modifier.vecesize ? 3 : 2;
else
i.memshift = t->opcode_modifier.disp8memshift;
 
for (op = 0; op < i.operands; op++)
if (operand_type_check (i.types[op], disp)
&& i.op[op].disps->X_op == O_constant)
{
offsetT value = i.op[op].disps->X_add_number;
int vec_disp8_ok = fits_in_vec_disp8 (value);
if (t->operand_types [op].bitfield.vec_disp8)
{
if (vec_disp8_ok)
i.types[op].bitfield.vec_disp8 = 1;
else
{
/* Vector insn can only have Vec_Disp8/Disp32 in
32/64bit modes, and Vec_Disp8/Disp16 in 16bit
mode. */
i.types[op].bitfield.disp8 = 0;
if (flag_code != CODE_16BIT)
i.types[op].bitfield.disp16 = 0;
}
}
else if (flag_code != CODE_16BIT)
{
/* One form of this instruction supports vector Disp8.
Try vector Disp8 if we need to use Disp32. */
if (vec_disp8_ok && !fits_in_signed_byte (value))
{
i.error = try_vector_disp8;
return 1;
}
}
}
}
else
i.memshift = -1;
 
return 0;
}
 
/* Check if operands are valid for the instruction. Update VEX
operand types. */
 
static int
VEX_check_operands (const insn_template *t)
{
/* VREX is only valid with EVEX prefix. */
if (i.need_vrex && !t->opcode_modifier.evex)
{
i.error = invalid_register_operand;
return 1;
}
 
if (!t->opcode_modifier.vex)
return 0;
 
/* Only check VEX_Imm4, which must be the first operand. */
if (t->operand_types[0].bitfield.vec_imm4)
{
if (i.op[0].imms->X_op != O_constant
|| !fits_in_imm4 (i.op[0].imms->X_add_number))
{
i.error = bad_imm4;
return 1;
}
 
/* Turn off Imm8 so that update_imm won't complain. */
i.types[0] = vec_imm4;
}
 
return 0;
}
 
static const insn_template *
match_template (void)
{
/* Points to template once we've found it. */
const insn_template *t;
i386_operand_type overlap0, overlap1, overlap2, overlap3;
i386_operand_type overlap4;
unsigned int found_reverse_match;
i386_opcode_modifier suffix_check;
i386_operand_type operand_types [MAX_OPERANDS];
int addr_prefix_disp;
unsigned int j;
unsigned int found_cpu_match;
unsigned int check_register;
enum i386_error specific_error = 0;
 
#if MAX_OPERANDS != 5
# error "MAX_OPERANDS must be 5."
#endif
 
found_reverse_match = 0;
addr_prefix_disp = -1;
 
memset (&suffix_check, 0, sizeof (suffix_check));
if (i.suffix == BYTE_MNEM_SUFFIX)
suffix_check.no_bsuf = 1;
else if (i.suffix == WORD_MNEM_SUFFIX)
suffix_check.no_wsuf = 1;
else if (i.suffix == SHORT_MNEM_SUFFIX)
suffix_check.no_ssuf = 1;
else if (i.suffix == LONG_MNEM_SUFFIX)
suffix_check.no_lsuf = 1;
else if (i.suffix == QWORD_MNEM_SUFFIX)
suffix_check.no_qsuf = 1;
else if (i.suffix == LONG_DOUBLE_MNEM_SUFFIX)
suffix_check.no_ldsuf = 1;
 
/* Must have right number of operands. */
i.error = number_of_operands_mismatch;
 
for (t = current_templates->start; t < current_templates->end; t++)
{
addr_prefix_disp = -1;
 
if (i.operands != t->operands)
continue;
 
/* Check processor support. */
i.error = unsupported;
found_cpu_match = (cpu_flags_match (t)
== CPU_FLAGS_PERFECT_MATCH);
if (!found_cpu_match)
continue;
 
/* Check old gcc support. */
i.error = old_gcc_only;
if (!old_gcc && t->opcode_modifier.oldgcc)
continue;
 
/* Check AT&T mnemonic. */
i.error = unsupported_with_intel_mnemonic;
if (intel_mnemonic && t->opcode_modifier.attmnemonic)
continue;
 
/* Check AT&T/Intel syntax. */
i.error = unsupported_syntax;
if ((intel_syntax && t->opcode_modifier.attsyntax)
|| (!intel_syntax && t->opcode_modifier.intelsyntax))
continue;
 
/* Check the suffix, except for some instructions in intel mode. */
i.error = invalid_instruction_suffix;
if ((!intel_syntax || !t->opcode_modifier.ignoresize)
&& ((t->opcode_modifier.no_bsuf && suffix_check.no_bsuf)
|| (t->opcode_modifier.no_wsuf && suffix_check.no_wsuf)
|| (t->opcode_modifier.no_lsuf && suffix_check.no_lsuf)
|| (t->opcode_modifier.no_ssuf && suffix_check.no_ssuf)
|| (t->opcode_modifier.no_qsuf && suffix_check.no_qsuf)
|| (t->opcode_modifier.no_ldsuf && suffix_check.no_ldsuf)))
continue;
 
if (!operand_size_match (t))
continue;
 
for (j = 0; j < MAX_OPERANDS; j++)
operand_types[j] = t->operand_types[j];
 
/* In general, don't allow 64-bit operands in 32-bit mode. */
if (i.suffix == QWORD_MNEM_SUFFIX
&& flag_code != CODE_64BIT
&& (intel_syntax
? (!t->opcode_modifier.ignoresize
&& !intel_float_operand (t->name))
: intel_float_operand (t->name) != 2)
&& ((!operand_types[0].bitfield.regmmx
&& !operand_types[0].bitfield.regxmm
&& !operand_types[0].bitfield.regymm
&& !operand_types[0].bitfield.regzmm)
|| (!operand_types[t->operands > 1].bitfield.regmmx
&& !!operand_types[t->operands > 1].bitfield.regxmm
&& !!operand_types[t->operands > 1].bitfield.regymm
&& !!operand_types[t->operands > 1].bitfield.regzmm))
&& (t->base_opcode != 0x0fc7
|| t->extension_opcode != 1 /* cmpxchg8b */))
continue;
 
/* In general, don't allow 32-bit operands on pre-386. */
else if (i.suffix == LONG_MNEM_SUFFIX
&& !cpu_arch_flags.bitfield.cpui386
&& (intel_syntax
? (!t->opcode_modifier.ignoresize
&& !intel_float_operand (t->name))
: intel_float_operand (t->name) != 2)
&& ((!operand_types[0].bitfield.regmmx
&& !operand_types[0].bitfield.regxmm)
|| (!operand_types[t->operands > 1].bitfield.regmmx
&& !!operand_types[t->operands > 1].bitfield.regxmm)))
continue;
 
/* Do not verify operands when there are none. */
else
{
if (!t->operands)
/* We've found a match; break out of loop. */
break;
}
 
/* Address size prefix will turn Disp64/Disp32/Disp16 operand
into Disp32/Disp16/Disp32 operand. */
if (i.prefix[ADDR_PREFIX] != 0)
{
/* There should be only one Disp operand. */
switch (flag_code)
{
case CODE_16BIT:
for (j = 0; j < MAX_OPERANDS; j++)
{
if (operand_types[j].bitfield.disp16)
{
addr_prefix_disp = j;
operand_types[j].bitfield.disp32 = 1;
operand_types[j].bitfield.disp16 = 0;
break;
}
}
break;
case CODE_32BIT:
for (j = 0; j < MAX_OPERANDS; j++)
{
if (operand_types[j].bitfield.disp32)
{
addr_prefix_disp = j;
operand_types[j].bitfield.disp32 = 0;
operand_types[j].bitfield.disp16 = 1;
break;
}
}
break;
case CODE_64BIT:
for (j = 0; j < MAX_OPERANDS; j++)
{
if (operand_types[j].bitfield.disp64)
{
addr_prefix_disp = j;
operand_types[j].bitfield.disp64 = 0;
operand_types[j].bitfield.disp32 = 1;
break;
}
}
break;
}
}
 
/* We check register size if needed. */
check_register = t->opcode_modifier.checkregsize;
overlap0 = operand_type_and (i.types[0], operand_types[0]);
switch (t->operands)
{
case 1:
if (!operand_type_match (overlap0, i.types[0]))
continue;
break;
case 2:
/* xchg %eax, %eax is a special case. It is an aliase for nop
only in 32bit mode and we can use opcode 0x90. In 64bit
mode, we can't use 0x90 for xchg %eax, %eax since it should
zero-extend %eax to %rax. */
if (flag_code == CODE_64BIT
&& t->base_opcode == 0x90
&& operand_type_equal (&i.types [0], &acc32)
&& operand_type_equal (&i.types [1], &acc32))
continue;
if (i.swap_operand)
{
/* If we swap operand in encoding, we either match
the next one or reverse direction of operands. */
if (t->opcode_modifier.s)
continue;
else if (t->opcode_modifier.d)
goto check_reverse;
}
 
case 3:
/* If we swap operand in encoding, we match the next one. */
if (i.swap_operand && t->opcode_modifier.s)
continue;
case 4:
case 5:
overlap1 = operand_type_and (i.types[1], operand_types[1]);
if (!operand_type_match (overlap0, i.types[0])
|| !operand_type_match (overlap1, i.types[1])
|| (check_register
&& !operand_type_register_match (overlap0, i.types[0],
operand_types[0],
overlap1, i.types[1],
operand_types[1])))
{
/* Check if other direction is valid ... */
if (!t->opcode_modifier.d && !t->opcode_modifier.floatd)
continue;
 
check_reverse:
/* Try reversing direction of operands. */
overlap0 = operand_type_and (i.types[0], operand_types[1]);
overlap1 = operand_type_and (i.types[1], operand_types[0]);
if (!operand_type_match (overlap0, i.types[0])
|| !operand_type_match (overlap1, i.types[1])
|| (check_register
&& !operand_type_register_match (overlap0,
i.types[0],
operand_types[1],
overlap1,
i.types[1],
operand_types[0])))
{
/* Does not match either direction. */
continue;
}
/* found_reverse_match holds which of D or FloatDR
we've found. */
if (t->opcode_modifier.d)
found_reverse_match = Opcode_D;
else if (t->opcode_modifier.floatd)
found_reverse_match = Opcode_FloatD;
else
found_reverse_match = 0;
if (t->opcode_modifier.floatr)
found_reverse_match |= Opcode_FloatR;
}
else
{
/* Found a forward 2 operand match here. */
switch (t->operands)
{
case 5:
overlap4 = operand_type_and (i.types[4],
operand_types[4]);
case 4:
overlap3 = operand_type_and (i.types[3],
operand_types[3]);
case 3:
overlap2 = operand_type_and (i.types[2],
operand_types[2]);
break;
}
 
switch (t->operands)
{
case 5:
if (!operand_type_match (overlap4, i.types[4])
|| !operand_type_register_match (overlap3,
i.types[3],
operand_types[3],
overlap4,
i.types[4],
operand_types[4]))
continue;
case 4:
if (!operand_type_match (overlap3, i.types[3])
|| (check_register
&& !operand_type_register_match (overlap2,
i.types[2],
operand_types[2],
overlap3,
i.types[3],
operand_types[3])))
continue;
case 3:
/* Here we make use of the fact that there are no
reverse match 3 operand instructions, and all 3
operand instructions only need to be checked for
register consistency between operands 2 and 3. */
if (!operand_type_match (overlap2, i.types[2])
|| (check_register
&& !operand_type_register_match (overlap1,
i.types[1],
operand_types[1],
overlap2,
i.types[2],
operand_types[2])))
continue;
break;
}
}
/* Found either forward/reverse 2, 3 or 4 operand match here:
slip through to break. */
}
if (!found_cpu_match)
{
found_reverse_match = 0;
continue;
}
 
/* Check if vector and VEX operands are valid. */
if (check_VecOperands (t) || VEX_check_operands (t))
{
specific_error = i.error;
continue;
}
 
/* We've found a match; break out of loop. */
break;
}
 
if (t == current_templates->end)
{
/* We found no match. */
const char *err_msg;
switch (specific_error ? specific_error : i.error)
{
default:
abort ();
case operand_size_mismatch:
err_msg = _("operand size mismatch");
break;
case operand_type_mismatch:
err_msg = _("operand type mismatch");
break;
case register_type_mismatch:
err_msg = _("register type mismatch");
break;
case number_of_operands_mismatch:
err_msg = _("number of operands mismatch");
break;
case invalid_instruction_suffix:
err_msg = _("invalid instruction suffix");
break;
case bad_imm4:
err_msg = _("constant doesn't fit in 4 bits");
break;
case old_gcc_only:
err_msg = _("only supported with old gcc");
break;
case unsupported_with_intel_mnemonic:
err_msg = _("unsupported with Intel mnemonic");
break;
case unsupported_syntax:
err_msg = _("unsupported syntax");
break;
case unsupported:
as_bad (_("unsupported instruction `%s'"),
current_templates->start->name);
return NULL;
case invalid_vsib_address:
err_msg = _("invalid VSIB address");
break;
case invalid_vector_register_set:
err_msg = _("mask, index, and destination registers must be distinct");
break;
case unsupported_vector_index_register:
err_msg = _("unsupported vector index register");
break;
case unsupported_broadcast:
err_msg = _("unsupported broadcast");
break;
case broadcast_not_on_src_operand:
err_msg = _("broadcast not on source memory operand");
break;
case broadcast_needed:
err_msg = _("broadcast is needed for operand of such type");
break;
case unsupported_masking:
err_msg = _("unsupported masking");
break;
case mask_not_on_destination:
err_msg = _("mask not on destination operand");
break;
case no_default_mask:
err_msg = _("default mask isn't allowed");
break;
case unsupported_rc_sae:
err_msg = _("unsupported static rounding/sae");
break;
case rc_sae_operand_not_last_imm:
if (intel_syntax)
err_msg = _("RC/SAE operand must precede immediate operands");
else
err_msg = _("RC/SAE operand must follow immediate operands");
break;
case invalid_register_operand:
err_msg = _("invalid register operand");
break;
}
as_bad (_("%s for `%s'"), err_msg,
current_templates->start->name);
return NULL;
}
 
if (!quiet_warnings)
{
if (!intel_syntax
&& (i.types[0].bitfield.jumpabsolute
!= operand_types[0].bitfield.jumpabsolute))
{
as_warn (_("indirect %s without `*'"), t->name);
}
 
if (t->opcode_modifier.isprefix
&& t->opcode_modifier.ignoresize)
{
/* Warn them that a data or address size prefix doesn't
affect assembly of the next line of code. */
as_warn (_("stand-alone `%s' prefix"), t->name);
}
}
 
/* Copy the template we found. */
i.tm = *t;
 
if (addr_prefix_disp != -1)
i.tm.operand_types[addr_prefix_disp]
= operand_types[addr_prefix_disp];
 
if (found_reverse_match)
{
/* If we found a reverse match we must alter the opcode
direction bit. found_reverse_match holds bits to change
(different for int & float insns). */
 
i.tm.base_opcode ^= found_reverse_match;
 
i.tm.operand_types[0] = operand_types[1];
i.tm.operand_types[1] = operand_types[0];
}
 
return t;
}
 
static int
check_string (void)
{
int mem_op = operand_type_check (i.types[0], anymem) ? 0 : 1;
if (i.tm.operand_types[mem_op].bitfield.esseg)
{
if (i.seg[0] != NULL && i.seg[0] != &es)
{
as_bad (_("`%s' operand %d must use `%ses' segment"),
i.tm.name,
mem_op + 1,
register_prefix);
return 0;
}
/* There's only ever one segment override allowed per instruction.
This instruction possibly has a legal segment override on the
second operand, so copy the segment to where non-string
instructions store it, allowing common code. */
i.seg[0] = i.seg[1];
}
else if (i.tm.operand_types[mem_op + 1].bitfield.esseg)
{
if (i.seg[1] != NULL && i.seg[1] != &es)
{
as_bad (_("`%s' operand %d must use `%ses' segment"),
i.tm.name,
mem_op + 2,
register_prefix);
return 0;
}
}
return 1;
}
 
static int
process_suffix (void)
{
/* If matched instruction specifies an explicit instruction mnemonic
suffix, use it. */
if (i.tm.opcode_modifier.size16)
i.suffix = WORD_MNEM_SUFFIX;
else if (i.tm.opcode_modifier.size32)
i.suffix = LONG_MNEM_SUFFIX;
else if (i.tm.opcode_modifier.size64)
i.suffix = QWORD_MNEM_SUFFIX;
else if (i.reg_operands)
{
/* If there's no instruction mnemonic suffix we try to invent one
based on register operands. */
if (!i.suffix)
{
/* We take i.suffix from the last register operand specified,
Destination register type is more significant than source
register type. crc32 in SSE4.2 prefers source register
type. */
if (i.tm.base_opcode == 0xf20f38f1)
{
if (i.types[0].bitfield.reg16)
i.suffix = WORD_MNEM_SUFFIX;
else if (i.types[0].bitfield.reg32)
i.suffix = LONG_MNEM_SUFFIX;
else if (i.types[0].bitfield.reg64)
i.suffix = QWORD_MNEM_SUFFIX;
}
else if (i.tm.base_opcode == 0xf20f38f0)
{
if (i.types[0].bitfield.reg8)
i.suffix = BYTE_MNEM_SUFFIX;
}
 
if (!i.suffix)
{
int op;
 
if (i.tm.base_opcode == 0xf20f38f1
|| i.tm.base_opcode == 0xf20f38f0)
{
/* We have to know the operand size for crc32. */
as_bad (_("ambiguous memory operand size for `%s`"),
i.tm.name);
return 0;
}
 
for (op = i.operands; --op >= 0;)
if (!i.tm.operand_types[op].bitfield.inoutportreg)
{
if (i.types[op].bitfield.reg8)
{
i.suffix = BYTE_MNEM_SUFFIX;
break;
}
else if (i.types[op].bitfield.reg16)
{
i.suffix = WORD_MNEM_SUFFIX;
break;
}
else if (i.types[op].bitfield.reg32)
{
i.suffix = LONG_MNEM_SUFFIX;
break;
}
else if (i.types[op].bitfield.reg64)
{
i.suffix = QWORD_MNEM_SUFFIX;
break;
}
}
}
}
else if (i.suffix == BYTE_MNEM_SUFFIX)
{
if (intel_syntax
&& i.tm.opcode_modifier.ignoresize
&& i.tm.opcode_modifier.no_bsuf)
i.suffix = 0;
else if (!check_byte_reg ())
return 0;
}
else if (i.suffix == LONG_MNEM_SUFFIX)
{
if (intel_syntax
&& i.tm.opcode_modifier.ignoresize
&& i.tm.opcode_modifier.no_lsuf)
i.suffix = 0;
else if (!check_long_reg ())
return 0;
}
else if (i.suffix == QWORD_MNEM_SUFFIX)
{
if (intel_syntax
&& i.tm.opcode_modifier.ignoresize
&& i.tm.opcode_modifier.no_qsuf)
i.suffix = 0;
else if (!check_qword_reg ())
return 0;
}
else if (i.suffix == WORD_MNEM_SUFFIX)
{
if (intel_syntax
&& i.tm.opcode_modifier.ignoresize
&& i.tm.opcode_modifier.no_wsuf)
i.suffix = 0;
else if (!check_word_reg ())
return 0;
}
else if (i.suffix == XMMWORD_MNEM_SUFFIX
|| i.suffix == YMMWORD_MNEM_SUFFIX
|| i.suffix == ZMMWORD_MNEM_SUFFIX)
{
/* Skip if the instruction has x/y/z suffix. match_template
should check if it is a valid suffix. */
}
else if (intel_syntax && i.tm.opcode_modifier.ignoresize)
/* Do nothing if the instruction is going to ignore the prefix. */
;
else
abort ();
}
else if (i.tm.opcode_modifier.defaultsize
&& !i.suffix
/* exclude fldenv/frstor/fsave/fstenv */
&& i.tm.opcode_modifier.no_ssuf)
{
i.suffix = stackop_size;
}
else if (intel_syntax
&& !i.suffix
&& (i.tm.operand_types[0].bitfield.jumpabsolute
|| i.tm.opcode_modifier.jumpbyte
|| i.tm.opcode_modifier.jumpintersegment
|| (i.tm.base_opcode == 0x0f01 /* [ls][gi]dt */
&& i.tm.extension_opcode <= 3)))
{
switch (flag_code)
{
case CODE_64BIT:
if (!i.tm.opcode_modifier.no_qsuf)
{
i.suffix = QWORD_MNEM_SUFFIX;
break;
}
case CODE_32BIT:
if (!i.tm.opcode_modifier.no_lsuf)
i.suffix = LONG_MNEM_SUFFIX;
break;
case CODE_16BIT:
if (!i.tm.opcode_modifier.no_wsuf)
i.suffix = WORD_MNEM_SUFFIX;
break;
}
}
 
if (!i.suffix)
{
if (!intel_syntax)
{
if (i.tm.opcode_modifier.w)
{
as_bad (_("no instruction mnemonic suffix given and "
"no register operands; can't size instruction"));
return 0;
}
}
else
{
unsigned int suffixes;
 
suffixes = !i.tm.opcode_modifier.no_bsuf;
if (!i.tm.opcode_modifier.no_wsuf)
suffixes |= 1 << 1;
if (!i.tm.opcode_modifier.no_lsuf)
suffixes |= 1 << 2;
if (!i.tm.opcode_modifier.no_ldsuf)
suffixes |= 1 << 3;
if (!i.tm.opcode_modifier.no_ssuf)
suffixes |= 1 << 4;
if (!i.tm.opcode_modifier.no_qsuf)
suffixes |= 1 << 5;
 
/* There are more than suffix matches. */
if (i.tm.opcode_modifier.w
|| ((suffixes & (suffixes - 1))
&& !i.tm.opcode_modifier.defaultsize
&& !i.tm.opcode_modifier.ignoresize))
{
as_bad (_("ambiguous operand size for `%s'"), i.tm.name);
return 0;
}
}
}
 
/* Change the opcode based on the operand size given by i.suffix;
We don't need to change things for byte insns. */
 
if (i.suffix
&& i.suffix != BYTE_MNEM_SUFFIX
&& i.suffix != XMMWORD_MNEM_SUFFIX
&& i.suffix != YMMWORD_MNEM_SUFFIX
&& i.suffix != ZMMWORD_MNEM_SUFFIX)
{
/* It's not a byte, select word/dword operation. */
if (i.tm.opcode_modifier.w)
{
if (i.tm.opcode_modifier.shortform)
i.tm.base_opcode |= 8;
else
i.tm.base_opcode |= 1;
}
 
/* Now select between word & dword operations via the operand
size prefix, except for instructions that will ignore this
prefix anyway. */
if (i.tm.opcode_modifier.addrprefixop0)
{
/* The address size override prefix changes the size of the
first operand. */
if ((flag_code == CODE_32BIT
&& i.op->regs[0].reg_type.bitfield.reg16)
|| (flag_code != CODE_32BIT
&& i.op->regs[0].reg_type.bitfield.reg32))
if (!add_prefix (ADDR_PREFIX_OPCODE))
return 0;
}
else if (i.suffix != QWORD_MNEM_SUFFIX
&& i.suffix != LONG_DOUBLE_MNEM_SUFFIX
&& !i.tm.opcode_modifier.ignoresize
&& !i.tm.opcode_modifier.floatmf
&& ((i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT)
|| (flag_code == CODE_64BIT
&& i.tm.opcode_modifier.jumpbyte)))
{
unsigned int prefix = DATA_PREFIX_OPCODE;
 
if (i.tm.opcode_modifier.jumpbyte) /* jcxz, loop */
prefix = ADDR_PREFIX_OPCODE;
 
if (!add_prefix (prefix))
return 0;
}
 
/* Set mode64 for an operand. */
if (i.suffix == QWORD_MNEM_SUFFIX
&& flag_code == CODE_64BIT
&& !i.tm.opcode_modifier.norex64)
{
/* Special case for xchg %rax,%rax. It is NOP and doesn't
need rex64. cmpxchg8b is also a special case. */
if (! (i.operands == 2
&& i.tm.base_opcode == 0x90
&& i.tm.extension_opcode == None
&& operand_type_equal (&i.types [0], &acc64)
&& operand_type_equal (&i.types [1], &acc64))
&& ! (i.operands == 1
&& i.tm.base_opcode == 0xfc7
&& i.tm.extension_opcode == 1
&& !operand_type_check (i.types [0], reg)
&& operand_type_check (i.types [0], anymem)))
i.rex |= REX_W;
}
 
/* Size floating point instruction. */
if (i.suffix == LONG_MNEM_SUFFIX)
if (i.tm.opcode_modifier.floatmf)
i.tm.base_opcode ^= 4;
}
 
return 1;
}
 
static int
check_byte_reg (void)
{
int op;
 
for (op = i.operands; --op >= 0;)
{
/* If this is an eight bit register, it's OK. If it's the 16 or
32 bit version of an eight bit register, we will just use the
low portion, and that's OK too. */
if (i.types[op].bitfield.reg8)
continue;
 
/* I/O port address operands are OK too. */
if (i.tm.operand_types[op].bitfield.inoutportreg)
continue;
 
/* crc32 doesn't generate this warning. */
if (i.tm.base_opcode == 0xf20f38f0)
continue;
 
if ((i.types[op].bitfield.reg16
|| i.types[op].bitfield.reg32
|| i.types[op].bitfield.reg64)
&& i.op[op].regs->reg_num < 4
/* Prohibit these changes in 64bit mode, since the lowering
would be more complicated. */
&& flag_code != CODE_64BIT)
{
#if REGISTER_WARNINGS
if (!quiet_warnings)
as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"),
register_prefix,
(i.op[op].regs + (i.types[op].bitfield.reg16
? REGNAM_AL - REGNAM_AX
: REGNAM_AL - REGNAM_EAX))->reg_name,
register_prefix,
i.op[op].regs->reg_name,
i.suffix);
#endif
continue;
}
/* Any other register is bad. */
if (i.types[op].bitfield.reg16
|| i.types[op].bitfield.reg32
|| i.types[op].bitfield.reg64
|| i.types[op].bitfield.regmmx
|| i.types[op].bitfield.regxmm
|| i.types[op].bitfield.regymm
|| i.types[op].bitfield.regzmm
|| i.types[op].bitfield.sreg2
|| i.types[op].bitfield.sreg3
|| i.types[op].bitfield.control
|| i.types[op].bitfield.debug
|| i.types[op].bitfield.test
|| i.types[op].bitfield.floatreg
|| i.types[op].bitfield.floatacc)
{
as_bad (_("`%s%s' not allowed with `%s%c'"),
register_prefix,
i.op[op].regs->reg_name,
i.tm.name,
i.suffix);
return 0;
}
}
return 1;
}
 
static int
check_long_reg (void)
{
int op;
 
for (op = i.operands; --op >= 0;)
/* Reject eight bit registers, except where the template requires
them. (eg. movzb) */
if (i.types[op].bitfield.reg8
&& (i.tm.operand_types[op].bitfield.reg16
|| i.tm.operand_types[op].bitfield.reg32
|| i.tm.operand_types[op].bitfield.acc))
{
as_bad (_("`%s%s' not allowed with `%s%c'"),
register_prefix,
i.op[op].regs->reg_name,
i.tm.name,
i.suffix);
return 0;
}
/* Warn if the e prefix on a general reg is missing. */
else if ((!quiet_warnings || flag_code == CODE_64BIT)
&& i.types[op].bitfield.reg16
&& (i.tm.operand_types[op].bitfield.reg32
|| i.tm.operand_types[op].bitfield.acc))
{
/* Prohibit these changes in the 64bit mode, since the
lowering is more complicated. */
if (flag_code == CODE_64BIT)
{
as_bad (_("incorrect register `%s%s' used with `%c' suffix"),
register_prefix, i.op[op].regs->reg_name,
i.suffix);
return 0;
}
#if REGISTER_WARNINGS
else
as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"),
register_prefix,
(i.op[op].regs + REGNAM_EAX - REGNAM_AX)->reg_name,
register_prefix,
i.op[op].regs->reg_name,
i.suffix);
#endif
}
/* Warn if the r prefix on a general reg is missing. */
else if (i.types[op].bitfield.reg64
&& (i.tm.operand_types[op].bitfield.reg32
|| i.tm.operand_types[op].bitfield.acc))
{
if (intel_syntax
&& i.tm.opcode_modifier.toqword
&& !i.types[0].bitfield.regxmm)
{
/* Convert to QWORD. We want REX byte. */
i.suffix = QWORD_MNEM_SUFFIX;
}
else
{
as_bad (_("incorrect register `%s%s' used with `%c' suffix"),
register_prefix, i.op[op].regs->reg_name,
i.suffix);
return 0;
}
}
return 1;
}
 
static int
check_qword_reg (void)
{
int op;
 
for (op = i.operands; --op >= 0; )
/* Reject eight bit registers, except where the template requires
them. (eg. movzb) */
if (i.types[op].bitfield.reg8
&& (i.tm.operand_types[op].bitfield.reg16
|| i.tm.operand_types[op].bitfield.reg32
|| i.tm.operand_types[op].bitfield.acc))
{
as_bad (_("`%s%s' not allowed with `%s%c'"),
register_prefix,
i.op[op].regs->reg_name,
i.tm.name,
i.suffix);
return 0;
}
/* Warn if the e prefix on a general reg is missing. */
else if ((i.types[op].bitfield.reg16
|| i.types[op].bitfield.reg32)
&& (i.tm.operand_types[op].bitfield.reg32
|| i.tm.operand_types[op].bitfield.acc))
{
/* Prohibit these changes in the 64bit mode, since the
lowering is more complicated. */
if (intel_syntax
&& i.tm.opcode_modifier.todword
&& !i.types[0].bitfield.regxmm)
{
/* Convert to DWORD. We don't want REX byte. */
i.suffix = LONG_MNEM_SUFFIX;
}
else
{
as_bad (_("incorrect register `%s%s' used with `%c' suffix"),
register_prefix, i.op[op].regs->reg_name,
i.suffix);
return 0;
}
}
return 1;
}
 
static int
check_word_reg (void)
{
int op;
for (op = i.operands; --op >= 0;)
/* Reject eight bit registers, except where the template requires
them. (eg. movzb) */
if (i.types[op].bitfield.reg8
&& (i.tm.operand_types[op].bitfield.reg16
|| i.tm.operand_types[op].bitfield.reg32
|| i.tm.operand_types[op].bitfield.acc))
{
as_bad (_("`%s%s' not allowed with `%s%c'"),
register_prefix,
i.op[op].regs->reg_name,
i.tm.name,
i.suffix);
return 0;
}
/* Warn if the e prefix on a general reg is present. */
else if ((!quiet_warnings || flag_code == CODE_64BIT)
&& i.types[op].bitfield.reg32
&& (i.tm.operand_types[op].bitfield.reg16
|| i.tm.operand_types[op].bitfield.acc))
{
/* Prohibit these changes in the 64bit mode, since the
lowering is more complicated. */
if (flag_code == CODE_64BIT)
{
as_bad (_("incorrect register `%s%s' used with `%c' suffix"),
register_prefix, i.op[op].regs->reg_name,
i.suffix);
return 0;
}
else
#if REGISTER_WARNINGS
as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"),
register_prefix,
(i.op[op].regs + REGNAM_AX - REGNAM_EAX)->reg_name,
register_prefix,
i.op[op].regs->reg_name,
i.suffix);
#endif
}
return 1;
}
 
static int
update_imm (unsigned int j)
{
i386_operand_type overlap = i.types[j];
if ((overlap.bitfield.imm8
|| overlap.bitfield.imm8s
|| overlap.bitfield.imm16
|| overlap.bitfield.imm32
|| overlap.bitfield.imm32s
|| overlap.bitfield.imm64)
&& !operand_type_equal (&overlap, &imm8)
&& !operand_type_equal (&overlap, &imm8s)
&& !operand_type_equal (&overlap, &imm16)
&& !operand_type_equal (&overlap, &imm32)
&& !operand_type_equal (&overlap, &imm32s)
&& !operand_type_equal (&overlap, &imm64))
{
if (i.suffix)
{
i386_operand_type temp;
 
operand_type_set (&temp, 0);
if (i.suffix == BYTE_MNEM_SUFFIX)
{
temp.bitfield.imm8 = overlap.bitfield.imm8;
temp.bitfield.imm8s = overlap.bitfield.imm8s;
}
else if (i.suffix == WORD_MNEM_SUFFIX)
temp.bitfield.imm16 = overlap.bitfield.imm16;
else if (i.suffix == QWORD_MNEM_SUFFIX)
{
temp.bitfield.imm64 = overlap.bitfield.imm64;
temp.bitfield.imm32s = overlap.bitfield.imm32s;
}
else
temp.bitfield.imm32 = overlap.bitfield.imm32;
overlap = temp;
}
else if (operand_type_equal (&overlap, &imm16_32_32s)
|| operand_type_equal (&overlap, &imm16_32)
|| operand_type_equal (&overlap, &imm16_32s))
{
if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0))
overlap = imm16;
else
overlap = imm32s;
}
if (!operand_type_equal (&overlap, &imm8)
&& !operand_type_equal (&overlap, &imm8s)
&& !operand_type_equal (&overlap, &imm16)
&& !operand_type_equal (&overlap, &imm32)
&& !operand_type_equal (&overlap, &imm32s)
&& !operand_type_equal (&overlap, &imm64))
{
as_bad (_("no instruction mnemonic suffix given; "
"can't determine immediate size"));
return 0;
}
}
i.types[j] = overlap;
 
return 1;
}
 
static int
finalize_imm (void)
{
unsigned int j, n;
 
/* Update the first 2 immediate operands. */
n = i.operands > 2 ? 2 : i.operands;
if (n)
{
for (j = 0; j < n; j++)
if (update_imm (j) == 0)
return 0;
 
/* The 3rd operand can't be immediate operand. */
gas_assert (operand_type_check (i.types[2], imm) == 0);
}
 
return 1;
}
 
static int
bad_implicit_operand (int xmm)
{
const char *ireg = xmm ? "xmm0" : "ymm0";
 
if (intel_syntax)
as_bad (_("the last operand of `%s' must be `%s%s'"),
i.tm.name, register_prefix, ireg);
else
as_bad (_("the first operand of `%s' must be `%s%s'"),
i.tm.name, register_prefix, ireg);
return 0;
}
 
static int
process_operands (void)
{
/* Default segment register this instruction will use for memory
accesses. 0 means unknown. This is only for optimizing out
unnecessary segment overrides. */
const seg_entry *default_seg = 0;
 
if (i.tm.opcode_modifier.sse2avx && i.tm.opcode_modifier.vexvvvv)
{
unsigned int dupl = i.operands;
unsigned int dest = dupl - 1;
unsigned int j;
 
/* The destination must be an xmm register. */
gas_assert (i.reg_operands
&& MAX_OPERANDS > dupl
&& operand_type_equal (&i.types[dest], &regxmm));
 
if (i.tm.opcode_modifier.firstxmm0)
{
/* The first operand is implicit and must be xmm0. */
gas_assert (operand_type_equal (&i.types[0], &regxmm));
if (register_number (i.op[0].regs) != 0)
return bad_implicit_operand (1);
 
if (i.tm.opcode_modifier.vexsources == VEX3SOURCES)
{
/* Keep xmm0 for instructions with VEX prefix and 3
sources. */
goto duplicate;
}
else
{
/* We remove the first xmm0 and keep the number of
operands unchanged, which in fact duplicates the
destination. */
for (j = 1; j < i.operands; j++)
{
i.op[j - 1] = i.op[j];
i.types[j - 1] = i.types[j];
i.tm.operand_types[j - 1] = i.tm.operand_types[j];
}
}
}
else if (i.tm.opcode_modifier.implicit1stxmm0)
{
gas_assert ((MAX_OPERANDS - 1) > dupl
&& (i.tm.opcode_modifier.vexsources
== VEX3SOURCES));
 
/* Add the implicit xmm0 for instructions with VEX prefix
and 3 sources. */
for (j = i.operands; j > 0; j--)
{
i.op[j] = i.op[j - 1];
i.types[j] = i.types[j - 1];
i.tm.operand_types[j] = i.tm.operand_types[j - 1];
}
i.op[0].regs
= (const reg_entry *) hash_find (reg_hash, "xmm0");
i.types[0] = regxmm;
i.tm.operand_types[0] = regxmm;
 
i.operands += 2;
i.reg_operands += 2;
i.tm.operands += 2;
 
dupl++;
dest++;
i.op[dupl] = i.op[dest];
i.types[dupl] = i.types[dest];
i.tm.operand_types[dupl] = i.tm.operand_types[dest];
}
else
{
duplicate:
i.operands++;
i.reg_operands++;
i.tm.operands++;
 
i.op[dupl] = i.op[dest];
i.types[dupl] = i.types[dest];
i.tm.operand_types[dupl] = i.tm.operand_types[dest];
}
 
if (i.tm.opcode_modifier.immext)
process_immext ();
}
else if (i.tm.opcode_modifier.firstxmm0)
{
unsigned int j;
 
/* The first operand is implicit and must be xmm0/ymm0/zmm0. */
gas_assert (i.reg_operands
&& (operand_type_equal (&i.types[0], &regxmm)
|| operand_type_equal (&i.types[0], &regymm)
|| operand_type_equal (&i.types[0], &regzmm)));
if (register_number (i.op[0].regs) != 0)
return bad_implicit_operand (i.types[0].bitfield.regxmm);
 
for (j = 1; j < i.operands; j++)
{
i.op[j - 1] = i.op[j];
i.types[j - 1] = i.types[j];
 
/* We need to adjust fields in i.tm since they are used by
build_modrm_byte. */
i.tm.operand_types [j - 1] = i.tm.operand_types [j];
}
 
i.operands--;
i.reg_operands--;
i.tm.operands--;
}
else if (i.tm.opcode_modifier.regkludge)
{
/* The imul $imm, %reg instruction is converted into
imul $imm, %reg, %reg, and the clr %reg instruction
is converted into xor %reg, %reg. */
 
unsigned int first_reg_op;
 
if (operand_type_check (i.types[0], reg))
first_reg_op = 0;
else
first_reg_op = 1;
/* Pretend we saw the extra register operand. */
gas_assert (i.reg_operands == 1
&& i.op[first_reg_op + 1].regs == 0);
i.op[first_reg_op + 1].regs = i.op[first_reg_op].regs;
i.types[first_reg_op + 1] = i.types[first_reg_op];
i.operands++;
i.reg_operands++;
}
 
if (i.tm.opcode_modifier.shortform)
{
if (i.types[0].bitfield.sreg2
|| i.types[0].bitfield.sreg3)
{
if (i.tm.base_opcode == POP_SEG_SHORT
&& i.op[0].regs->reg_num == 1)
{
as_bad (_("you can't `pop %scs'"), register_prefix);
return 0;
}
i.tm.base_opcode |= (i.op[0].regs->reg_num << 3);
if ((i.op[0].regs->reg_flags & RegRex) != 0)
i.rex |= REX_B;
}
else
{
/* The register or float register operand is in operand
0 or 1. */
unsigned int op;
 
if (i.types[0].bitfield.floatreg
|| operand_type_check (i.types[0], reg))
op = 0;
else
op = 1;
/* Register goes in low 3 bits of opcode. */
i.tm.base_opcode |= i.op[op].regs->reg_num;
if ((i.op[op].regs->reg_flags & RegRex) != 0)
i.rex |= REX_B;
if (!quiet_warnings && i.tm.opcode_modifier.ugh)
{
/* Warn about some common errors, but press on regardless.
The first case can be generated by gcc (<= 2.8.1). */
if (i.operands == 2)
{
/* Reversed arguments on faddp, fsubp, etc. */
as_warn (_("translating to `%s %s%s,%s%s'"), i.tm.name,
register_prefix, i.op[!intel_syntax].regs->reg_name,
register_prefix, i.op[intel_syntax].regs->reg_name);
}
else
{
/* Extraneous `l' suffix on fp insn. */
as_warn (_("translating to `%s %s%s'"), i.tm.name,
register_prefix, i.op[0].regs->reg_name);
}
}
}
}
else if (i.tm.opcode_modifier.modrm)
{
/* The opcode is completed (modulo i.tm.extension_opcode which
must be put into the modrm byte). Now, we make the modrm and
index base bytes based on all the info we've collected. */
 
default_seg = build_modrm_byte ();
}
else if ((i.tm.base_opcode & ~0x3) == MOV_AX_DISP32)
{
default_seg = &ds;
}
else if (i.tm.opcode_modifier.isstring)
{
/* For the string instructions that allow a segment override
on one of their operands, the default segment is ds. */
default_seg = &ds;
}
 
if (i.tm.base_opcode == 0x8d /* lea */
&& i.seg[0]
&& !quiet_warnings)
as_warn (_("segment override on `%s' is ineffectual"), i.tm.name);
 
/* If a segment was explicitly specified, and the specified segment
is not the default, use an opcode prefix to select it. If we
never figured out what the default segment is, then default_seg
will be zero at this point, and the specified segment prefix will
always be used. */
if ((i.seg[0]) && (i.seg[0] != default_seg))
{
if (!add_prefix (i.seg[0]->seg_prefix))
return 0;
}
return 1;
}
 
static const seg_entry *
build_modrm_byte (void)
{
const seg_entry *default_seg = 0;
unsigned int source, dest;
int vex_3_sources;
 
/* The first operand of instructions with VEX prefix and 3 sources
must be VEX_Imm4. */
vex_3_sources = i.tm.opcode_modifier.vexsources == VEX3SOURCES;
if (vex_3_sources)
{
unsigned int nds, reg_slot;
expressionS *exp;
 
if (i.tm.opcode_modifier.veximmext
&& i.tm.opcode_modifier.immext)
{
dest = i.operands - 2;
gas_assert (dest == 3);
}
else
dest = i.operands - 1;
nds = dest - 1;
 
/* There are 2 kinds of instructions:
1. 5 operands: 4 register operands or 3 register operands
plus 1 memory operand plus one Vec_Imm4 operand, VexXDS, and
VexW0 or VexW1. The destination must be either XMM, YMM or
ZMM register.
2. 4 operands: 4 register operands or 3 register operands
plus 1 memory operand, VexXDS, and VexImmExt */
gas_assert ((i.reg_operands == 4
|| (i.reg_operands == 3 && i.mem_operands == 1))
&& i.tm.opcode_modifier.vexvvvv == VEXXDS
&& (i.tm.opcode_modifier.veximmext
|| (i.imm_operands == 1
&& i.types[0].bitfield.vec_imm4
&& (i.tm.opcode_modifier.vexw == VEXW0
|| i.tm.opcode_modifier.vexw == VEXW1)
&& (operand_type_equal (&i.tm.operand_types[dest], &regxmm)
|| operand_type_equal (&i.tm.operand_types[dest], &regymm)
|| operand_type_equal (&i.tm.operand_types[dest], &regzmm)))));
 
if (i.imm_operands == 0)
{
/* When there is no immediate operand, generate an 8bit
immediate operand to encode the first operand. */
exp = &im_expressions[i.imm_operands++];
i.op[i.operands].imms = exp;
i.types[i.operands] = imm8;
i.operands++;
/* If VexW1 is set, the first operand is the source and
the second operand is encoded in the immediate operand. */
if (i.tm.opcode_modifier.vexw == VEXW1)
{
source = 0;
reg_slot = 1;
}
else
{
source = 1;
reg_slot = 0;
}
 
/* FMA swaps REG and NDS. */
if (i.tm.cpu_flags.bitfield.cpufma)
{
unsigned int tmp;
tmp = reg_slot;
reg_slot = nds;
nds = tmp;
}
 
gas_assert (operand_type_equal (&i.tm.operand_types[reg_slot],
&regxmm)
|| operand_type_equal (&i.tm.operand_types[reg_slot],
&regymm)
|| operand_type_equal (&i.tm.operand_types[reg_slot],
&regzmm));
exp->X_op = O_constant;
exp->X_add_number = register_number (i.op[reg_slot].regs) << 4;
gas_assert ((i.op[reg_slot].regs->reg_flags & RegVRex) == 0);
}
else
{
unsigned int imm_slot;
 
if (i.tm.opcode_modifier.vexw == VEXW0)
{
/* If VexW0 is set, the third operand is the source and
the second operand is encoded in the immediate
operand. */
source = 2;
reg_slot = 1;
}
else
{
/* VexW1 is set, the second operand is the source and
the third operand is encoded in the immediate
operand. */
source = 1;
reg_slot = 2;
}
 
if (i.tm.opcode_modifier.immext)
{
/* When ImmExt is set, the immdiate byte is the last
operand. */
imm_slot = i.operands - 1;
source--;
reg_slot--;
}
else
{
imm_slot = 0;
 
/* Turn on Imm8 so that output_imm will generate it. */
i.types[imm_slot].bitfield.imm8 = 1;
}
 
gas_assert (operand_type_equal (&i.tm.operand_types[reg_slot],
&regxmm)
|| operand_type_equal (&i.tm.operand_types[reg_slot],
&regymm)
|| operand_type_equal (&i.tm.operand_types[reg_slot],
&regzmm));
i.op[imm_slot].imms->X_add_number
|= register_number (i.op[reg_slot].regs) << 4;
gas_assert ((i.op[reg_slot].regs->reg_flags & RegVRex) == 0);
}
 
gas_assert (operand_type_equal (&i.tm.operand_types[nds], &regxmm)
|| operand_type_equal (&i.tm.operand_types[nds],
&regymm)
|| operand_type_equal (&i.tm.operand_types[nds],
&regzmm));
i.vex.register_specifier = i.op[nds].regs;
}
else
source = dest = 0;
 
/* i.reg_operands MUST be the number of real register operands;
implicit registers do not count. If there are 3 register
operands, it must be a instruction with VexNDS. For a
instruction with VexNDD, the destination register is encoded
in VEX prefix. If there are 4 register operands, it must be
a instruction with VEX prefix and 3 sources. */
if (i.mem_operands == 0
&& ((i.reg_operands == 2
&& i.tm.opcode_modifier.vexvvvv <= VEXXDS)
|| (i.reg_operands == 3
&& i.tm.opcode_modifier.vexvvvv == VEXXDS)
|| (i.reg_operands == 4 && vex_3_sources)))
{
switch (i.operands)
{
case 2:
source = 0;
break;
case 3:
/* When there are 3 operands, one of them may be immediate,
which may be the first or the last operand. Otherwise,
the first operand must be shift count register (cl) or it
is an instruction with VexNDS. */
gas_assert (i.imm_operands == 1
|| (i.imm_operands == 0
&& (i.tm.opcode_modifier.vexvvvv == VEXXDS
|| i.types[0].bitfield.shiftcount)));
if (operand_type_check (i.types[0], imm)
|| i.types[0].bitfield.shiftcount)
source = 1;
else
source = 0;
break;
case 4:
/* When there are 4 operands, the first two must be 8bit
immediate operands. The source operand will be the 3rd
one.
 
For instructions with VexNDS, if the first operand
an imm8, the source operand is the 2nd one. If the last
operand is imm8, the source operand is the first one. */
gas_assert ((i.imm_operands == 2
&& i.types[0].bitfield.imm8
&& i.types[1].bitfield.imm8)
|| (i.tm.opcode_modifier.vexvvvv == VEXXDS
&& i.imm_operands == 1
&& (i.types[0].bitfield.imm8
|| i.types[i.operands - 1].bitfield.imm8
|| i.rounding)));
if (i.imm_operands == 2)
source = 2;
else
{
if (i.types[0].bitfield.imm8)
source = 1;
else
source = 0;
}
break;
case 5:
if (i.tm.opcode_modifier.evex)
{
/* For EVEX instructions, when there are 5 operands, the
first one must be immediate operand. If the second one
is immediate operand, the source operand is the 3th
one. If the last one is immediate operand, the source
operand is the 2nd one. */
gas_assert (i.imm_operands == 2
&& i.tm.opcode_modifier.sae
&& operand_type_check (i.types[0], imm));
if (operand_type_check (i.types[1], imm))
source = 2;
else if (operand_type_check (i.types[4], imm))
source = 1;
else
abort ();
}
break;
default:
abort ();
}
 
if (!vex_3_sources)
{
dest = source + 1;
 
/* RC/SAE operand could be between DEST and SRC. That happens
when one operand is GPR and the other one is XMM/YMM/ZMM
register. */
if (i.rounding && i.rounding->operand == (int) dest)
dest++;
 
if (i.tm.opcode_modifier.vexvvvv == VEXXDS)
{
/* For instructions with VexNDS, the register-only source
operand must be 32/64bit integer, XMM, YMM or ZMM
register. It is encoded in VEX prefix. We need to
clear RegMem bit before calling operand_type_equal. */
 
i386_operand_type op;
unsigned int vvvv;
 
/* Check register-only source operand when two source
operands are swapped. */
if (!i.tm.operand_types[source].bitfield.baseindex
&& i.tm.operand_types[dest].bitfield.baseindex)
{
vvvv = source;
source = dest;
}
else
vvvv = dest;
 
op = i.tm.operand_types[vvvv];
op.bitfield.regmem = 0;
if ((dest + 1) >= i.operands
|| (op.bitfield.reg32 != 1
&& !op.bitfield.reg64 != 1
&& !operand_type_equal (&op, &regxmm)
&& !operand_type_equal (&op, &regymm)
&& !operand_type_equal (&op, &regzmm)
&& !operand_type_equal (&op, &regmask)))
abort ();
i.vex.register_specifier = i.op[vvvv].regs;
dest++;
}
}
 
i.rm.mode = 3;
/* One of the register operands will be encoded in the i.tm.reg
field, the other in the combined i.tm.mode and i.tm.regmem
fields. If no form of this instruction supports a memory
destination operand, then we assume the source operand may
sometimes be a memory operand and so we need to store the
destination in the i.rm.reg field. */
if (!i.tm.operand_types[dest].bitfield.regmem
&& operand_type_check (i.tm.operand_types[dest], anymem) == 0)
{
i.rm.reg = i.op[dest].regs->reg_num;
i.rm.regmem = i.op[source].regs->reg_num;
if ((i.op[dest].regs->reg_flags & RegRex) != 0)
i.rex |= REX_R;
if ((i.op[dest].regs->reg_flags & RegVRex) != 0)
i.vrex |= REX_R;
if ((i.op[source].regs->reg_flags & RegRex) != 0)
i.rex |= REX_B;
if ((i.op[source].regs->reg_flags & RegVRex) != 0)
i.vrex |= REX_B;
}
else
{
i.rm.reg = i.op[source].regs->reg_num;
i.rm.regmem = i.op[dest].regs->reg_num;
if ((i.op[dest].regs->reg_flags & RegRex) != 0)
i.rex |= REX_B;
if ((i.op[dest].regs->reg_flags & RegVRex) != 0)
i.vrex |= REX_B;
if ((i.op[source].regs->reg_flags & RegRex) != 0)
i.rex |= REX_R;
if ((i.op[source].regs->reg_flags & RegVRex) != 0)
i.vrex |= REX_R;
}
if (flag_code != CODE_64BIT && (i.rex & (REX_R | REX_B)))
{
if (!i.types[0].bitfield.control
&& !i.types[1].bitfield.control)
abort ();
i.rex &= ~(REX_R | REX_B);
add_prefix (LOCK_PREFIX_OPCODE);
}
}
else
{ /* If it's not 2 reg operands... */
unsigned int mem;
 
if (i.mem_operands)
{
unsigned int fake_zero_displacement = 0;
unsigned int op;
 
for (op = 0; op < i.operands; op++)
if (operand_type_check (i.types[op], anymem))
break;
gas_assert (op < i.operands);
 
if (i.tm.opcode_modifier.vecsib)
{
if (i.index_reg->reg_num == RegEiz
|| i.index_reg->reg_num == RegRiz)
abort ();
 
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
if (!i.base_reg)
{
i.sib.base = NO_BASE_REGISTER;
i.sib.scale = i.log2_scale_factor;
/* No Vec_Disp8 if there is no base. */
i.types[op].bitfield.vec_disp8 = 0;
i.types[op].bitfield.disp8 = 0;
i.types[op].bitfield.disp16 = 0;
i.types[op].bitfield.disp64 = 0;
if (flag_code != CODE_64BIT)
{
/* Must be 32 bit */
i.types[op].bitfield.disp32 = 1;
i.types[op].bitfield.disp32s = 0;
}
else
{
i.types[op].bitfield.disp32 = 0;
i.types[op].bitfield.disp32s = 1;
}
}
i.sib.index = i.index_reg->reg_num;
if ((i.index_reg->reg_flags & RegRex) != 0)
i.rex |= REX_X;
if ((i.index_reg->reg_flags & RegVRex) != 0)
i.vrex |= REX_X;
}
 
default_seg = &ds;
 
if (i.base_reg == 0)
{
i.rm.mode = 0;
if (!i.disp_operands)
{
fake_zero_displacement = 1;
/* Instructions with VSIB byte need 32bit displacement
if there is no base register. */
if (i.tm.opcode_modifier.vecsib)
i.types[op].bitfield.disp32 = 1;
}
if (i.index_reg == 0)
{
gas_assert (!i.tm.opcode_modifier.vecsib);
/* Operand is just <disp> */
if (flag_code == CODE_64BIT)
{
/* 64bit mode overwrites the 32bit absolute
addressing by RIP relative addressing and
absolute addressing is encoded by one of the
redundant SIB forms. */
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
i.sib.base = NO_BASE_REGISTER;
i.sib.index = NO_INDEX_REGISTER;
i.types[op] = ((i.prefix[ADDR_PREFIX] == 0)
? disp32s : disp32);
}
else if ((flag_code == CODE_16BIT)
^ (i.prefix[ADDR_PREFIX] != 0))
{
i.rm.regmem = NO_BASE_REGISTER_16;
i.types[op] = disp16;
}
else
{
i.rm.regmem = NO_BASE_REGISTER;
i.types[op] = disp32;
}
}
else if (!i.tm.opcode_modifier.vecsib)
{
/* !i.base_reg && i.index_reg */
if (i.index_reg->reg_num == RegEiz
|| i.index_reg->reg_num == RegRiz)
i.sib.index = NO_INDEX_REGISTER;
else
i.sib.index = i.index_reg->reg_num;
i.sib.base = NO_BASE_REGISTER;
i.sib.scale = i.log2_scale_factor;
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
/* No Vec_Disp8 if there is no base. */
i.types[op].bitfield.vec_disp8 = 0;
i.types[op].bitfield.disp8 = 0;
i.types[op].bitfield.disp16 = 0;
i.types[op].bitfield.disp64 = 0;
if (flag_code != CODE_64BIT)
{
/* Must be 32 bit */
i.types[op].bitfield.disp32 = 1;
i.types[op].bitfield.disp32s = 0;
}
else
{
i.types[op].bitfield.disp32 = 0;
i.types[op].bitfield.disp32s = 1;
}
if ((i.index_reg->reg_flags & RegRex) != 0)
i.rex |= REX_X;
}
}
/* RIP addressing for 64bit mode. */
else if (i.base_reg->reg_num == RegRip ||
i.base_reg->reg_num == RegEip)
{
gas_assert (!i.tm.opcode_modifier.vecsib);
i.rm.regmem = NO_BASE_REGISTER;
i.types[op].bitfield.disp8 = 0;
i.types[op].bitfield.disp16 = 0;
i.types[op].bitfield.disp32 = 0;
i.types[op].bitfield.disp32s = 1;
i.types[op].bitfield.disp64 = 0;
i.types[op].bitfield.vec_disp8 = 0;
i.flags[op] |= Operand_PCrel;
if (! i.disp_operands)
fake_zero_displacement = 1;
}
else if (i.base_reg->reg_type.bitfield.reg16)
{
gas_assert (!i.tm.opcode_modifier.vecsib);
switch (i.base_reg->reg_num)
{
case 3: /* (%bx) */
if (i.index_reg == 0)
i.rm.regmem = 7;
else /* (%bx,%si) -> 0, or (%bx,%di) -> 1 */
i.rm.regmem = i.index_reg->reg_num - 6;
break;
case 5: /* (%bp) */
default_seg = &ss;
if (i.index_reg == 0)
{
i.rm.regmem = 6;
if (operand_type_check (i.types[op], disp) == 0)
{
/* fake (%bp) into 0(%bp) */
if (i.tm.operand_types[op].bitfield.vec_disp8)
i.types[op].bitfield.vec_disp8 = 1;
else
i.types[op].bitfield.disp8 = 1;
fake_zero_displacement = 1;
}
}
else /* (%bp,%si) -> 2, or (%bp,%di) -> 3 */
i.rm.regmem = i.index_reg->reg_num - 6 + 2;
break;
default: /* (%si) -> 4 or (%di) -> 5 */
i.rm.regmem = i.base_reg->reg_num - 6 + 4;
}
i.rm.mode = mode_from_disp_size (i.types[op]);
}
else /* i.base_reg and 32/64 bit mode */
{
if (flag_code == CODE_64BIT
&& operand_type_check (i.types[op], disp))
{
i386_operand_type temp;
operand_type_set (&temp, 0);
temp.bitfield.disp8 = i.types[op].bitfield.disp8;
temp.bitfield.vec_disp8
= i.types[op].bitfield.vec_disp8;
i.types[op] = temp;
if (i.prefix[ADDR_PREFIX] == 0)
i.types[op].bitfield.disp32s = 1;
else
i.types[op].bitfield.disp32 = 1;
}
 
if (!i.tm.opcode_modifier.vecsib)
i.rm.regmem = i.base_reg->reg_num;
if ((i.base_reg->reg_flags & RegRex) != 0)
i.rex |= REX_B;
i.sib.base = i.base_reg->reg_num;
/* x86-64 ignores REX prefix bit here to avoid decoder
complications. */
if (!(i.base_reg->reg_flags & RegRex)
&& (i.base_reg->reg_num == EBP_REG_NUM
|| i.base_reg->reg_num == ESP_REG_NUM))
default_seg = &ss;
if (i.base_reg->reg_num == 5 && i.disp_operands == 0)
{
fake_zero_displacement = 1;
if (i.tm.operand_types [op].bitfield.vec_disp8)
i.types[op].bitfield.vec_disp8 = 1;
else
i.types[op].bitfield.disp8 = 1;
}
i.sib.scale = i.log2_scale_factor;
if (i.index_reg == 0)
{
gas_assert (!i.tm.opcode_modifier.vecsib);
/* <disp>(%esp) becomes two byte modrm with no index
register. We've already stored the code for esp
in i.rm.regmem ie. ESCAPE_TO_TWO_BYTE_ADDRESSING.
Any base register besides %esp will not use the
extra modrm byte. */
i.sib.index = NO_INDEX_REGISTER;
}
else if (!i.tm.opcode_modifier.vecsib)
{
if (i.index_reg->reg_num == RegEiz
|| i.index_reg->reg_num == RegRiz)
i.sib.index = NO_INDEX_REGISTER;
else
i.sib.index = i.index_reg->reg_num;
i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
if ((i.index_reg->reg_flags & RegRex) != 0)
i.rex |= REX_X;
}
 
if (i.disp_operands
&& (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL
|| i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL))
i.rm.mode = 0;
else
{
if (!fake_zero_displacement
&& !i.disp_operands
&& i.disp_encoding)
{
fake_zero_displacement = 1;
if (i.disp_encoding == disp_encoding_8bit)
i.types[op].bitfield.disp8 = 1;
else
i.types[op].bitfield.disp32 = 1;
}
i.rm.mode = mode_from_disp_size (i.types[op]);
}
}
 
if (fake_zero_displacement)
{
/* Fakes a zero displacement assuming that i.types[op]
holds the correct displacement size. */
expressionS *exp;
 
gas_assert (i.op[op].disps == 0);
exp = &disp_expressions[i.disp_operands++];
i.op[op].disps = exp;
exp->X_op = O_constant;
exp->X_add_number = 0;
exp->X_add_symbol = (symbolS *) 0;
exp->X_op_symbol = (symbolS *) 0;
}
 
mem = op;
}
else
mem = ~0;
 
if (i.tm.opcode_modifier.vexsources == XOP2SOURCES)
{
if (operand_type_check (i.types[0], imm))
i.vex.register_specifier = NULL;
else
{
/* VEX.vvvv encodes one of the sources when the first
operand is not an immediate. */
if (i.tm.opcode_modifier.vexw == VEXW0)
i.vex.register_specifier = i.op[0].regs;
else
i.vex.register_specifier = i.op[1].regs;
}
 
/* Destination is a XMM register encoded in the ModRM.reg
and VEX.R bit. */
i.rm.reg = i.op[2].regs->reg_num;
if ((i.op[2].regs->reg_flags & RegRex) != 0)
i.rex |= REX_R;
 
/* ModRM.rm and VEX.B encodes the other source. */
if (!i.mem_operands)
{
i.rm.mode = 3;
 
if (i.tm.opcode_modifier.vexw == VEXW0)
i.rm.regmem = i.op[1].regs->reg_num;
else
i.rm.regmem = i.op[0].regs->reg_num;
 
if ((i.op[1].regs->reg_flags & RegRex) != 0)
i.rex |= REX_B;
}
}
else if (i.tm.opcode_modifier.vexvvvv == VEXLWP)
{
i.vex.register_specifier = i.op[2].regs;
if (!i.mem_operands)
{
i.rm.mode = 3;
i.rm.regmem = i.op[1].regs->reg_num;
if ((i.op[1].regs->reg_flags & RegRex) != 0)
i.rex |= REX_B;
}
}
/* Fill in i.rm.reg or i.rm.regmem field with register operand
(if any) based on i.tm.extension_opcode. Again, we must be
careful to make sure that segment/control/debug/test/MMX
registers are coded into the i.rm.reg field. */
else if (i.reg_operands)
{
unsigned int op;
unsigned int vex_reg = ~0;
 
for (op = 0; op < i.operands; op++)
if (i.types[op].bitfield.reg8
|| i.types[op].bitfield.reg16
|| i.types[op].bitfield.reg32
|| i.types[op].bitfield.reg64
|| i.types[op].bitfield.regmmx
|| i.types[op].bitfield.regxmm
|| i.types[op].bitfield.regymm
|| i.types[op].bitfield.regbnd
|| i.types[op].bitfield.regzmm
|| i.types[op].bitfield.regmask
|| i.types[op].bitfield.sreg2
|| i.types[op].bitfield.sreg3
|| i.types[op].bitfield.control
|| i.types[op].bitfield.debug
|| i.types[op].bitfield.test)
break;
 
if (vex_3_sources)
op = dest;
else if (i.tm.opcode_modifier.vexvvvv == VEXXDS)
{
/* For instructions with VexNDS, the register-only
source operand is encoded in VEX prefix. */
gas_assert (mem != (unsigned int) ~0);
 
if (op > mem)
{
vex_reg = op++;
gas_assert (op < i.operands);
}
else
{
/* Check register-only source operand when two source
operands are swapped. */
if (!i.tm.operand_types[op].bitfield.baseindex
&& i.tm.operand_types[op + 1].bitfield.baseindex)
{
vex_reg = op;
op += 2;
gas_assert (mem == (vex_reg + 1)
&& op < i.operands);
}
else
{
vex_reg = op + 1;
gas_assert (vex_reg < i.operands);
}
}
}
else if (i.tm.opcode_modifier.vexvvvv == VEXNDD)
{
/* For instructions with VexNDD, the register destination
is encoded in VEX prefix. */
if (i.mem_operands == 0)
{
/* There is no memory operand. */
gas_assert ((op + 2) == i.operands);
vex_reg = op + 1;
}
else
{
/* There are only 2 operands. */
gas_assert (op < 2 && i.operands == 2);
vex_reg = 1;
}
}
else
gas_assert (op < i.operands);
 
if (vex_reg != (unsigned int) ~0)
{
i386_operand_type *type = &i.tm.operand_types[vex_reg];
 
if (type->bitfield.reg32 != 1
&& type->bitfield.reg64 != 1
&& !operand_type_equal (type, &regxmm)
&& !operand_type_equal (type, &regymm)
&& !operand_type_equal (type, &regzmm)
&& !operand_type_equal (type, &regmask))
abort ();
 
i.vex.register_specifier = i.op[vex_reg].regs;
}
 
/* Don't set OP operand twice. */
if (vex_reg != op)
{
/* If there is an extension opcode to put here, the
register number must be put into the regmem field. */
if (i.tm.extension_opcode != None)
{
i.rm.regmem = i.op[op].regs->reg_num;
if ((i.op[op].regs->reg_flags & RegRex) != 0)
i.rex |= REX_B;
if ((i.op[op].regs->reg_flags & RegVRex) != 0)
i.vrex |= REX_B;
}
else
{
i.rm.reg = i.op[op].regs->reg_num;
if ((i.op[op].regs->reg_flags & RegRex) != 0)
i.rex |= REX_R;
if ((i.op[op].regs->reg_flags & RegVRex) != 0)
i.vrex |= REX_R;
}
}
 
/* Now, if no memory operand has set i.rm.mode = 0, 1, 2 we
must set it to 3 to indicate this is a register operand
in the regmem field. */
if (!i.mem_operands)
i.rm.mode = 3;
}
 
/* Fill in i.rm.reg field with extension opcode (if any). */
if (i.tm.extension_opcode != None)
i.rm.reg = i.tm.extension_opcode;
}
return default_seg;
}
 
static void
output_branch (void)
{
char *p;
int size;
int code16;
int prefix;
relax_substateT subtype;
symbolS *sym;
offsetT off;
 
code16 = flag_code == CODE_16BIT ? CODE16 : 0;
size = i.disp_encoding == disp_encoding_32bit ? BIG : SMALL;
 
prefix = 0;
if (i.prefix[DATA_PREFIX] != 0)
{
prefix = 1;
i.prefixes -= 1;
code16 ^= CODE16;
}
/* Pentium4 branch hints. */
if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE /* not taken */
|| i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE /* taken */)
{
prefix++;
i.prefixes--;
}
if (i.prefix[REX_PREFIX] != 0)
{
prefix++;
i.prefixes--;
}
 
/* BND prefixed jump. */
if (i.prefix[BND_PREFIX] != 0)
{
FRAG_APPEND_1_CHAR (i.prefix[BND_PREFIX]);
i.prefixes -= 1;
}
 
if (i.prefixes != 0 && !intel_syntax)
as_warn (_("skipping prefixes on this instruction"));
 
/* It's always a symbol; End frag & setup for relax.
Make sure there is enough room in this frag for the largest
instruction we may generate in md_convert_frag. This is 2
bytes for the opcode and room for the prefix and largest
displacement. */
frag_grow (prefix + 2 + 4);
/* Prefix and 1 opcode byte go in fr_fix. */
p = frag_more (prefix + 1);
if (i.prefix[DATA_PREFIX] != 0)
*p++ = DATA_PREFIX_OPCODE;
if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE
|| i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE)
*p++ = i.prefix[SEG_PREFIX];
if (i.prefix[REX_PREFIX] != 0)
*p++ = i.prefix[REX_PREFIX];
*p = i.tm.base_opcode;
 
if ((unsigned char) *p == JUMP_PC_RELATIVE)
subtype = ENCODE_RELAX_STATE (UNCOND_JUMP, size);
else if (cpu_arch_flags.bitfield.cpui386)
subtype = ENCODE_RELAX_STATE (COND_JUMP, size);
else
subtype = ENCODE_RELAX_STATE (COND_JUMP86, size);
subtype |= code16;
 
sym = i.op[0].disps->X_add_symbol;
off = i.op[0].disps->X_add_number;
 
if (i.op[0].disps->X_op != O_constant
&& i.op[0].disps->X_op != O_symbol)
{
/* Handle complex expressions. */
sym = make_expr_symbol (i.op[0].disps);
off = 0;
}
 
/* 1 possible extra opcode + 4 byte displacement go in var part.
Pass reloc in fr_var. */
frag_var (rs_machine_dependent, 5,
((!object_64bit
|| i.reloc[0] != NO_RELOC
|| (i.bnd_prefix == NULL && !add_bnd_prefix))
? i.reloc[0]
: BFD_RELOC_X86_64_PC32_BND),
subtype, sym, off, p);
}
 
static void
output_jump (void)
{
char *p;
int size;
fixS *fixP;
 
if (i.tm.opcode_modifier.jumpbyte)
{
/* This is a loop or jecxz type instruction. */
size = 1;
if (i.prefix[ADDR_PREFIX] != 0)
{
FRAG_APPEND_1_CHAR (ADDR_PREFIX_OPCODE);
i.prefixes -= 1;
}
/* Pentium4 branch hints. */
if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE /* not taken */
|| i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE /* taken */)
{
FRAG_APPEND_1_CHAR (i.prefix[SEG_PREFIX]);
i.prefixes--;
}
}
else
{
int code16;
 
code16 = 0;
if (flag_code == CODE_16BIT)
code16 = CODE16;
 
if (i.prefix[DATA_PREFIX] != 0)
{
FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
i.prefixes -= 1;
code16 ^= CODE16;
}
 
size = 4;
if (code16)
size = 2;
}
 
if (i.prefix[REX_PREFIX] != 0)
{
FRAG_APPEND_1_CHAR (i.prefix[REX_PREFIX]);
i.prefixes -= 1;
}
 
/* BND prefixed jump. */
if (i.prefix[BND_PREFIX] != 0)
{
FRAG_APPEND_1_CHAR (i.prefix[BND_PREFIX]);
i.prefixes -= 1;
}
 
if (i.prefixes != 0 && !intel_syntax)
as_warn (_("skipping prefixes on this instruction"));
 
p = frag_more (i.tm.opcode_length + size);
switch (i.tm.opcode_length)
{
case 2:
*p++ = i.tm.base_opcode >> 8;
case 1:
*p++ = i.tm.base_opcode;
break;
default:
abort ();
}
 
fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size,
i.op[0].disps, 1, reloc (size, 1, 1,
(i.bnd_prefix != NULL
|| add_bnd_prefix),
i.reloc[0]));
 
/* All jumps handled here are signed, but don't use a signed limit
check for 32 and 16 bit jumps as we want to allow wrap around at
4G and 64k respectively. */
if (size == 1)
fixP->fx_signed = 1;
}
 
static void
output_interseg_jump (void)
{
char *p;
int size;
int prefix;
int code16;
 
code16 = 0;
if (flag_code == CODE_16BIT)
code16 = CODE16;
 
prefix = 0;
if (i.prefix[DATA_PREFIX] != 0)
{
prefix = 1;
i.prefixes -= 1;
code16 ^= CODE16;
}
if (i.prefix[REX_PREFIX] != 0)
{
prefix++;
i.prefixes -= 1;
}
 
size = 4;
if (code16)
size = 2;
 
if (i.prefixes != 0 && !intel_syntax)
as_warn (_("skipping prefixes on this instruction"));
 
/* 1 opcode; 2 segment; offset */
p = frag_more (prefix + 1 + 2 + size);
 
if (i.prefix[DATA_PREFIX] != 0)
*p++ = DATA_PREFIX_OPCODE;
 
if (i.prefix[REX_PREFIX] != 0)
*p++ = i.prefix[REX_PREFIX];
 
*p++ = i.tm.base_opcode;
if (i.op[1].imms->X_op == O_constant)
{
offsetT n = i.op[1].imms->X_add_number;
 
if (size == 2
&& !fits_in_unsigned_word (n)
&& !fits_in_signed_word (n))
{
as_bad (_("16-bit jump out of range"));
return;
}
md_number_to_chars (p, n, size);
}
else
fix_new_exp (frag_now, p - frag_now->fr_literal, size,
i.op[1].imms, 0, reloc (size, 0, 0, 0, i.reloc[1]));
if (i.op[0].imms->X_op != O_constant)
as_bad (_("can't handle non absolute segment in `%s'"),
i.tm.name);
md_number_to_chars (p + size, (valueT) i.op[0].imms->X_add_number, 2);
}
 
static void
output_insn (void)
{
fragS *insn_start_frag;
offsetT insn_start_off;
 
/* Tie dwarf2 debug info to the address at the start of the insn.
We can't do this after the insn has been output as the current
frag may have been closed off. eg. by frag_var. */
dwarf2_emit_insn (0);
 
insn_start_frag = frag_now;
insn_start_off = frag_now_fix ();
 
/* Output jumps. */
if (i.tm.opcode_modifier.jump)
output_branch ();
else if (i.tm.opcode_modifier.jumpbyte
|| i.tm.opcode_modifier.jumpdword)
output_jump ();
else if (i.tm.opcode_modifier.jumpintersegment)
output_interseg_jump ();
else
{
/* Output normal instructions here. */
char *p;
unsigned char *q;
unsigned int j;
unsigned int prefix;
 
/* Since the VEX/EVEX prefix contains the implicit prefix, we
don't need the explicit prefix. */
if (!i.tm.opcode_modifier.vex && !i.tm.opcode_modifier.evex)
{
switch (i.tm.opcode_length)
{
case 3:
if (i.tm.base_opcode & 0xff000000)
{
prefix = (i.tm.base_opcode >> 24) & 0xff;
goto check_prefix;
}
break;
case 2:
if ((i.tm.base_opcode & 0xff0000) != 0)
{
prefix = (i.tm.base_opcode >> 16) & 0xff;
if (i.tm.cpu_flags.bitfield.cpupadlock)
{
check_prefix:
if (prefix != REPE_PREFIX_OPCODE
|| (i.prefix[REP_PREFIX]
!= REPE_PREFIX_OPCODE))
add_prefix (prefix);
}
else
add_prefix (prefix);
}
break;
case 1:
break;
default:
abort ();
}
 
/* The prefix bytes. */
for (j = ARRAY_SIZE (i.prefix), q = i.prefix; j > 0; j--, q++)
if (*q)
FRAG_APPEND_1_CHAR (*q);
}
else
{
for (j = 0, q = i.prefix; j < ARRAY_SIZE (i.prefix); j++, q++)
if (*q)
switch (j)
{
case REX_PREFIX:
/* REX byte is encoded in VEX prefix. */
break;
case SEG_PREFIX:
case ADDR_PREFIX:
FRAG_APPEND_1_CHAR (*q);
break;
default:
/* There should be no other prefixes for instructions
with VEX prefix. */
abort ();
}
 
/* For EVEX instructions i.vrex should become 0 after
build_evex_prefix. For VEX instructions upper 16 registers
aren't available, so VREX should be 0. */
if (i.vrex)
abort ();
/* Now the VEX prefix. */
p = frag_more (i.vex.length);
for (j = 0; j < i.vex.length; j++)
p[j] = i.vex.bytes[j];
}
 
/* Now the opcode; be careful about word order here! */
if (i.tm.opcode_length == 1)
{
FRAG_APPEND_1_CHAR (i.tm.base_opcode);
}
else
{
switch (i.tm.opcode_length)
{
case 4:
p = frag_more (4);
*p++ = (i.tm.base_opcode >> 24) & 0xff;
*p++ = (i.tm.base_opcode >> 16) & 0xff;
break;
case 3:
p = frag_more (3);
*p++ = (i.tm.base_opcode >> 16) & 0xff;
break;
case 2:
p = frag_more (2);
break;
default:
abort ();
break;
}
 
/* Put out high byte first: can't use md_number_to_chars! */
*p++ = (i.tm.base_opcode >> 8) & 0xff;
*p = i.tm.base_opcode & 0xff;
}
 
/* Now the modrm byte and sib byte (if present). */
if (i.tm.opcode_modifier.modrm)
{
FRAG_APPEND_1_CHAR ((i.rm.regmem << 0
| i.rm.reg << 3
| i.rm.mode << 6));
/* If i.rm.regmem == ESP (4)
&& i.rm.mode != (Register mode)
&& not 16 bit
==> need second modrm byte. */
if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING
&& i.rm.mode != 3
&& !(i.base_reg && i.base_reg->reg_type.bitfield.reg16))
FRAG_APPEND_1_CHAR ((i.sib.base << 0
| i.sib.index << 3
| i.sib.scale << 6));
}
 
if (i.disp_operands)
output_disp (insn_start_frag, insn_start_off);
 
if (i.imm_operands)
output_imm (insn_start_frag, insn_start_off);
}
 
#ifdef DEBUG386
if (flag_debug)
{
pi ("" /*line*/, &i);
}
#endif /* DEBUG386 */
}
 
/* Return the size of the displacement operand N. */
 
static int
disp_size (unsigned int n)
{
int size = 4;
 
/* Vec_Disp8 has to be 8bit. */
if (i.types[n].bitfield.vec_disp8)
size = 1;
else if (i.types[n].bitfield.disp64)
size = 8;
else if (i.types[n].bitfield.disp8)
size = 1;
else if (i.types[n].bitfield.disp16)
size = 2;
return size;
}
 
/* Return the size of the immediate operand N. */
 
static int
imm_size (unsigned int n)
{
int size = 4;
if (i.types[n].bitfield.imm64)
size = 8;
else if (i.types[n].bitfield.imm8 || i.types[n].bitfield.imm8s)
size = 1;
else if (i.types[n].bitfield.imm16)
size = 2;
return size;
}
 
static void
output_disp (fragS *insn_start_frag, offsetT insn_start_off)
{
char *p;
unsigned int n;
 
for (n = 0; n < i.operands; n++)
{
if (i.types[n].bitfield.vec_disp8
|| operand_type_check (i.types[n], disp))
{
if (i.op[n].disps->X_op == O_constant)
{
int size = disp_size (n);
offsetT val = i.op[n].disps->X_add_number;
 
if (i.types[n].bitfield.vec_disp8)
val >>= i.memshift;
val = offset_in_range (val, size);
p = frag_more (size);
md_number_to_chars (p, val, size);
}
else
{
enum bfd_reloc_code_real reloc_type;
int size = disp_size (n);
int sign = i.types[n].bitfield.disp32s;
int pcrel = (i.flags[n] & Operand_PCrel) != 0;
 
/* We can't have 8 bit displacement here. */
gas_assert (!i.types[n].bitfield.disp8);
 
/* The PC relative address is computed relative
to the instruction boundary, so in case immediate
fields follows, we need to adjust the value. */
if (pcrel && i.imm_operands)
{
unsigned int n1;
int sz = 0;
 
for (n1 = 0; n1 < i.operands; n1++)
if (operand_type_check (i.types[n1], imm))
{
/* Only one immediate is allowed for PC
relative address. */
gas_assert (sz == 0);
sz = imm_size (n1);
i.op[n].disps->X_add_number -= sz;
}
/* We should find the immediate. */
gas_assert (sz != 0);
}
 
p = frag_more (size);
reloc_type = reloc (size, pcrel, sign,
(i.bnd_prefix != NULL
|| add_bnd_prefix),
i.reloc[n]);
if (GOT_symbol
&& GOT_symbol == i.op[n].disps->X_add_symbol
&& (((reloc_type == BFD_RELOC_32
|| reloc_type == BFD_RELOC_X86_64_32S
|| (reloc_type == BFD_RELOC_64
&& object_64bit))
&& (i.op[n].disps->X_op == O_symbol
|| (i.op[n].disps->X_op == O_add
&& ((symbol_get_value_expression
(i.op[n].disps->X_op_symbol)->X_op)
== O_subtract))))
|| reloc_type == BFD_RELOC_32_PCREL))
{
offsetT add;
 
if (insn_start_frag == frag_now)
add = (p - frag_now->fr_literal) - insn_start_off;
else
{
fragS *fr;
 
add = insn_start_frag->fr_fix - insn_start_off;
for (fr = insn_start_frag->fr_next;
fr && fr != frag_now; fr = fr->fr_next)
add += fr->fr_fix;
add += p - frag_now->fr_literal;
}
 
if (!object_64bit)
{
reloc_type = BFD_RELOC_386_GOTPC;
i.op[n].imms->X_add_number += add;
}
else if (reloc_type == BFD_RELOC_64)
reloc_type = BFD_RELOC_X86_64_GOTPC64;
else
/* Don't do the adjustment for x86-64, as there
the pcrel addressing is relative to the _next_
insn, and that is taken care of in other code. */
reloc_type = BFD_RELOC_X86_64_GOTPC32;
}
fix_new_exp (frag_now, p - frag_now->fr_literal, size,
i.op[n].disps, pcrel, reloc_type);
}
}
}
}
 
static void
output_imm (fragS *insn_start_frag, offsetT insn_start_off)
{
char *p;
unsigned int n;
 
for (n = 0; n < i.operands; n++)
{
/* Skip SAE/RC Imm operand in EVEX. They are already handled. */
if (i.rounding && (int) n == i.rounding->operand)
continue;
 
if (operand_type_check (i.types[n], imm))
{
if (i.op[n].imms->X_op == O_constant)
{
int size = imm_size (n);
offsetT val;
 
val = offset_in_range (i.op[n].imms->X_add_number,
size);
p = frag_more (size);
md_number_to_chars (p, val, size);
}
else
{
/* Not absolute_section.
Need a 32-bit fixup (don't support 8bit
non-absolute imms). Try to support other
sizes ... */
enum bfd_reloc_code_real reloc_type;
int size = imm_size (n);
int sign;
 
if (i.types[n].bitfield.imm32s
&& (i.suffix == QWORD_MNEM_SUFFIX
|| (!i.suffix && i.tm.opcode_modifier.no_lsuf)))
sign = 1;
else
sign = 0;
 
p = frag_more (size);
reloc_type = reloc (size, 0, sign, 0, i.reloc[n]);
 
/* This is tough to explain. We end up with this one if we
* have operands that look like
* "_GLOBAL_OFFSET_TABLE_+[.-.L284]". The goal here is to
* obtain the absolute address of the GOT, and it is strongly
* preferable from a performance point of view to avoid using
* a runtime relocation for this. The actual sequence of
* instructions often look something like:
*
* call .L66
* .L66:
* popl %ebx
* addl $_GLOBAL_OFFSET_TABLE_+[.-.L66],%ebx
*
* The call and pop essentially return the absolute address
* of the label .L66 and store it in %ebx. The linker itself
* will ultimately change the first operand of the addl so
* that %ebx points to the GOT, but to keep things simple, the
* .o file must have this operand set so that it generates not
* the absolute address of .L66, but the absolute address of
* itself. This allows the linker itself simply treat a GOTPC
* relocation as asking for a pcrel offset to the GOT to be
* added in, and the addend of the relocation is stored in the
* operand field for the instruction itself.
*
* Our job here is to fix the operand so that it would add
* the correct offset so that %ebx would point to itself. The
* thing that is tricky is that .-.L66 will point to the
* beginning of the instruction, so we need to further modify
* the operand so that it will point to itself. There are
* other cases where you have something like:
*
* .long $_GLOBAL_OFFSET_TABLE_+[.-.L66]
*
* and here no correction would be required. Internally in
* the assembler we treat operands of this form as not being
* pcrel since the '.' is explicitly mentioned, and I wonder
* whether it would simplify matters to do it this way. Who
* knows. In earlier versions of the PIC patches, the
* pcrel_adjust field was used to store the correction, but
* since the expression is not pcrel, I felt it would be
* confusing to do it this way. */
 
if ((reloc_type == BFD_RELOC_32
|| reloc_type == BFD_RELOC_X86_64_32S
|| reloc_type == BFD_RELOC_64)
&& GOT_symbol
&& GOT_symbol == i.op[n].imms->X_add_symbol
&& (i.op[n].imms->X_op == O_symbol
|| (i.op[n].imms->X_op == O_add
&& ((symbol_get_value_expression
(i.op[n].imms->X_op_symbol)->X_op)
== O_subtract))))
{
offsetT add;
 
if (insn_start_frag == frag_now)
add = (p - frag_now->fr_literal) - insn_start_off;
else
{
fragS *fr;
 
add = insn_start_frag->fr_fix - insn_start_off;
for (fr = insn_start_frag->fr_next;
fr && fr != frag_now; fr = fr->fr_next)
add += fr->fr_fix;
add += p - frag_now->fr_literal;
}
 
if (!object_64bit)
reloc_type = BFD_RELOC_386_GOTPC;
else if (size == 4)
reloc_type = BFD_RELOC_X86_64_GOTPC32;
else if (size == 8)
reloc_type = BFD_RELOC_X86_64_GOTPC64;
i.op[n].imms->X_add_number += add;
}
fix_new_exp (frag_now, p - frag_now->fr_literal, size,
i.op[n].imms, 0, reloc_type);
}
}
}
}
/* x86_cons_fix_new is called via the expression parsing code when a
reloc is needed. We use this hook to get the correct .got reloc. */
static enum bfd_reloc_code_real got_reloc = NO_RELOC;
static int cons_sign = -1;
 
void
x86_cons_fix_new (fragS *frag, unsigned int off, unsigned int len,
expressionS *exp)
{
enum bfd_reloc_code_real r = reloc (len, 0, cons_sign, 0, got_reloc);
 
got_reloc = NO_RELOC;
 
#ifdef TE_PE
if (exp->X_op == O_secrel)
{
exp->X_op = O_symbol;
r = BFD_RELOC_32_SECREL;
}
#endif
 
fix_new_exp (frag, off, len, exp, 0, r);
}
 
/* Export the ABI address size for use by TC_ADDRESS_BYTES for the
purpose of the `.dc.a' internal pseudo-op. */
 
int
x86_address_bytes (void)
{
if ((stdoutput->arch_info->mach & bfd_mach_x64_32))
return 4;
return stdoutput->arch_info->bits_per_address / 8;
}
 
#if !(defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined (OBJ_MACH_O)) \
|| defined (LEX_AT)
# define lex_got(reloc, adjust, types, bnd_prefix) NULL
#else
/* Parse operands of the form
<symbol>@GOTOFF+<nnn>
and similar .plt or .got references.
 
If we find one, set up the correct relocation in RELOC and copy the
input string, minus the `@GOTOFF' into a malloc'd buffer for
parsing by the calling routine. Return this buffer, and if ADJUST
is non-null set it to the length of the string we removed from the
input line. Otherwise return NULL. */
static char *
lex_got (enum bfd_reloc_code_real *rel,
int *adjust,
i386_operand_type *types,
int bnd_prefix)
{
/* Some of the relocations depend on the size of what field is to
be relocated. But in our callers i386_immediate and i386_displacement
we don't yet know the operand size (this will be set by insn
matching). Hence we record the word32 relocation here,
and adjust the reloc according to the real size in reloc(). */
static const struct {
const char *str;
int len;
const enum bfd_reloc_code_real rel[2];
const i386_operand_type types64;
} gotrel[] = {
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
{ STRING_COMMA_LEN ("SIZE"), { BFD_RELOC_SIZE32,
BFD_RELOC_SIZE32 },
OPERAND_TYPE_IMM32_64 },
#endif
{ STRING_COMMA_LEN ("PLTOFF"), { _dummy_first_bfd_reloc_code_real,
BFD_RELOC_X86_64_PLTOFF64 },
OPERAND_TYPE_IMM64 },
{ STRING_COMMA_LEN ("PLT"), { BFD_RELOC_386_PLT32,
BFD_RELOC_X86_64_PLT32 },
OPERAND_TYPE_IMM32_32S_DISP32 },
{ STRING_COMMA_LEN ("GOTPLT"), { _dummy_first_bfd_reloc_code_real,
BFD_RELOC_X86_64_GOTPLT64 },
OPERAND_TYPE_IMM64_DISP64 },
{ STRING_COMMA_LEN ("GOTOFF"), { BFD_RELOC_386_GOTOFF,
BFD_RELOC_X86_64_GOTOFF64 },
OPERAND_TYPE_IMM64_DISP64 },
{ STRING_COMMA_LEN ("GOTPCREL"), { _dummy_first_bfd_reloc_code_real,
BFD_RELOC_X86_64_GOTPCREL },
OPERAND_TYPE_IMM32_32S_DISP32 },
{ STRING_COMMA_LEN ("TLSGD"), { BFD_RELOC_386_TLS_GD,
BFD_RELOC_X86_64_TLSGD },
OPERAND_TYPE_IMM32_32S_DISP32 },
{ STRING_COMMA_LEN ("TLSLDM"), { BFD_RELOC_386_TLS_LDM,
_dummy_first_bfd_reloc_code_real },
OPERAND_TYPE_NONE },
{ STRING_COMMA_LEN ("TLSLD"), { _dummy_first_bfd_reloc_code_real,
BFD_RELOC_X86_64_TLSLD },
OPERAND_TYPE_IMM32_32S_DISP32 },
{ STRING_COMMA_LEN ("GOTTPOFF"), { BFD_RELOC_386_TLS_IE_32,
BFD_RELOC_X86_64_GOTTPOFF },
OPERAND_TYPE_IMM32_32S_DISP32 },
{ STRING_COMMA_LEN ("TPOFF"), { BFD_RELOC_386_TLS_LE_32,
BFD_RELOC_X86_64_TPOFF32 },
OPERAND_TYPE_IMM32_32S_64_DISP32_64 },
{ STRING_COMMA_LEN ("NTPOFF"), { BFD_RELOC_386_TLS_LE,
_dummy_first_bfd_reloc_code_real },
OPERAND_TYPE_NONE },
{ STRING_COMMA_LEN ("DTPOFF"), { BFD_RELOC_386_TLS_LDO_32,
BFD_RELOC_X86_64_DTPOFF32 },
OPERAND_TYPE_IMM32_32S_64_DISP32_64 },
{ STRING_COMMA_LEN ("GOTNTPOFF"),{ BFD_RELOC_386_TLS_GOTIE,
_dummy_first_bfd_reloc_code_real },
OPERAND_TYPE_NONE },
{ STRING_COMMA_LEN ("INDNTPOFF"),{ BFD_RELOC_386_TLS_IE,
_dummy_first_bfd_reloc_code_real },
OPERAND_TYPE_NONE },
{ STRING_COMMA_LEN ("GOT"), { BFD_RELOC_386_GOT32,
BFD_RELOC_X86_64_GOT32 },
OPERAND_TYPE_IMM32_32S_64_DISP32 },
{ STRING_COMMA_LEN ("TLSDESC"), { BFD_RELOC_386_TLS_GOTDESC,
BFD_RELOC_X86_64_GOTPC32_TLSDESC },
OPERAND_TYPE_IMM32_32S_DISP32 },
{ STRING_COMMA_LEN ("TLSCALL"), { BFD_RELOC_386_TLS_DESC_CALL,
BFD_RELOC_X86_64_TLSDESC_CALL },
OPERAND_TYPE_IMM32_32S_DISP32 },
};
char *cp;
unsigned int j;
 
#if defined (OBJ_MAYBE_ELF)
if (!IS_ELF)
return NULL;
#endif
 
for (cp = input_line_pointer; *cp != '@'; cp++)
if (is_end_of_line[(unsigned char) *cp] || *cp == ',')
return NULL;
 
for (j = 0; j < ARRAY_SIZE (gotrel); j++)
{
int len = gotrel[j].len;
if (strncasecmp (cp + 1, gotrel[j].str, len) == 0)
{
if (gotrel[j].rel[object_64bit] != 0)
{
int first, second;
char *tmpbuf, *past_reloc;
 
*rel = gotrel[j].rel[object_64bit];
 
if (types)
{
if (flag_code != CODE_64BIT)
{
types->bitfield.imm32 = 1;
types->bitfield.disp32 = 1;
}
else
*types = gotrel[j].types64;
}
 
if (j != 0 && GOT_symbol == NULL)
GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
 
/* The length of the first part of our input line. */
first = cp - input_line_pointer;
 
/* The second part goes from after the reloc token until
(and including) an end_of_line char or comma. */
past_reloc = cp + 1 + len;
cp = past_reloc;
while (!is_end_of_line[(unsigned char) *cp] && *cp != ',')
++cp;
second = cp + 1 - past_reloc;
 
/* Allocate and copy string. The trailing NUL shouldn't
be necessary, but be safe. */
tmpbuf = (char *) xmalloc (first + second + 2);
memcpy (tmpbuf, input_line_pointer, first);
if (second != 0 && *past_reloc != ' ')
/* Replace the relocation token with ' ', so that
errors like foo@GOTOFF1 will be detected. */
tmpbuf[first++] = ' ';
else
/* Increment length by 1 if the relocation token is
removed. */
len++;
if (adjust)
*adjust = len;
memcpy (tmpbuf + first, past_reloc, second);
tmpbuf[first + second] = '\0';
if (bnd_prefix && *rel == BFD_RELOC_X86_64_PLT32)
*rel = BFD_RELOC_X86_64_PLT32_BND;
return tmpbuf;
}
 
as_bad (_("@%s reloc is not supported with %d-bit output format"),
gotrel[j].str, 1 << (5 + object_64bit));
return NULL;
}
}
 
/* Might be a symbol version string. Don't as_bad here. */
return NULL;
}
#endif
 
#ifdef TE_PE
#ifdef lex_got
#undef lex_got
#endif
/* Parse operands of the form
<symbol>@SECREL32+<nnn>
 
If we find one, set up the correct relocation in RELOC and copy the
input string, minus the `@SECREL32' into a malloc'd buffer for
parsing by the calling routine. Return this buffer, and if ADJUST
is non-null set it to the length of the string we removed from the
input line. Otherwise return NULL.
 
This function is copied from the ELF version above adjusted for PE targets. */
 
static char *
lex_got (enum bfd_reloc_code_real *rel ATTRIBUTE_UNUSED,
int *adjust ATTRIBUTE_UNUSED,
i386_operand_type *types,
int bnd_prefix ATTRIBUTE_UNUSED)
{
static const struct
{
const char *str;
int len;
const enum bfd_reloc_code_real rel[2];
const i386_operand_type types64;
}
gotrel[] =
{
{ STRING_COMMA_LEN ("SECREL32"), { BFD_RELOC_32_SECREL,
BFD_RELOC_32_SECREL },
OPERAND_TYPE_IMM32_32S_64_DISP32_64 },
};
 
char *cp;
unsigned j;
 
for (cp = input_line_pointer; *cp != '@'; cp++)
if (is_end_of_line[(unsigned char) *cp] || *cp == ',')
return NULL;
 
for (j = 0; j < ARRAY_SIZE (gotrel); j++)
{
int len = gotrel[j].len;
 
if (strncasecmp (cp + 1, gotrel[j].str, len) == 0)
{
if (gotrel[j].rel[object_64bit] != 0)
{
int first, second;
char *tmpbuf, *past_reloc;
 
*rel = gotrel[j].rel[object_64bit];
if (adjust)
*adjust = len;
 
if (types)
{
if (flag_code != CODE_64BIT)
{
types->bitfield.imm32 = 1;
types->bitfield.disp32 = 1;
}
else
*types = gotrel[j].types64;
}
 
/* The length of the first part of our input line. */
first = cp - input_line_pointer;
 
/* The second part goes from after the reloc token until
(and including) an end_of_line char or comma. */
past_reloc = cp + 1 + len;
cp = past_reloc;
while (!is_end_of_line[(unsigned char) *cp] && *cp != ',')
++cp;
second = cp + 1 - past_reloc;
 
/* Allocate and copy string. The trailing NUL shouldn't
be necessary, but be safe. */
tmpbuf = (char *) xmalloc (first + second + 2);
memcpy (tmpbuf, input_line_pointer, first);
if (second != 0 && *past_reloc != ' ')
/* Replace the relocation token with ' ', so that
errors like foo@SECLREL321 will be detected. */
tmpbuf[first++] = ' ';
memcpy (tmpbuf + first, past_reloc, second);
tmpbuf[first + second] = '\0';
return tmpbuf;
}
 
as_bad (_("@%s reloc is not supported with %d-bit output format"),
gotrel[j].str, 1 << (5 + object_64bit));
return NULL;
}
}
 
/* Might be a symbol version string. Don't as_bad here. */
return NULL;
}
 
#endif /* TE_PE */
 
void
x86_cons (expressionS *exp, int size)
{
intel_syntax = -intel_syntax;
 
exp->X_md = 0;
if (size == 4 || (object_64bit && size == 8))
{
/* Handle @GOTOFF and the like in an expression. */
char *save;
char *gotfree_input_line;
int adjust = 0;
 
save = input_line_pointer;
gotfree_input_line = lex_got (&got_reloc, &adjust, NULL, 0);
if (gotfree_input_line)
input_line_pointer = gotfree_input_line;
 
expression (exp);
 
if (gotfree_input_line)
{
/* expression () has merrily parsed up to the end of line,
or a comma - in the wrong buffer. Transfer how far
input_line_pointer has moved to the right buffer. */
input_line_pointer = (save
+ (input_line_pointer - gotfree_input_line)
+ adjust);
free (gotfree_input_line);
if (exp->X_op == O_constant
|| exp->X_op == O_absent
|| exp->X_op == O_illegal
|| exp->X_op == O_register
|| exp->X_op == O_big)
{
char c = *input_line_pointer;
*input_line_pointer = 0;
as_bad (_("missing or invalid expression `%s'"), save);
*input_line_pointer = c;
}
}
}
else
expression (exp);
 
intel_syntax = -intel_syntax;
 
if (intel_syntax)
i386_intel_simplify (exp);
}
 
static void
signed_cons (int size)
{
if (flag_code == CODE_64BIT)
cons_sign = 1;
cons (size);
cons_sign = -1;
}
 
#ifdef TE_PE
static void
pe_directive_secrel (int dummy ATTRIBUTE_UNUSED)
{
expressionS exp;
 
do
{
expression (&exp);
if (exp.X_op == O_symbol)
exp.X_op = O_secrel;
 
emit_expr (&exp, 4);
}
while (*input_line_pointer++ == ',');
 
input_line_pointer--;
demand_empty_rest_of_line ();
}
#endif
 
/* Handle Vector operations. */
 
static char *
check_VecOperations (char *op_string, char *op_end)
{
const reg_entry *mask;
const char *saved;
char *end_op;
 
while (*op_string
&& (op_end == NULL || op_string < op_end))
{
saved = op_string;
if (*op_string == '{')
{
op_string++;
 
/* Check broadcasts. */
if (strncmp (op_string, "1to", 3) == 0)
{
int bcst_type;
 
if (i.broadcast)
goto duplicated_vec_op;
 
op_string += 3;
if (*op_string == '8')
bcst_type = BROADCAST_1TO8;
else if (*op_string == '1'
&& *(op_string+1) == '6')
{
bcst_type = BROADCAST_1TO16;
op_string++;
}
else
{
as_bad (_("Unsupported broadcast: `%s'"), saved);
return NULL;
}
op_string++;
 
broadcast_op.type = bcst_type;
broadcast_op.operand = this_operand;
i.broadcast = &broadcast_op;
}
/* Check masking operation. */
else if ((mask = parse_register (op_string, &end_op)) != NULL)
{
/* k0 can't be used for write mask. */
if (mask->reg_num == 0)
{
as_bad (_("`%s' can't be used for write mask"),
op_string);
return NULL;
}
 
if (!i.mask)
{
mask_op.mask = mask;
mask_op.zeroing = 0;
mask_op.operand = this_operand;
i.mask = &mask_op;
}
else
{
if (i.mask->mask)
goto duplicated_vec_op;
 
i.mask->mask = mask;
 
/* Only "{z}" is allowed here. No need to check
zeroing mask explicitly. */
if (i.mask->operand != this_operand)
{
as_bad (_("invalid write mask `%s'"), saved);
return NULL;
}
}
 
op_string = end_op;
}
/* Check zeroing-flag for masking operation. */
else if (*op_string == 'z')
{
if (!i.mask)
{
mask_op.mask = NULL;
mask_op.zeroing = 1;
mask_op.operand = this_operand;
i.mask = &mask_op;
}
else
{
if (i.mask->zeroing)
{
duplicated_vec_op:
as_bad (_("duplicated `%s'"), saved);
return NULL;
}
 
i.mask->zeroing = 1;
 
/* Only "{%k}" is allowed here. No need to check mask
register explicitly. */
if (i.mask->operand != this_operand)
{
as_bad (_("invalid zeroing-masking `%s'"),
saved);
return NULL;
}
}
 
op_string++;
}
else
goto unknown_vec_op;
 
if (*op_string != '}')
{
as_bad (_("missing `}' in `%s'"), saved);
return NULL;
}
op_string++;
continue;
}
unknown_vec_op:
/* We don't know this one. */
as_bad (_("unknown vector operation: `%s'"), saved);
return NULL;
}
 
return op_string;
}
 
static int
i386_immediate (char *imm_start)
{
char *save_input_line_pointer;
char *gotfree_input_line;
segT exp_seg = 0;
expressionS *exp;
i386_operand_type types;
 
operand_type_set (&types, ~0);
 
if (i.imm_operands == MAX_IMMEDIATE_OPERANDS)
{
as_bad (_("at most %d immediate operands are allowed"),
MAX_IMMEDIATE_OPERANDS);
return 0;
}
 
exp = &im_expressions[i.imm_operands++];
i.op[this_operand].imms = exp;
 
if (is_space_char (*imm_start))
++imm_start;
 
save_input_line_pointer = input_line_pointer;
input_line_pointer = imm_start;
 
gotfree_input_line = lex_got (&i.reloc[this_operand], NULL, &types,
(i.bnd_prefix != NULL
|| add_bnd_prefix));
if (gotfree_input_line)
input_line_pointer = gotfree_input_line;
 
exp_seg = expression (exp);
 
SKIP_WHITESPACE ();
 
/* Handle vector operations. */
if (*input_line_pointer == '{')
{
input_line_pointer = check_VecOperations (input_line_pointer,
NULL);
if (input_line_pointer == NULL)
return 0;
}
 
if (*input_line_pointer)
as_bad (_("junk `%s' after expression"), input_line_pointer);
 
input_line_pointer = save_input_line_pointer;
if (gotfree_input_line)
{
free (gotfree_input_line);
 
if (exp->X_op == O_constant || exp->X_op == O_register)
exp->X_op = O_illegal;
}
 
return i386_finalize_immediate (exp_seg, exp, types, imm_start);
}
 
static int
i386_finalize_immediate (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp,
i386_operand_type types, const char *imm_start)
{
if (exp->X_op == O_absent || exp->X_op == O_illegal || exp->X_op == O_big)
{
if (imm_start)
as_bad (_("missing or invalid immediate expression `%s'"),
imm_start);
return 0;
}
else if (exp->X_op == O_constant)
{
/* Size it properly later. */
i.types[this_operand].bitfield.imm64 = 1;
/* If not 64bit, sign extend val. */
if (flag_code != CODE_64BIT
&& (exp->X_add_number & ~(((addressT) 2 << 31) - 1)) == 0)
exp->X_add_number
= (exp->X_add_number ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31);
}
#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
else if (OUTPUT_FLAVOR == bfd_target_aout_flavour
&& exp_seg != absolute_section
&& exp_seg != text_section
&& exp_seg != data_section
&& exp_seg != bss_section
&& exp_seg != undefined_section
&& !bfd_is_com_section (exp_seg))
{
as_bad (_("unimplemented segment %s in operand"), exp_seg->name);
return 0;
}
#endif
else if (!intel_syntax && exp->X_op == O_register)
{
if (imm_start)
as_bad (_("illegal immediate register operand %s"), imm_start);
return 0;
}
else
{
/* This is an address. The size of the address will be
determined later, depending on destination register,
suffix, or the default for the section. */
i.types[this_operand].bitfield.imm8 = 1;
i.types[this_operand].bitfield.imm16 = 1;
i.types[this_operand].bitfield.imm32 = 1;
i.types[this_operand].bitfield.imm32s = 1;
i.types[this_operand].bitfield.imm64 = 1;
i.types[this_operand] = operand_type_and (i.types[this_operand],
types);
}
 
return 1;
}
 
static char *
i386_scale (char *scale)
{
offsetT val;
char *save = input_line_pointer;
 
input_line_pointer = scale;
val = get_absolute_expression ();
 
switch (val)
{
case 1:
i.log2_scale_factor = 0;
break;
case 2:
i.log2_scale_factor = 1;
break;
case 4:
i.log2_scale_factor = 2;
break;
case 8:
i.log2_scale_factor = 3;
break;
default:
{
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)
{
as_warn (_("scale factor of %d without an index register"),
1 << i.log2_scale_factor);
i.log2_scale_factor = 0;
}
scale = input_line_pointer;
input_line_pointer = save;
return scale;
}
 
static int
i386_displacement (char *disp_start, char *disp_end)
{
expressionS *exp;
segT exp_seg = 0;
char *save_input_line_pointer;
char *gotfree_input_line;
int override;
i386_operand_type bigdisp, types = anydisp;
int ret;
 
if (i.disp_operands == MAX_MEMORY_OPERANDS)
{
as_bad (_("at most %d displacement operands are allowed"),
MAX_MEMORY_OPERANDS);
return 0;
}
 
operand_type_set (&bigdisp, 0);
if ((i.types[this_operand].bitfield.jumpabsolute)
|| (!current_templates->start->opcode_modifier.jump
&& !current_templates->start->opcode_modifier.jumpdword))
{
bigdisp.bitfield.disp32 = 1;
override = (i.prefix[ADDR_PREFIX] != 0);
if (flag_code == CODE_64BIT)
{
if (!override)
{
bigdisp.bitfield.disp32s = 1;
bigdisp.bitfield.disp64 = 1;
}
}
else if ((flag_code == CODE_16BIT) ^ override)
{
bigdisp.bitfield.disp32 = 0;
bigdisp.bitfield.disp16 = 1;
}
}
else
{
/* For PC-relative branches, the width of the displacement
is dependent upon data size, not address size. */
override = (i.prefix[DATA_PREFIX] != 0);
if (flag_code == CODE_64BIT)
{
if (override || i.suffix == WORD_MNEM_SUFFIX)
bigdisp.bitfield.disp16 = 1;
else
{
bigdisp.bitfield.disp32 = 1;
bigdisp.bitfield.disp32s = 1;
}
}
else
{
if (!override)
override = (i.suffix == (flag_code != CODE_16BIT
? WORD_MNEM_SUFFIX
: LONG_MNEM_SUFFIX));
bigdisp.bitfield.disp32 = 1;
if ((flag_code == CODE_16BIT) ^ override)
{
bigdisp.bitfield.disp32 = 0;
bigdisp.bitfield.disp16 = 1;
}
}
}
i.types[this_operand] = operand_type_or (i.types[this_operand],
bigdisp);
 
exp = &disp_expressions[i.disp_operands];
i.op[this_operand].disps = exp;
i.disp_operands++;
save_input_line_pointer = input_line_pointer;
input_line_pointer = disp_start;
END_STRING_AND_SAVE (disp_end);
 
#ifndef GCC_ASM_O_HACK
#define GCC_ASM_O_HACK 0
#endif
#if GCC_ASM_O_HACK
END_STRING_AND_SAVE (disp_end + 1);
if (i.types[this_operand].bitfield.baseIndex
&& displacement_string_end[-1] == '+')
{
/* This hack is to avoid a warning when using the "o"
constraint within gcc asm statements.
For instance:
 
#define _set_tssldt_desc(n,addr,limit,type) \
__asm__ __volatile__ ( \
"movw %w2,%0\n\t" \
"movw %w1,2+%0\n\t" \
"rorl $16,%1\n\t" \
"movb %b1,4+%0\n\t" \
"movb %4,5+%0\n\t" \
"movb $0,6+%0\n\t" \
"movb %h1,7+%0\n\t" \
"rorl $16,%1" \
: "=o"(*(n)) : "q" (addr), "ri"(limit), "i"(type))
 
This works great except that the output assembler ends
up looking a bit weird if it turns out that there is
no offset. You end up producing code that looks like:
 
#APP
movw $235,(%eax)
movw %dx,2+(%eax)
rorl $16,%edx
movb %dl,4+(%eax)
movb $137,5+(%eax)
movb $0,6+(%eax)
movb %dh,7+(%eax)
rorl $16,%edx
#NO_APP
 
So here we provide the missing zero. */
 
*displacement_string_end = '0';
}
#endif
gotfree_input_line = lex_got (&i.reloc[this_operand], NULL, &types,
(i.bnd_prefix != NULL
|| add_bnd_prefix));
if (gotfree_input_line)
input_line_pointer = gotfree_input_line;
 
exp_seg = expression (exp);
 
SKIP_WHITESPACE ();
if (*input_line_pointer)
as_bad (_("junk `%s' after expression"), input_line_pointer);
#if GCC_ASM_O_HACK
RESTORE_END_STRING (disp_end + 1);
#endif
input_line_pointer = save_input_line_pointer;
if (gotfree_input_line)
{
free (gotfree_input_line);
 
if (exp->X_op == O_constant || exp->X_op == O_register)
exp->X_op = O_illegal;
}
 
ret = i386_finalize_displacement (exp_seg, exp, types, disp_start);
 
RESTORE_END_STRING (disp_end);
 
return ret;
}
 
static int
i386_finalize_displacement (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp,
i386_operand_type types, const char *disp_start)
{
i386_operand_type bigdisp;
int ret = 1;
 
/* We do this to make sure that the section symbol is in
the symbol table. We will ultimately change the relocation
to be relative to the beginning of the section. */
if (i.reloc[this_operand] == BFD_RELOC_386_GOTOFF
|| i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL
|| i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64)
{
if (exp->X_op != O_symbol)
goto inv_disp;
 
if (S_IS_LOCAL (exp->X_add_symbol)
&& S_GET_SEGMENT (exp->X_add_symbol) != undefined_section
&& S_GET_SEGMENT (exp->X_add_symbol) != expr_section)
section_symbol (S_GET_SEGMENT (exp->X_add_symbol));
exp->X_op = O_subtract;
exp->X_op_symbol = GOT_symbol;
if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL)
i.reloc[this_operand] = BFD_RELOC_32_PCREL;
else if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64)
i.reloc[this_operand] = BFD_RELOC_64;
else
i.reloc[this_operand] = BFD_RELOC_32;
}
 
else if (exp->X_op == O_absent
|| exp->X_op == O_illegal
|| exp->X_op == O_big)
{
inv_disp:
as_bad (_("missing or invalid displacement expression `%s'"),
disp_start);
ret = 0;
}
 
else if (flag_code == CODE_64BIT
&& !i.prefix[ADDR_PREFIX]
&& exp->X_op == O_constant)
{
/* Since displacement is signed extended to 64bit, don't allow
disp32 and turn off disp32s if they are out of range. */
i.types[this_operand].bitfield.disp32 = 0;
if (!fits_in_signed_long (exp->X_add_number))
{
i.types[this_operand].bitfield.disp32s = 0;
if (i.types[this_operand].bitfield.baseindex)
{
as_bad (_("0x%lx out range of signed 32bit displacement"),
(long) exp->X_add_number);
ret = 0;
}
}
}
 
#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
else if (exp->X_op != O_constant
&& OUTPUT_FLAVOR == bfd_target_aout_flavour
&& exp_seg != absolute_section
&& exp_seg != text_section
&& exp_seg != data_section
&& exp_seg != bss_section
&& exp_seg != undefined_section
&& !bfd_is_com_section (exp_seg))
{
as_bad (_("unimplemented segment %s in operand"), exp_seg->name);
ret = 0;
}
#endif
 
/* Check if this is a displacement only operand. */
bigdisp = i.types[this_operand];
bigdisp.bitfield.disp8 = 0;
bigdisp.bitfield.disp16 = 0;
bigdisp.bitfield.disp32 = 0;
bigdisp.bitfield.disp32s = 0;
bigdisp.bitfield.disp64 = 0;
if (operand_type_all_zero (&bigdisp))
i.types[this_operand] = operand_type_and (i.types[this_operand],
types);
 
return ret;
}
 
/* Make sure the memory operand we've been dealt is valid.
Return 1 on success, 0 on a failure. */
 
static int
i386_index_check (const char *operand_string)
{
const char *kind = "base/index";
enum flag_code addr_mode;
 
if (i.prefix[ADDR_PREFIX])
addr_mode = flag_code == CODE_32BIT ? CODE_16BIT : CODE_32BIT;
else
{
addr_mode = flag_code;
 
#if INFER_ADDR_PREFIX
if (i.mem_operands == 0)
{
/* Infer address prefix from the first memory operand. */
const reg_entry *addr_reg = i.base_reg;
 
if (addr_reg == NULL)
addr_reg = i.index_reg;
 
if (addr_reg)
{
if (addr_reg->reg_num == RegEip
|| addr_reg->reg_num == RegEiz
|| addr_reg->reg_type.bitfield.reg32)
addr_mode = CODE_32BIT;
else if (flag_code != CODE_64BIT
&& addr_reg->reg_type.bitfield.reg16)
addr_mode = CODE_16BIT;
 
if (addr_mode != flag_code)
{
i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE;
i.prefixes += 1;
/* Change the size of any displacement too. At most one
of Disp16 or Disp32 is set.
FIXME. There doesn't seem to be any real need for
separate Disp16 and Disp32 flags. The same goes for
Imm16 and Imm32. Removing them would probably clean
up the code quite a lot. */
if (flag_code != CODE_64BIT
&& (i.types[this_operand].bitfield.disp16
|| i.types[this_operand].bitfield.disp32))
i.types[this_operand]
= operand_type_xor (i.types[this_operand], disp16_32);
}
}
}
#endif
}
 
if (current_templates->start->opcode_modifier.isstring
&& !current_templates->start->opcode_modifier.immext
&& (current_templates->end[-1].opcode_modifier.isstring
|| i.mem_operands))
{
/* Memory operands of string insns are special in that they only allow
a single register (rDI, rSI, or rBX) as their memory address. */
const reg_entry *expected_reg;
static const char *di_si[][2] =
{
{ "esi", "edi" },
{ "si", "di" },
{ "rsi", "rdi" }
};
static const char *bx[] = { "ebx", "bx", "rbx" };
 
kind = "string address";
 
if (current_templates->start->opcode_modifier.w)
{
i386_operand_type type = current_templates->end[-1].operand_types[0];
 
if (!type.bitfield.baseindex
|| ((!i.mem_operands != !intel_syntax)
&& current_templates->end[-1].operand_types[1]
.bitfield.baseindex))
type = current_templates->end[-1].operand_types[1];
expected_reg = hash_find (reg_hash,
di_si[addr_mode][type.bitfield.esseg]);
 
}
else
expected_reg = hash_find (reg_hash, bx[addr_mode]);
 
if (i.base_reg != expected_reg
|| i.index_reg
|| operand_type_check (i.types[this_operand], disp))
{
/* The second memory operand must have the same size as
the first one. */
if (i.mem_operands
&& i.base_reg
&& !((addr_mode == CODE_64BIT
&& i.base_reg->reg_type.bitfield.reg64)
|| (addr_mode == CODE_32BIT
? i.base_reg->reg_type.bitfield.reg32
: i.base_reg->reg_type.bitfield.reg16)))
goto bad_address;
 
as_warn (_("`%s' is not valid here (expected `%c%s%s%c')"),
operand_string,
intel_syntax ? '[' : '(',
register_prefix,
expected_reg->reg_name,
intel_syntax ? ']' : ')');
return 1;
}
else
return 1;
 
bad_address:
as_bad (_("`%s' is not a valid %s expression"),
operand_string, kind);
return 0;
}
else
{
if (addr_mode != CODE_16BIT)
{
/* 32-bit/64-bit checks. */
if ((i.base_reg
&& (addr_mode == CODE_64BIT
? !i.base_reg->reg_type.bitfield.reg64
: !i.base_reg->reg_type.bitfield.reg32)
&& (i.index_reg
|| (i.base_reg->reg_num
!= (addr_mode == CODE_64BIT ? RegRip : RegEip))))
|| (i.index_reg
&& !i.index_reg->reg_type.bitfield.regxmm
&& !i.index_reg->reg_type.bitfield.regymm
&& !i.index_reg->reg_type.bitfield.regzmm
&& ((addr_mode == CODE_64BIT
? !(i.index_reg->reg_type.bitfield.reg64
|| i.index_reg->reg_num == RegRiz)
: !(i.index_reg->reg_type.bitfield.reg32
|| i.index_reg->reg_num == RegEiz))
|| !i.index_reg->reg_type.bitfield.baseindex)))
goto bad_address;
}
else
{
/* 16-bit checks. */
if ((i.base_reg
&& (!i.base_reg->reg_type.bitfield.reg16
|| !i.base_reg->reg_type.bitfield.baseindex))
|| (i.index_reg
&& (!i.index_reg->reg_type.bitfield.reg16
|| !i.index_reg->reg_type.bitfield.baseindex
|| !(i.base_reg
&& i.base_reg->reg_num < 6
&& i.index_reg->reg_num >= 6
&& i.log2_scale_factor == 0))))
goto bad_address;
}
}
return 1;
}
 
/* Handle vector immediates. */
 
static int
RC_SAE_immediate (const char *imm_start)
{
unsigned int match_found, j;
const char *pstr = imm_start;
expressionS *exp;
 
if (*pstr != '{')
return 0;
 
pstr++;
match_found = 0;
for (j = 0; j < ARRAY_SIZE (RC_NamesTable); j++)
{
if (!strncmp (pstr, RC_NamesTable[j].name, RC_NamesTable[j].len))
{
if (!i.rounding)
{
rc_op.type = RC_NamesTable[j].type;
rc_op.operand = this_operand;
i.rounding = &rc_op;
}
else
{
as_bad (_("duplicated `%s'"), imm_start);
return 0;
}
pstr += RC_NamesTable[j].len;
match_found = 1;
break;
}
}
if (!match_found)
return 0;
 
if (*pstr++ != '}')
{
as_bad (_("Missing '}': '%s'"), imm_start);
return 0;
}
/* RC/SAE immediate string should contain nothing more. */;
if (*pstr != 0)
{
as_bad (_("Junk after '}': '%s'"), imm_start);
return 0;
}
 
exp = &im_expressions[i.imm_operands++];
i.op[this_operand].imms = exp;
 
exp->X_op = O_constant;
exp->X_add_number = 0;
exp->X_add_symbol = (symbolS *) 0;
exp->X_op_symbol = (symbolS *) 0;
 
i.types[this_operand].bitfield.imm8 = 1;
return 1;
}
 
/* Parse OPERAND_STRING into the i386_insn structure I. Returns zero
on error. */
 
static int
i386_att_operand (char *operand_string)
{
const reg_entry *r;
char *end_op;
char *op_string = operand_string;
 
if (is_space_char (*op_string))
++op_string;
 
/* We check for an absolute prefix (differentiating,
for example, 'jmp pc_relative_label' from 'jmp *absolute_label'. */
if (*op_string == ABSOLUTE_PREFIX)
{
++op_string;
if (is_space_char (*op_string))
++op_string;
i.types[this_operand].bitfield.jumpabsolute = 1;
}
 
/* Check if operand is a register. */
if ((r = parse_register (op_string, &end_op)) != NULL)
{
i386_operand_type temp;
 
/* Check for a segment override by searching for ':' after a
segment register. */
op_string = end_op;
if (is_space_char (*op_string))
++op_string;
if (*op_string == ':'
&& (r->reg_type.bitfield.sreg2
|| r->reg_type.bitfield.sreg3))
{
switch (r->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;
}
 
/* Skip the ':' and whitespace. */
++op_string;
if (is_space_char (*op_string))
++op_string;
 
if (!is_digit_char (*op_string)
&& !is_identifier_char (*op_string)
&& *op_string != '('
&& *op_string != ABSOLUTE_PREFIX)
{
as_bad (_("bad memory operand `%s'"), op_string);
return 0;
}
/* Handle case of %es:*foo. */
if (*op_string == ABSOLUTE_PREFIX)
{
++op_string;
if (is_space_char (*op_string))
++op_string;
i.types[this_operand].bitfield.jumpabsolute = 1;
}
goto do_memory_reference;
}
 
/* Handle vector operations. */
if (*op_string == '{')
{
op_string = check_VecOperations (op_string, NULL);
if (op_string == NULL)
return 0;
}
 
if (*op_string)
{
as_bad (_("junk `%s' after register"), op_string);
return 0;
}
temp = r->reg_type;
temp.bitfield.baseindex = 0;
i.types[this_operand] = operand_type_or (i.types[this_operand],
temp);
i.types[this_operand].bitfield.unspecified = 0;
i.op[this_operand].regs = r;
i.reg_operands++;
}
else if (*op_string == REGISTER_PREFIX)
{
as_bad (_("bad register name `%s'"), op_string);
return 0;
}
else if (*op_string == IMMEDIATE_PREFIX)
{
++op_string;
if (i.types[this_operand].bitfield.jumpabsolute)
{
as_bad (_("immediate operand illegal with absolute jump"));
return 0;
}
if (!i386_immediate (op_string))
return 0;
}
else if (RC_SAE_immediate (operand_string))
{
/* If it is a RC or SAE immediate, do nothing. */
;
}
else if (is_digit_char (*op_string)
|| is_identifier_char (*op_string)
|| *op_string == '(')
{
/* This is a memory reference of some sort. */
char *base_string;
 
/* Start and end of displacement string expression (if found). */
char *displacement_string_start;
char *displacement_string_end;
char *vop_start;
 
do_memory_reference:
if ((i.mem_operands == 1
&& !current_templates->start->opcode_modifier.isstring)
|| i.mem_operands == 2)
{
as_bad (_("too many memory references for `%s'"),
current_templates->start->name);
return 0;
}
 
/* Check for base index form. We detect the base index form by
looking for an ')' at the end of the operand, searching
for the '(' matching it, and finding a REGISTER_PREFIX or ','
after the '('. */
base_string = op_string + strlen (op_string);
 
/* Handle vector operations. */
vop_start = strchr (op_string, '{');
if (vop_start && vop_start < base_string)
{
if (check_VecOperations (vop_start, base_string) == NULL)
return 0;
base_string = vop_start;
}
 
--base_string;
if (is_space_char (*base_string))
--base_string;
 
/* If we only have a displacement, set-up for it to be parsed later. */
displacement_string_start = op_string;
displacement_string_end = base_string + 1;
 
if (*base_string == ')')
{
char *temp_string;
unsigned int parens_balanced = 1;
/* We've already checked that the number of left & right ()'s are
equal, so this loop will not be infinite. */
do
{
base_string--;
if (*base_string == ')')
parens_balanced++;
if (*base_string == '(')
parens_balanced--;
}
while (parens_balanced);
 
temp_string = base_string;
 
/* Skip past '(' and whitespace. */
++base_string;
if (is_space_char (*base_string))
++base_string;
 
if (*base_string == ','
|| ((i.base_reg = parse_register (base_string, &end_op))
!= NULL))
{
displacement_string_end = temp_string;
 
i.types[this_operand].bitfield.baseindex = 1;
 
if (i.base_reg)
{
base_string = end_op;
if (is_space_char (*base_string))
++base_string;
}
 
/* There may be an index reg or scale factor here. */
if (*base_string == ',')
{
++base_string;
if (is_space_char (*base_string))
++base_string;
 
if ((i.index_reg = parse_register (base_string, &end_op))
!= NULL)
{
base_string = end_op;
if (is_space_char (*base_string))
++base_string;
if (*base_string == ',')
{
++base_string;
if (is_space_char (*base_string))
++base_string;
}
else if (*base_string != ')')
{
as_bad (_("expecting `,' or `)' "
"after index register in `%s'"),
operand_string);
return 0;
}
}
else if (*base_string == REGISTER_PREFIX)
{
end_op = strchr (base_string, ',');
if (end_op)
*end_op = '\0';
as_bad (_("bad register name `%s'"), base_string);
return 0;
}
 
/* Check for scale factor. */
if (*base_string != ')')
{
char *end_scale = i386_scale (base_string);
 
if (!end_scale)
return 0;
 
base_string = end_scale;
if (is_space_char (*base_string))
++base_string;
if (*base_string != ')')
{
as_bad (_("expecting `)' "
"after scale factor in `%s'"),
operand_string);
return 0;
}
}
else if (!i.index_reg)
{
as_bad (_("expecting index register or scale factor "
"after `,'; got '%c'"),
*base_string);
return 0;
}
}
else if (*base_string != ')')
{
as_bad (_("expecting `,' or `)' "
"after base register in `%s'"),
operand_string);
return 0;
}
}
else if (*base_string == REGISTER_PREFIX)
{
end_op = strchr (base_string, ',');
if (end_op)
*end_op = '\0';
as_bad (_("bad register name `%s'"), base_string);
return 0;
}
}
 
/* If there's an expression beginning the operand, parse it,
assuming displacement_string_start and
displacement_string_end are meaningful. */
if (displacement_string_start != displacement_string_end)
{
if (!i386_displacement (displacement_string_start,
displacement_string_end))
return 0;
}
 
/* Special case for (%dx) while doing input/output op. */
if (i.base_reg
&& operand_type_equal (&i.base_reg->reg_type,
&reg16_inoutportreg)
&& i.index_reg == 0
&& i.log2_scale_factor == 0
&& i.seg[i.mem_operands] == 0
&& !operand_type_check (i.types[this_operand], disp))
{
i.types[this_operand] = inoutportreg;
return 1;
}
 
if (i386_index_check (operand_string) == 0)
return 0;
i.types[this_operand].bitfield.mem = 1;
i.mem_operands++;
}
else
{
/* It's not a memory operand; argh! */
as_bad (_("invalid char %s beginning operand %d `%s'"),
output_invalid (*op_string),
this_operand + 1,
op_string);
return 0;
}
return 1; /* Normal return. */
}
/* Calculate the maximum variable size (i.e., excluding fr_fix)
that an rs_machine_dependent frag may reach. */
 
unsigned int
i386_frag_max_var (fragS *frag)
{
/* The only relaxable frags are for jumps.
Unconditional jumps can grow by 4 bytes and others by 5 bytes. */
gas_assert (frag->fr_type == rs_machine_dependent);
return TYPE_FROM_RELAX_STATE (frag->fr_subtype) == UNCOND_JUMP ? 4 : 5;
}
 
/* md_estimate_size_before_relax()
 
Called just before relax() for rs_machine_dependent frags. The x86
assembler uses these frags to handle variable size jump
instructions.
 
Any symbol that is now undefined will not become defined.
Return the correct fr_subtype in the frag.
Return the initial "guess for variable size of frag" to caller.
The guess is actually the growth beyond the fixed part. Whatever
we do to grow the fixed or variable part contributes to our
returned value. */
 
int
md_estimate_size_before_relax (fragS *fragP, segT segment)
{
/* We've already got fragP->fr_subtype right; all we have to do is
check for un-relaxable symbols. On an ELF system, we can't relax
an externally visible symbol, because it may be overridden by a
shared library. */
if (S_GET_SEGMENT (fragP->fr_symbol) != segment
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
|| (IS_ELF
&& (S_IS_EXTERNAL (fragP->fr_symbol)
|| S_IS_WEAK (fragP->fr_symbol)
|| ((symbol_get_bfdsym (fragP->fr_symbol)->flags
& BSF_GNU_INDIRECT_FUNCTION))))
#endif
#if defined (OBJ_COFF) && defined (TE_PE)
|| (OUTPUT_FLAVOR == bfd_target_coff_flavour
&& S_IS_WEAK (fragP->fr_symbol))
#endif
)
{
/* Symbol is undefined in this segment, or we need to keep a
reloc so that weak symbols can be overridden. */
int size = (fragP->fr_subtype & CODE16) ? 2 : 4;
enum bfd_reloc_code_real reloc_type;
unsigned char *opcode;
int old_fr_fix;
 
if (fragP->fr_var != NO_RELOC)
reloc_type = (enum bfd_reloc_code_real) fragP->fr_var;
else if (size == 2)
reloc_type = BFD_RELOC_16_PCREL;
else
reloc_type = BFD_RELOC_32_PCREL;
 
old_fr_fix = fragP->fr_fix;
opcode = (unsigned char *) fragP->fr_opcode;
 
switch (TYPE_FROM_RELAX_STATE (fragP->fr_subtype))
{
case UNCOND_JUMP:
/* Make jmp (0xeb) a (d)word displacement jump. */
opcode[0] = 0xe9;
fragP->fr_fix += size;
fix_new (fragP, old_fr_fix, size,
fragP->fr_symbol,
fragP->fr_offset, 1,
reloc_type);
break;
 
case COND_JUMP86:
if (size == 2
&& (!no_cond_jump_promotion || fragP->fr_var != NO_RELOC))
{
/* Negate the condition, and branch past an
unconditional jump. */
opcode[0] ^= 1;
opcode[1] = 3;
/* Insert an unconditional jump. */
opcode[2] = 0xe9;
/* We added two extra opcode bytes, and have a two byte
offset. */
fragP->fr_fix += 2 + 2;
fix_new (fragP, old_fr_fix + 2, 2,
fragP->fr_symbol,
fragP->fr_offset, 1,
reloc_type);
break;
}
/* Fall through. */
 
case COND_JUMP:
if (no_cond_jump_promotion && fragP->fr_var == NO_RELOC)
{
fixS *fixP;
 
fragP->fr_fix += 1;
fixP = fix_new (fragP, old_fr_fix, 1,
fragP->fr_symbol,
fragP->fr_offset, 1,
BFD_RELOC_8_PCREL);
fixP->fx_signed = 1;
break;
}
 
/* This changes the byte-displacement jump 0x7N
to the (d)word-displacement jump 0x0f,0x8N. */
opcode[1] = opcode[0] + 0x10;
opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
/* We've added an opcode byte. */
fragP->fr_fix += 1 + size;
fix_new (fragP, old_fr_fix + 1, size,
fragP->fr_symbol,
fragP->fr_offset, 1,
reloc_type);
break;
 
default:
BAD_CASE (fragP->fr_subtype);
break;
}
frag_wane (fragP);
return fragP->fr_fix - old_fr_fix;
}
 
/* Guess size depending on current relax state. Initially the relax
state will correspond to a short jump and we return 1, because
the variable part of the frag (the branch offset) is one byte
long. However, we can relax a section more than once and in that
case we must either set fr_subtype back to the unrelaxed state,
or return the value for the appropriate branch. */
return md_relax_table[fragP->fr_subtype].rlx_length;
}
 
/* Called after relax() is finished.
 
In: Address of frag.
fr_type == rs_machine_dependent.
fr_subtype is what the address relaxed to.
 
Out: Any fixSs and constants are set up.
Caller will turn frag into a ".space 0". */
 
void
md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec ATTRIBUTE_UNUSED,
fragS *fragP)
{
unsigned char *opcode;
unsigned char *where_to_put_displacement = NULL;
offsetT target_address;
offsetT opcode_address;
unsigned int extension = 0;
offsetT displacement_from_opcode_start;
 
opcode = (unsigned char *) fragP->fr_opcode;
 
/* Address we want to reach in file space. */
target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
 
/* Address opcode resides at in file space. */
opcode_address = fragP->fr_address + fragP->fr_fix;
 
/* Displacement from opcode start to fill into instruction. */
displacement_from_opcode_start = target_address - opcode_address;
 
if ((fragP->fr_subtype & BIG) == 0)
{
/* Don't have to change opcode. */
extension = 1; /* 1 opcode + 1 displacement */
where_to_put_displacement = &opcode[1];
}
else
{
if (no_cond_jump_promotion
&& TYPE_FROM_RELAX_STATE (fragP->fr_subtype) != UNCOND_JUMP)
as_warn_where (fragP->fr_file, fragP->fr_line,
_("long jump required"));
 
switch (fragP->fr_subtype)
{
case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG):
extension = 4; /* 1 opcode + 4 displacement */
opcode[0] = 0xe9;
where_to_put_displacement = &opcode[1];
break;
 
case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16):
extension = 2; /* 1 opcode + 2 displacement */
opcode[0] = 0xe9;
where_to_put_displacement = &opcode[1];
break;
 
case ENCODE_RELAX_STATE (COND_JUMP, BIG):
case ENCODE_RELAX_STATE (COND_JUMP86, BIG):
extension = 5; /* 2 opcode + 4 displacement */
opcode[1] = opcode[0] + 0x10;
opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
where_to_put_displacement = &opcode[2];
break;
 
case ENCODE_RELAX_STATE (COND_JUMP, BIG16):
extension = 3; /* 2 opcode + 2 displacement */
opcode[1] = opcode[0] + 0x10;
opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
where_to_put_displacement = &opcode[2];
break;
 
case ENCODE_RELAX_STATE (COND_JUMP86, BIG16):
extension = 4;
opcode[0] ^= 1;
opcode[1] = 3;
opcode[2] = 0xe9;
where_to_put_displacement = &opcode[3];
break;
 
default:
BAD_CASE (fragP->fr_subtype);
break;
}
}
 
/* If size if less then four we are sure that the operand fits,
but if it's 4, then it could be that the displacement is larger
then -/+ 2GB. */
if (DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype) == 4
&& object_64bit
&& ((addressT) (displacement_from_opcode_start - extension
+ ((addressT) 1 << 31))
> (((addressT) 2 << 31) - 1)))
{
as_bad_where (fragP->fr_file, fragP->fr_line,
_("jump target out of range"));
/* Make us emit 0. */
displacement_from_opcode_start = extension;
}
/* Now put displacement after opcode. */
md_number_to_chars ((char *) where_to_put_displacement,
(valueT) (displacement_from_opcode_start - extension),
DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype));
fragP->fr_fix += extension;
}
/* Apply a fixup (fixP) to segment data, once it has been determined
by our caller that we have all the info we need to fix it up.
 
Parameter valP is the pointer to the value of the bits.
 
On the 386, immediates, displacements, and data pointers are all in
the same (little-endian) format, so we don't need to care about which
we are handling. */
 
void
md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
{
char *p = fixP->fx_where + fixP->fx_frag->fr_literal;
valueT value = *valP;
 
#if !defined (TE_Mach)
if (fixP->fx_pcrel)
{
switch (fixP->fx_r_type)
{
default:
break;
 
case BFD_RELOC_64:
fixP->fx_r_type = BFD_RELOC_64_PCREL;
break;
case BFD_RELOC_32:
case BFD_RELOC_X86_64_32S:
fixP->fx_r_type = BFD_RELOC_32_PCREL;
break;
case BFD_RELOC_16:
fixP->fx_r_type = BFD_RELOC_16_PCREL;
break;
case BFD_RELOC_8:
fixP->fx_r_type = BFD_RELOC_8_PCREL;
break;
}
}
 
if (fixP->fx_addsy != NULL
&& (fixP->fx_r_type == BFD_RELOC_32_PCREL
|| fixP->fx_r_type == BFD_RELOC_64_PCREL
|| fixP->fx_r_type == BFD_RELOC_16_PCREL
|| fixP->fx_r_type == BFD_RELOC_8_PCREL
|| fixP->fx_r_type == BFD_RELOC_X86_64_PC32_BND)
&& !use_rela_relocations)
{
/* This is a hack. There should be a better way to handle this.
This covers for the fact that bfd_install_relocation will
subtract the current location (for partial_inplace, PC relative
relocations); see more below. */
#ifndef OBJ_AOUT
if (IS_ELF
#ifdef TE_PE
|| OUTPUT_FLAVOR == bfd_target_coff_flavour
#endif
)
value += fixP->fx_where + fixP->fx_frag->fr_address;
#endif
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
if (IS_ELF)
{
segT sym_seg = S_GET_SEGMENT (fixP->fx_addsy);
 
if ((sym_seg == seg
|| (symbol_section_p (fixP->fx_addsy)
&& sym_seg != absolute_section))
&& !generic_force_reloc (fixP))
{
/* Yes, we add the values in twice. This is because
bfd_install_relocation subtracts them out again. I think
bfd_install_relocation is broken, but I don't dare change
it. FIXME. */
value += fixP->fx_where + fixP->fx_frag->fr_address;
}
}
#endif
#if defined (OBJ_COFF) && defined (TE_PE)
/* For some reason, the PE format does not store a
section address offset for a PC relative symbol. */
if (S_GET_SEGMENT (fixP->fx_addsy) != seg
|| S_IS_WEAK (fixP->fx_addsy))
value += md_pcrel_from (fixP);
#endif
}
#if defined (OBJ_COFF) && defined (TE_PE)
if (fixP->fx_addsy != NULL && S_IS_WEAK (fixP->fx_addsy))
{
value -= S_GET_VALUE (fixP->fx_addsy);
}
#endif
 
/* Fix a few things - the dynamic linker expects certain values here,
and we must not disappoint it. */
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
if (IS_ELF && fixP->fx_addsy)
switch (fixP->fx_r_type)
{
case BFD_RELOC_386_PLT32:
case BFD_RELOC_X86_64_PLT32:
case BFD_RELOC_X86_64_PLT32_BND:
/* Make the jump instruction point to the address of the operand. At
runtime we merely add the offset to the actual PLT entry. */
value = -4;
break;
 
case BFD_RELOC_386_TLS_GD:
case BFD_RELOC_386_TLS_LDM:
case BFD_RELOC_386_TLS_IE_32:
case BFD_RELOC_386_TLS_IE:
case BFD_RELOC_386_TLS_GOTIE:
case BFD_RELOC_386_TLS_GOTDESC:
case BFD_RELOC_X86_64_TLSGD:
case BFD_RELOC_X86_64_TLSLD:
case BFD_RELOC_X86_64_GOTTPOFF:
case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
value = 0; /* Fully resolved at runtime. No addend. */
/* Fallthrough */
case BFD_RELOC_386_TLS_LE:
case BFD_RELOC_386_TLS_LDO_32:
case BFD_RELOC_386_TLS_LE_32:
case BFD_RELOC_X86_64_DTPOFF32:
case BFD_RELOC_X86_64_DTPOFF64:
case BFD_RELOC_X86_64_TPOFF32:
case BFD_RELOC_X86_64_TPOFF64:
S_SET_THREAD_LOCAL (fixP->fx_addsy);
break;
 
case BFD_RELOC_386_TLS_DESC_CALL:
case BFD_RELOC_X86_64_TLSDESC_CALL:
value = 0; /* Fully resolved at runtime. No addend. */
S_SET_THREAD_LOCAL (fixP->fx_addsy);
fixP->fx_done = 0;
return;
 
case BFD_RELOC_386_GOT32:
case BFD_RELOC_X86_64_GOT32:
value = 0; /* Fully resolved at runtime. No addend. */
break;
 
case BFD_RELOC_VTABLE_INHERIT:
case BFD_RELOC_VTABLE_ENTRY:
fixP->fx_done = 0;
return;
 
default:
break;
}
#endif /* defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) */
*valP = value;
#endif /* !defined (TE_Mach) */
 
/* Are we finished with this relocation now? */
if (fixP->fx_addsy == NULL)
fixP->fx_done = 1;
#if defined (OBJ_COFF) && defined (TE_PE)
else if (fixP->fx_addsy != NULL && S_IS_WEAK (fixP->fx_addsy))
{
fixP->fx_done = 0;
/* Remember value for tc_gen_reloc. */
fixP->fx_addnumber = value;
/* Clear out the frag for now. */
value = 0;
}
#endif
else if (use_rela_relocations)
{
fixP->fx_no_overflow = 1;
/* Remember value for tc_gen_reloc. */
fixP->fx_addnumber = value;
value = 0;
}
 
md_number_to_chars (p, value, fixP->fx_size);
}
char *
md_atof (int type, char *litP, int *sizeP)
{
/* This outputs the LITTLENUMs in REVERSE order;
in accord with the bigendian 386. */
return ieee_md_atof (type, litP, sizeP, FALSE);
}
static char output_invalid_buf[sizeof (unsigned char) * 2 + 6];
 
static char *
output_invalid (int c)
{
if (ISPRINT (c))
snprintf (output_invalid_buf, sizeof (output_invalid_buf),
"'%c'", c);
else
snprintf (output_invalid_buf, sizeof (output_invalid_buf),
"(0x%x)", (unsigned char) c);
return output_invalid_buf;
}
 
/* REG_STRING starts *before* REGISTER_PREFIX. */
 
static const reg_entry *
parse_real_register (char *reg_string, char **end_op)
{
char *s = reg_string;
char *p;
char reg_name_given[MAX_REG_NAME_SIZE + 1];
const reg_entry *r;
 
/* Skip possible REGISTER_PREFIX and possible whitespace. */
if (*s == REGISTER_PREFIX)
++s;
 
if (is_space_char (*s))
++s;
 
p = reg_name_given;
while ((*p++ = register_chars[(unsigned char) *s]) != '\0')
{
if (p >= reg_name_given + MAX_REG_NAME_SIZE)
return (const reg_entry *) NULL;
s++;
}
 
/* For naked regs, make sure that we are not dealing with an identifier.
This prevents confusing an identifier like `eax_var' with register
`eax'. */
if (allow_naked_reg && identifier_chars[(unsigned char) *s])
return (const reg_entry *) NULL;
 
*end_op = s;
 
r = (const reg_entry *) hash_find (reg_hash, reg_name_given);
 
/* Handle floating point regs, allowing spaces in the (i) part. */
if (r == i386_regtab /* %st is first entry of table */)
{
if (is_space_char (*s))
++s;
if (*s == '(')
{
++s;
if (is_space_char (*s))
++s;
if (*s >= '0' && *s <= '7')
{
int fpr = *s - '0';
++s;
if (is_space_char (*s))
++s;
if (*s == ')')
{
*end_op = s + 1;
r = (const reg_entry *) hash_find (reg_hash, "st(0)");
know (r);
return r + fpr;
}
}
/* We have "%st(" then garbage. */
return (const reg_entry *) NULL;
}
}
 
if (r == NULL || allow_pseudo_reg)
return r;
 
if (operand_type_all_zero (&r->reg_type))
return (const reg_entry *) NULL;
 
if ((r->reg_type.bitfield.reg32
|| r->reg_type.bitfield.sreg3
|| r->reg_type.bitfield.control
|| r->reg_type.bitfield.debug
|| r->reg_type.bitfield.test)
&& !cpu_arch_flags.bitfield.cpui386)
return (const reg_entry *) NULL;
 
if (r->reg_type.bitfield.floatreg
&& !cpu_arch_flags.bitfield.cpu8087
&& !cpu_arch_flags.bitfield.cpu287
&& !cpu_arch_flags.bitfield.cpu387)
return (const reg_entry *) NULL;
 
if (r->reg_type.bitfield.regmmx && !cpu_arch_flags.bitfield.cpummx)
return (const reg_entry *) NULL;
 
if (r->reg_type.bitfield.regxmm && !cpu_arch_flags.bitfield.cpusse)
return (const reg_entry *) NULL;
 
if (r->reg_type.bitfield.regymm && !cpu_arch_flags.bitfield.cpuavx)
return (const reg_entry *) NULL;
 
if ((r->reg_type.bitfield.regzmm || r->reg_type.bitfield.regmask)
&& !cpu_arch_flags.bitfield.cpuavx512f)
return (const reg_entry *) NULL;
 
/* Don't allow fake index register unless allow_index_reg isn't 0. */
if (!allow_index_reg
&& (r->reg_num == RegEiz || r->reg_num == RegRiz))
return (const reg_entry *) NULL;
 
/* Upper 16 vector register is only available with VREX in 64bit
mode. */
if ((r->reg_flags & RegVRex))
{
if (!cpu_arch_flags.bitfield.cpuvrex
|| flag_code != CODE_64BIT)
return (const reg_entry *) NULL;
 
i.need_vrex = 1;
}
 
if (((r->reg_flags & (RegRex64 | RegRex))
|| r->reg_type.bitfield.reg64)
&& (!cpu_arch_flags.bitfield.cpulm
|| !operand_type_equal (&r->reg_type, &control))
&& flag_code != CODE_64BIT)
return (const reg_entry *) NULL;
 
if (r->reg_type.bitfield.sreg3 && r->reg_num == RegFlat && !intel_syntax)
return (const reg_entry *) NULL;
 
return r;
}
 
/* REG_STRING starts *before* REGISTER_PREFIX. */
 
static const reg_entry *
parse_register (char *reg_string, char **end_op)
{
const reg_entry *r;
 
if (*reg_string == REGISTER_PREFIX || allow_naked_reg)
r = parse_real_register (reg_string, end_op);
else
r = NULL;
if (!r)
{
char *save = input_line_pointer;
char c;
symbolS *symbolP;
 
input_line_pointer = reg_string;
c = get_symbol_end ();
symbolP = symbol_find (reg_string);
if (symbolP && S_GET_SEGMENT (symbolP) == reg_section)
{
const expressionS *e = symbol_get_value_expression (symbolP);
 
know (e->X_op == O_register);
know (e->X_add_number >= 0
&& (valueT) e->X_add_number < i386_regtab_size);
r = i386_regtab + e->X_add_number;
*end_op = input_line_pointer;
}
*input_line_pointer = c;
input_line_pointer = save;
}
return r;
}
 
int
i386_parse_name (char *name, expressionS *e, char *nextcharP)
{
const reg_entry *r;
char *end = input_line_pointer;
 
*end = *nextcharP;
r = parse_register (name, &input_line_pointer);
if (r && end <= input_line_pointer)
{
*nextcharP = *input_line_pointer;
*input_line_pointer = 0;
e->X_op = O_register;
e->X_add_number = r - i386_regtab;
return 1;
}
input_line_pointer = end;
*end = 0;
return intel_syntax ? i386_intel_parse_name (name, e) : 0;
}
 
void
md_operand (expressionS *e)
{
char *end;
const reg_entry *r;
 
switch (*input_line_pointer)
{
case REGISTER_PREFIX:
r = parse_real_register (input_line_pointer, &end);
if (r)
{
e->X_op = O_register;
e->X_add_number = r - i386_regtab;
input_line_pointer = end;
}
break;
 
case '[':
gas_assert (intel_syntax);
end = input_line_pointer++;
expression (e);
if (*input_line_pointer == ']')
{
++input_line_pointer;
e->X_op_symbol = make_expr_symbol (e);
e->X_add_symbol = NULL;
e->X_add_number = 0;
e->X_op = O_index;
}
else
{
e->X_op = O_absent;
input_line_pointer = end;
}
break;
}
}
 
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
const char *md_shortopts = "kVQ:sqn";
#else
const char *md_shortopts = "qn";
#endif
 
#define OPTION_32 (OPTION_MD_BASE + 0)
#define OPTION_64 (OPTION_MD_BASE + 1)
#define OPTION_DIVIDE (OPTION_MD_BASE + 2)
#define OPTION_MARCH (OPTION_MD_BASE + 3)
#define OPTION_MTUNE (OPTION_MD_BASE + 4)
#define OPTION_MMNEMONIC (OPTION_MD_BASE + 5)
#define OPTION_MSYNTAX (OPTION_MD_BASE + 6)
#define OPTION_MINDEX_REG (OPTION_MD_BASE + 7)
#define OPTION_MNAKED_REG (OPTION_MD_BASE + 8)
#define OPTION_MOLD_GCC (OPTION_MD_BASE + 9)
#define OPTION_MSSE2AVX (OPTION_MD_BASE + 10)
#define OPTION_MSSE_CHECK (OPTION_MD_BASE + 11)
#define OPTION_MOPERAND_CHECK (OPTION_MD_BASE + 12)
#define OPTION_MAVXSCALAR (OPTION_MD_BASE + 13)
#define OPTION_X32 (OPTION_MD_BASE + 14)
#define OPTION_MADD_BND_PREFIX (OPTION_MD_BASE + 15)
#define OPTION_MEVEXLIG (OPTION_MD_BASE + 16)
#define OPTION_MEVEXWIG (OPTION_MD_BASE + 17)
 
struct option md_longopts[] =
{
{"32", no_argument, NULL, OPTION_32},
#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \
|| defined (TE_PE) || defined (TE_PEP) || defined (OBJ_MACH_O))
{"64", no_argument, NULL, OPTION_64},
#endif
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
{"x32", no_argument, NULL, OPTION_X32},
#endif
{"divide", no_argument, NULL, OPTION_DIVIDE},
{"march", required_argument, NULL, OPTION_MARCH},
{"mtune", required_argument, NULL, OPTION_MTUNE},
{"mmnemonic", required_argument, NULL, OPTION_MMNEMONIC},
{"msyntax", required_argument, NULL, OPTION_MSYNTAX},
{"mindex-reg", no_argument, NULL, OPTION_MINDEX_REG},
{"mnaked-reg", no_argument, NULL, OPTION_MNAKED_REG},
{"mold-gcc", no_argument, NULL, OPTION_MOLD_GCC},
{"msse2avx", no_argument, NULL, OPTION_MSSE2AVX},
{"msse-check", required_argument, NULL, OPTION_MSSE_CHECK},
{"moperand-check", required_argument, NULL, OPTION_MOPERAND_CHECK},
{"mavxscalar", required_argument, NULL, OPTION_MAVXSCALAR},
{"madd-bnd-prefix", no_argument, NULL, OPTION_MADD_BND_PREFIX},
{"mevexlig", required_argument, NULL, OPTION_MEVEXLIG},
{"mevexwig", required_argument, NULL, OPTION_MEVEXWIG},
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
 
int
md_parse_option (int c, char *arg)
{
unsigned int j;
char *arch, *next;
 
switch (c)
{
case 'n':
optimize_align_code = 0;
break;
 
case 'q':
quiet_warnings = 1;
break;
 
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
/* -Qy, -Qn: SVR4 arguments controlling whether a .comment section
should be emitted or not. FIXME: Not implemented. */
case 'Q':
break;
 
/* -V: SVR4 argument to print version ID. */
case 'V':
print_version_id ();
break;
 
/* -k: Ignore for FreeBSD compatibility. */
case 'k':
break;
 
case 's':
/* -s: On i386 Solaris, this tells the native assembler to use
.stab instead of .stab.excl. We always use .stab anyhow. */
break;
#endif
#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \
|| defined (TE_PE) || defined (TE_PEP) || defined (OBJ_MACH_O))
case OPTION_64:
{
const char **list, **l;
 
list = bfd_target_list ();
for (l = list; *l != NULL; l++)
if (CONST_STRNEQ (*l, "elf64-x86-64")
|| strcmp (*l, "coff-x86-64") == 0
|| strcmp (*l, "pe-x86-64") == 0
|| strcmp (*l, "pei-x86-64") == 0
|| strcmp (*l, "mach-o-x86-64") == 0)
{
default_arch = "x86_64";
break;
}
if (*l == NULL)
as_fatal (_("no compiled in support for x86_64"));
free (list);
}
break;
#endif
 
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
case OPTION_X32:
if (IS_ELF)
{
const char **list, **l;
 
list = bfd_target_list ();
for (l = list; *l != NULL; l++)
if (CONST_STRNEQ (*l, "elf32-x86-64"))
{
default_arch = "x86_64:32";
break;
}
if (*l == NULL)
as_fatal (_("no compiled in support for 32bit x86_64"));
free (list);
}
else
as_fatal (_("32bit x86_64 is only supported for ELF"));
break;
#endif
 
case OPTION_32:
default_arch = "i386";
break;
 
case OPTION_DIVIDE:
#ifdef SVR4_COMMENT_CHARS
{
char *n, *t;
const char *s;
 
n = (char *) xmalloc (strlen (i386_comment_chars) + 1);
t = n;
for (s = i386_comment_chars; *s != '\0'; s++)
if (*s != '/')
*t++ = *s;
*t = '\0';
i386_comment_chars = n;
}
#endif
break;
 
case OPTION_MARCH:
arch = xstrdup (arg);
do
{
if (*arch == '.')
as_fatal (_("invalid -march= option: `%s'"), arg);
next = strchr (arch, '+');
if (next)
*next++ = '\0';
for (j = 0; j < ARRAY_SIZE (cpu_arch); j++)
{
if (strcmp (arch, cpu_arch [j].name) == 0)
{
/* Processor. */
if (! cpu_arch[j].flags.bitfield.cpui386)
continue;
 
cpu_arch_name = cpu_arch[j].name;
cpu_sub_arch_name = NULL;
cpu_arch_flags = cpu_arch[j].flags;
cpu_arch_isa = cpu_arch[j].type;
cpu_arch_isa_flags = cpu_arch[j].flags;
if (!cpu_arch_tune_set)
{
cpu_arch_tune = cpu_arch_isa;
cpu_arch_tune_flags = cpu_arch_isa_flags;
}
break;
}
else if (*cpu_arch [j].name == '.'
&& strcmp (arch, cpu_arch [j].name + 1) == 0)
{
/* ISA entension. */
i386_cpu_flags flags;
 
if (!cpu_arch[j].negated)
flags = cpu_flags_or (cpu_arch_flags,
cpu_arch[j].flags);
else
flags = cpu_flags_and_not (cpu_arch_flags,
cpu_arch[j].flags);
if (!cpu_flags_equal (&flags, &cpu_arch_flags))
{
if (cpu_sub_arch_name)
{
char *name = cpu_sub_arch_name;
cpu_sub_arch_name = concat (name,
cpu_arch[j].name,
(const char *) NULL);
free (name);
}
else
cpu_sub_arch_name = xstrdup (cpu_arch[j].name);
cpu_arch_flags = flags;
cpu_arch_isa_flags = flags;
}
break;
}
}
 
if (j >= ARRAY_SIZE (cpu_arch))
as_fatal (_("invalid -march= option: `%s'"), arg);
 
arch = next;
}
while (next != NULL );
break;
 
case OPTION_MTUNE:
if (*arg == '.')
as_fatal (_("invalid -mtune= option: `%s'"), arg);
for (j = 0; j < ARRAY_SIZE (cpu_arch); j++)
{
if (strcmp (arg, cpu_arch [j].name) == 0)
{
cpu_arch_tune_set = 1;
cpu_arch_tune = cpu_arch [j].type;
cpu_arch_tune_flags = cpu_arch[j].flags;
break;
}
}
if (j >= ARRAY_SIZE (cpu_arch))
as_fatal (_("invalid -mtune= option: `%s'"), arg);
break;
 
case OPTION_MMNEMONIC:
if (strcasecmp (arg, "att") == 0)
intel_mnemonic = 0;
else if (strcasecmp (arg, "intel") == 0)
intel_mnemonic = 1;
else
as_fatal (_("invalid -mmnemonic= option: `%s'"), arg);
break;
 
case OPTION_MSYNTAX:
if (strcasecmp (arg, "att") == 0)
intel_syntax = 0;
else if (strcasecmp (arg, "intel") == 0)
intel_syntax = 1;
else
as_fatal (_("invalid -msyntax= option: `%s'"), arg);
break;
 
case OPTION_MINDEX_REG:
allow_index_reg = 1;
break;
 
case OPTION_MNAKED_REG:
allow_naked_reg = 1;
break;
 
case OPTION_MOLD_GCC:
old_gcc = 1;
break;
 
case OPTION_MSSE2AVX:
sse2avx = 1;
break;
 
case OPTION_MSSE_CHECK:
if (strcasecmp (arg, "error") == 0)
sse_check = check_error;
else if (strcasecmp (arg, "warning") == 0)
sse_check = check_warning;
else if (strcasecmp (arg, "none") == 0)
sse_check = check_none;
else
as_fatal (_("invalid -msse-check= option: `%s'"), arg);
break;
 
case OPTION_MOPERAND_CHECK:
if (strcasecmp (arg, "error") == 0)
operand_check = check_error;
else if (strcasecmp (arg, "warning") == 0)
operand_check = check_warning;
else if (strcasecmp (arg, "none") == 0)
operand_check = check_none;
else
as_fatal (_("invalid -moperand-check= option: `%s'"), arg);
break;
 
case OPTION_MAVXSCALAR:
if (strcasecmp (arg, "128") == 0)
avxscalar = vex128;
else if (strcasecmp (arg, "256") == 0)
avxscalar = vex256;
else
as_fatal (_("invalid -mavxscalar= option: `%s'"), arg);
break;
 
case OPTION_MADD_BND_PREFIX:
add_bnd_prefix = 1;
break;
 
case OPTION_MEVEXLIG:
if (strcmp (arg, "128") == 0)
evexlig = evexl128;
else if (strcmp (arg, "256") == 0)
evexlig = evexl256;
else if (strcmp (arg, "512") == 0)
evexlig = evexl512;
else
as_fatal (_("invalid -mevexlig= option: `%s'"), arg);
break;
 
case OPTION_MEVEXWIG:
if (strcmp (arg, "0") == 0)
evexwig = evexw0;
else if (strcmp (arg, "1") == 0)
evexwig = evexw1;
else
as_fatal (_("invalid -mevexwig= option: `%s'"), arg);
break;
 
default:
return 0;
}
return 1;
}
 
#define MESSAGE_TEMPLATE \
" "
 
static void
show_arch (FILE *stream, int ext, int check)
{
static char message[] = MESSAGE_TEMPLATE;
char *start = message + 27;
char *p;
int size = sizeof (MESSAGE_TEMPLATE);
int left;
const char *name;
int len;
unsigned int j;
 
p = start;
left = size - (start - message);
for (j = 0; j < ARRAY_SIZE (cpu_arch); j++)
{
/* Should it be skipped? */
if (cpu_arch [j].skip)
continue;
 
name = cpu_arch [j].name;
len = cpu_arch [j].len;
if (*name == '.')
{
/* It is an extension. Skip if we aren't asked to show it. */
if (ext)
{
name++;
len--;
}
else
continue;
}
else if (ext)
{
/* It is an processor. Skip if we show only extension. */
continue;
}
else if (check && ! cpu_arch[j].flags.bitfield.cpui386)
{
/* It is an impossible processor - skip. */
continue;
}
 
/* Reserve 2 spaces for ", " or ",\0" */
left -= len + 2;
 
/* Check if there is any room. */
if (left >= 0)
{
if (p != start)
{
*p++ = ',';
*p++ = ' ';
}
p = mempcpy (p, name, len);
}
else
{
/* Output the current message now and start a new one. */
*p++ = ',';
*p = '\0';
fprintf (stream, "%s\n", message);
p = start;
left = size - (start - message) - len - 2;
 
gas_assert (left >= 0);
 
p = mempcpy (p, name, len);
}
}
 
*p = '\0';
fprintf (stream, "%s\n", message);
}
 
void
md_show_usage (FILE *stream)
{
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
fprintf (stream, _("\
-Q ignored\n\
-V print assembler version number\n\
-k ignored\n"));
#endif
fprintf (stream, _("\
-n Do not optimize code alignment\n\
-q quieten some warnings\n"));
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
fprintf (stream, _("\
-s ignored\n"));
#endif
#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \
|| defined (TE_PE) || defined (TE_PEP))
fprintf (stream, _("\
--32/--64/--x32 generate 32bit/64bit/x32 code\n"));
#endif
#ifdef SVR4_COMMENT_CHARS
fprintf (stream, _("\
--divide do not treat `/' as a comment character\n"));
#else
fprintf (stream, _("\
--divide ignored\n"));
#endif
fprintf (stream, _("\
-march=CPU[,+EXTENSION...]\n\
generate code for CPU and EXTENSION, CPU is one of:\n"));
show_arch (stream, 0, 1);
fprintf (stream, _("\
EXTENSION is combination of:\n"));
show_arch (stream, 1, 0);
fprintf (stream, _("\
-mtune=CPU optimize for CPU, CPU is one of:\n"));
show_arch (stream, 0, 0);
fprintf (stream, _("\
-msse2avx encode SSE instructions with VEX prefix\n"));
fprintf (stream, _("\
-msse-check=[none|error|warning]\n\
check SSE instructions\n"));
fprintf (stream, _("\
-moperand-check=[none|error|warning]\n\
check operand combinations for validity\n"));
fprintf (stream, _("\
-mavxscalar=[128|256] encode scalar AVX instructions with specific vector\n\
length\n"));
fprintf (stream, _("\
-mevexlig=[128|256|512] encode scalar EVEX instructions with specific vector\n\
length\n"));
fprintf (stream, _("\
-mevexwig=[0|1] encode EVEX instructions with specific EVEX.W value\n\
for EVEX.W bit ignored instructions\n"));
fprintf (stream, _("\
-mmnemonic=[att|intel] use AT&T/Intel mnemonic\n"));
fprintf (stream, _("\
-msyntax=[att|intel] use AT&T/Intel syntax\n"));
fprintf (stream, _("\
-mindex-reg support pseudo index registers\n"));
fprintf (stream, _("\
-mnaked-reg don't require `%%' prefix for registers\n"));
fprintf (stream, _("\
-mold-gcc support old (<= 2.8.1) versions of gcc\n"));
fprintf (stream, _("\
-madd-bnd-prefix add BND prefix for all valid branches\n"));
}
 
#if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \
|| defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \
|| defined (TE_PE) || defined (TE_PEP) || defined (OBJ_MACH_O))
 
/* Pick the target format to use. */
 
const char *
i386_target_format (void)
{
if (!strncmp (default_arch, "x86_64", 6))
{
update_code_flag (CODE_64BIT, 1);
if (default_arch[6] == '\0')
x86_elf_abi = X86_64_ABI;
else
x86_elf_abi = X86_64_X32_ABI;
}
else if (!strcmp (default_arch, "i386"))
update_code_flag (CODE_32BIT, 1);
else
as_fatal (_("unknown architecture"));
 
if (cpu_flags_all_zero (&cpu_arch_isa_flags))
cpu_arch_isa_flags = cpu_arch[flag_code == CODE_64BIT].flags;
if (cpu_flags_all_zero (&cpu_arch_tune_flags))
cpu_arch_tune_flags = cpu_arch[flag_code == CODE_64BIT].flags;
 
switch (OUTPUT_FLAVOR)
{
#if defined (OBJ_MAYBE_AOUT) || defined (OBJ_AOUT)
case bfd_target_aout_flavour:
return AOUT_TARGET_FORMAT;
#endif
#if defined (OBJ_MAYBE_COFF) || defined (OBJ_COFF)
# if defined (TE_PE) || defined (TE_PEP)
case bfd_target_coff_flavour:
return flag_code == CODE_64BIT ? "pe-x86-64" : "pe-i386";
# elif defined (TE_GO32)
case bfd_target_coff_flavour:
return "coff-go32";
# else
case bfd_target_coff_flavour:
return "coff-i386";
# endif
#endif
#if defined (OBJ_MAYBE_ELF) || defined (OBJ_ELF)
case bfd_target_elf_flavour:
{
const char *format;
 
switch (x86_elf_abi)
{
default:
format = ELF_TARGET_FORMAT;
break;
case X86_64_ABI:
use_rela_relocations = 1;
object_64bit = 1;
format = ELF_TARGET_FORMAT64;
break;
case X86_64_X32_ABI:
use_rela_relocations = 1;
object_64bit = 1;
disallow_64bit_reloc = 1;
format = ELF_TARGET_FORMAT32;
break;
}
if (cpu_arch_isa == PROCESSOR_L1OM)
{
if (x86_elf_abi != X86_64_ABI)
as_fatal (_("Intel L1OM is 64bit only"));
return ELF_TARGET_L1OM_FORMAT;
}
if (cpu_arch_isa == PROCESSOR_K1OM)
{
if (x86_elf_abi != X86_64_ABI)
as_fatal (_("Intel K1OM is 64bit only"));
return ELF_TARGET_K1OM_FORMAT;
}
else
return format;
}
#endif
#if defined (OBJ_MACH_O)
case bfd_target_mach_o_flavour:
if (flag_code == CODE_64BIT)
{
use_rela_relocations = 1;
object_64bit = 1;
return "mach-o-x86-64";
}
else
return "mach-o-i386";
#endif
default:
abort ();
return NULL;
}
}
 
#endif /* OBJ_MAYBE_ more than one */
 
#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF))
void
i386_elf_emit_arch_note (void)
{
if (IS_ELF && cpu_arch_name != NULL)
{
char *p;
asection *seg = now_seg;
subsegT subseg = now_subseg;
Elf_Internal_Note i_note;
Elf_External_Note e_note;
asection *note_secp;
int len;
 
/* Create the .note section. */
note_secp = subseg_new (".note", 0);
bfd_set_section_flags (stdoutput,
note_secp,
SEC_HAS_CONTENTS | SEC_READONLY);
 
/* Process the arch string. */
len = strlen (cpu_arch_name);
 
i_note.namesz = len + 1;
i_note.descsz = 0;
i_note.type = NT_ARCH;
p = frag_more (sizeof (e_note.namesz));
md_number_to_chars (p, (valueT) i_note.namesz, sizeof (e_note.namesz));
p = frag_more (sizeof (e_note.descsz));
md_number_to_chars (p, (valueT) i_note.descsz, sizeof (e_note.descsz));
p = frag_more (sizeof (e_note.type));
md_number_to_chars (p, (valueT) i_note.type, sizeof (e_note.type));
p = frag_more (len + 1);
strcpy (p, cpu_arch_name);
 
frag_align (2, 0, 0);
 
subseg_set (seg, subseg);
}
}
#endif
symbolS *
md_undefined_symbol (char *name)
{
if (name[0] == GLOBAL_OFFSET_TABLE_NAME[0]
&& name[1] == GLOBAL_OFFSET_TABLE_NAME[1]
&& name[2] == GLOBAL_OFFSET_TABLE_NAME[2]
&& strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0)
{
if (!GOT_symbol)
{
if (symbol_find (name))
as_bad (_("GOT already in symbol table"));
GOT_symbol = symbol_new (name, undefined_section,
(valueT) 0, &zero_address_frag);
};
return GOT_symbol;
}
return 0;
}
 
/* Round up a section size to the appropriate boundary. */
 
valueT
md_section_align (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 (fixS *fixP)
{
return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address;
}
 
#ifndef I386COFF
 
static void
s_bss (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 (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 (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
{
arelent *rel;
bfd_reloc_code_real_type code;
 
switch (fixp->fx_r_type)
{
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
case BFD_RELOC_SIZE32:
case BFD_RELOC_SIZE64:
if (S_IS_DEFINED (fixp->fx_addsy)
&& !S_IS_EXTERNAL (fixp->fx_addsy))
{
/* Resolve size relocation against local symbol to size of
the symbol plus addend. */
valueT value = S_GET_SIZE (fixp->fx_addsy) + fixp->fx_offset;
if (fixp->fx_r_type == BFD_RELOC_SIZE32
&& !fits_in_unsigned_long (value))
as_bad_where (fixp->fx_file, fixp->fx_line,
_("symbol size computation overflow"));
fixp->fx_addsy = NULL;
fixp->fx_subsy = NULL;
md_apply_fix (fixp, (valueT *) &value, NULL);
return NULL;
}
#endif
 
case BFD_RELOC_X86_64_PLT32:
case BFD_RELOC_X86_64_PLT32_BND:
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_386_TLS_GOTDESC:
case BFD_RELOC_386_TLS_DESC_CALL:
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_X86_64_GOT64:
case BFD_RELOC_X86_64_GOTPCREL64:
case BFD_RELOC_X86_64_GOTPC64:
case BFD_RELOC_X86_64_GOTPLT64:
case BFD_RELOC_X86_64_PLTOFF64:
case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
case BFD_RELOC_X86_64_TLSDESC_CALL:
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 = (fixp->fx_r_type == BFD_RELOC_X86_64_PC32_BND
? fixp-> fx_r_type : 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
|| code == BFD_RELOC_X86_64_32S)
&& GOT_symbol
&& fixp->fx_addsy == GOT_symbol)
{
if (!object_64bit)
code = BFD_RELOC_386_GOTPC;
else
code = BFD_RELOC_X86_64_GOTPC32;
}
if ((code == BFD_RELOC_64 || code == BFD_RELOC_64_PCREL)
&& GOT_symbol
&& fixp->fx_addsy == GOT_symbol)
{
code = BFD_RELOC_X86_64_GOTPC64;
}
 
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;
#if defined (OBJ_COFF) && defined (TE_PE)
else if (fixp->fx_addsy && S_IS_WEAK (fixp->fx_addsy))
rel->addend = fixp->fx_addnumber - (S_GET_VALUE (fixp->fx_addsy) * 2);
else
#endif
rel->addend = 0;
}
/* Use the rela in 64bit mode. */
else
{
if (disallow_64bit_reloc)
switch (code)
{
case BFD_RELOC_X86_64_DTPOFF64:
case BFD_RELOC_X86_64_TPOFF64:
case BFD_RELOC_64_PCREL:
case BFD_RELOC_X86_64_GOTOFF64:
case BFD_RELOC_X86_64_GOT64:
case BFD_RELOC_X86_64_GOTPCREL64:
case BFD_RELOC_X86_64_GOTPC64:
case BFD_RELOC_X86_64_GOTPLT64:
case BFD_RELOC_X86_64_PLTOFF64:
as_bad_where (fixp->fx_file, fixp->fx_line,
_("cannot represent relocation type %s in x32 mode"),
bfd_get_reloc_code_name (code));
break;
default:
break;
}
 
if (!fixp->fx_pcrel)
rel->addend = fixp->fx_offset;
else
switch (code)
{
case BFD_RELOC_X86_64_PLT32:
case BFD_RELOC_X86_64_PLT32_BND:
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:
case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
case BFD_RELOC_X86_64_TLSDESC_CALL:
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);
gas_assert (rel->howto != NULL);
}
 
return rel;
}
 
#include "tc-i386-intel.c"
 
void
tc_x86_parse_to_dw2regnum (expressionS *exp)
{
int saved_naked_reg;
char saved_register_dot;
 
saved_naked_reg = allow_naked_reg;
allow_naked_reg = 1;
saved_register_dot = register_chars['.'];
register_chars['.'] = '.';
allow_pseudo_reg = 1;
expression_and_evaluate (exp);
allow_pseudo_reg = 0;
register_chars['.'] = saved_register_dot;
allow_naked_reg = saved_naked_reg;
 
if (exp->X_op == O_register && exp->X_add_number >= 0)
{
if ((addressT) exp->X_add_number < i386_regtab_size)
{
exp->X_op = O_constant;
exp->X_add_number = i386_regtab[exp->X_add_number]
.dw2_regnum[flag_code >> 1];
}
else
exp->X_op = O_illegal;
}
}
 
void
tc_x86_frame_initial_instructions (void)
{
static unsigned int sp_regno[2];
 
if (!sp_regno[flag_code >> 1])
{
char *saved_input = input_line_pointer;
char sp[][4] = {"esp", "rsp"};
expressionS exp;
 
input_line_pointer = sp[flag_code >> 1];
tc_x86_parse_to_dw2regnum (&exp);
gas_assert (exp.X_op == O_constant);
sp_regno[flag_code >> 1] = exp.X_add_number;
input_line_pointer = saved_input;
}
 
cfi_add_CFA_def_cfa (sp_regno[flag_code >> 1], -x86_cie_data_alignment);
cfi_add_CFA_offset (x86_dwarf2_return_column, x86_cie_data_alignment);
}
 
int
x86_dwarf2_addr_size (void)
{
#if defined (OBJ_MAYBE_ELF) || defined (OBJ_ELF)
if (x86_elf_abi == X86_64_X32_ABI)
return 4;
#endif
return bfd_arch_bits_per_address (stdoutput) / 8;
}
 
int
i386_elf_section_type (const char *str, size_t len)
{
if (flag_code == CODE_64BIT
&& len == sizeof ("unwind") - 1
&& strncmp (str, "unwind", 6) == 0)
return SHT_X86_64_UNWIND;
 
return -1;
}
 
#ifdef TE_SOLARIS
void
i386_solaris_fix_up_eh_frame (segT sec)
{
if (flag_code == CODE_64BIT)
elf_section_type (sec) = SHT_X86_64_UNWIND;
}
#endif
 
#ifdef TE_PE
void
tc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
{
expressionS exp;
 
exp.X_op = O_secrel;
exp.X_add_symbol = symbol;
exp.X_add_number = 0;
emit_expr (&exp, size);
}
#endif
 
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
/* For ELF on x86-64, add support for SHF_X86_64_LARGE. */
 
bfd_vma
x86_64_section_letter (int letter, char **ptr_msg)
{
if (flag_code == CODE_64BIT)
{
if (letter == 'l')
return SHF_X86_64_LARGE;
 
*ptr_msg = _("bad .section directive: want a,l,w,x,M,S,G,T in string");
}
else
*ptr_msg = _("bad .section directive: want a,w,x,M,S,G,T in string");
return -1;
}
 
bfd_vma
x86_64_section_word (char *str, size_t len)
{
if (len == 5 && flag_code == CODE_64BIT && CONST_STRNEQ (str, "large"))
return SHF_X86_64_LARGE;
 
return -1;
}
 
static void
handle_large_common (int small ATTRIBUTE_UNUSED)
{
if (flag_code != CODE_64BIT)
{
s_comm_internal (0, elf_common_parse);
as_warn (_(".largecomm supported only in 64bit mode, producing .comm"));
}
else
{
static segT lbss_section;
asection *saved_com_section_ptr = elf_com_section_ptr;
asection *saved_bss_section = bss_section;
 
if (lbss_section == NULL)
{
flagword applicable;
segT seg = now_seg;
subsegT subseg = now_subseg;
 
/* The .lbss section is for local .largecomm symbols. */
lbss_section = subseg_new (".lbss", 0);
applicable = bfd_applicable_section_flags (stdoutput);
bfd_set_section_flags (stdoutput, lbss_section,
applicable & SEC_ALLOC);
seg_info (lbss_section)->bss = 1;
 
subseg_set (seg, subseg);
}
 
elf_com_section_ptr = &_bfd_elf_large_com_section;
bss_section = lbss_section;
 
s_comm_internal (0, elf_common_parse);
 
elf_com_section_ptr = saved_com_section_ptr;
bss_section = saved_bss_section;
}
}
#endif /* OBJ_ELF || OBJ_MAYBE_ELF */
/contrib/toolchain/binutils/gas/config/tc-i386.h
0,0 → 1,342
/* tc-i386.h -- Header file for tc-i386.c
Copyright 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
 
This file is part of GAS, the GNU Assembler.
 
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
 
GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
#ifndef TC_I386
#define TC_I386 1
 
#include "opcodes/i386-opc.h"
 
struct fix;
 
#define TARGET_BYTES_BIG_ENDIAN 0
 
#define TARGET_ARCH (i386_arch ())
#define TARGET_MACH (i386_mach ())
extern enum bfd_architecture i386_arch (void);
extern unsigned long i386_mach (void);
 
#ifdef TE_FreeBSD
#define AOUT_TARGET_FORMAT "a.out-i386-freebsd"
#endif
#ifdef TE_NetBSD
#define AOUT_TARGET_FORMAT "a.out-i386-netbsd"
#endif
#ifdef TE_386BSD
#define AOUT_TARGET_FORMAT "a.out-i386-bsd"
#endif
#ifdef TE_LINUX
#define AOUT_TARGET_FORMAT "a.out-i386-linux"
#endif
#ifdef TE_Mach
#define AOUT_TARGET_FORMAT "a.out-mach3"
#endif
#ifdef TE_DYNIX
#define AOUT_TARGET_FORMAT "a.out-i386-dynix"
#endif
#ifndef AOUT_TARGET_FORMAT
#define AOUT_TARGET_FORMAT "a.out-i386"
#endif
 
#ifdef TE_FreeBSD
#define ELF_TARGET_FORMAT "elf32-i386-freebsd"
#define ELF_TARGET_FORMAT64 "elf64-x86-64-freebsd"
#elif defined (TE_VXWORKS)
#define ELF_TARGET_FORMAT "elf32-i386-vxworks"
#elif defined (TE_NACL)
#define ELF_TARGET_FORMAT "elf32-i386-nacl"
#define ELF_TARGET_FORMAT32 "elf32-x86-64-nacl"
#define ELF_TARGET_FORMAT64 "elf64-x86-64-nacl"
#endif
 
#ifdef TE_SOLARIS
#define ELF_TARGET_FORMAT "elf32-i386-sol2"
#define ELF_TARGET_FORMAT64 "elf64-x86-64-sol2"
#endif
 
#ifndef ELF_TARGET_FORMAT
#define ELF_TARGET_FORMAT "elf32-i386"
#endif
 
#ifndef ELF_TARGET_FORMAT64
#define ELF_TARGET_FORMAT64 "elf64-x86-64"
#endif
 
#ifndef ELF_TARGET_FORMAT32
#define ELF_TARGET_FORMAT32 "elf32-x86-64"
#endif
 
#ifndef ELF_TARGET_L1OM_FORMAT
#define ELF_TARGET_L1OM_FORMAT "elf64-l1om"
#endif
 
#ifndef ELF_TARGET_K1OM_FORMAT
#define ELF_TARGET_K1OM_FORMAT "elf64-k1om"
#endif
 
#if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \
|| defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \
|| defined (TE_PE) || defined (TE_PEP) || defined (OBJ_MACH_O))
extern const char *i386_target_format (void);
#define TARGET_FORMAT i386_target_format ()
#else
#ifdef TE_GO32
#define TARGET_FORMAT "coff-go32"
#endif
#ifdef OBJ_AOUT
#define TARGET_FORMAT AOUT_TARGET_FORMAT
#endif
#endif
 
#if (defined (OBJ_MAYBE_ELF) || defined (OBJ_ELF))
#define md_end i386_elf_emit_arch_note
extern void i386_elf_emit_arch_note (void);
#endif
 
#define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) 0
 
/* '$' may be used as immediate prefix. */
#undef LOCAL_LABELS_DOLLAR
#define LOCAL_LABELS_DOLLAR 0
#undef LOCAL_LABELS_FB
#define LOCAL_LABELS_FB 1
 
extern const char extra_symbol_chars[];
#define tc_symbol_chars extra_symbol_chars
 
extern const char *i386_comment_chars;
#define tc_comment_chars i386_comment_chars
 
/* The name of the global offset table generated by the compiler. Allow
this to be overridden if need be. */
#ifndef GLOBAL_OFFSET_TABLE_NAME
#define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_"
#endif
 
#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && !defined (LEX_AT)
#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) x86_cons (EXP, NBYTES)
#endif
extern void x86_cons (expressionS *, int);
 
#define TC_CONS_FIX_NEW(FRAG,OFF,LEN,EXP) x86_cons_fix_new(FRAG, OFF, LEN, EXP)
extern void x86_cons_fix_new
(fragS *, unsigned int, unsigned int, expressionS *);
 
#define TC_ADDRESS_BYTES x86_address_bytes
extern int x86_address_bytes (void);
 
#define DIFF_EXPR_OK /* foo-. gets turned into PC relative relocs */
 
#define NO_RELOC BFD_RELOC_NONE
 
void i386_validate_fix (struct fix *);
#define TC_VALIDATE_FIX(FIX,SEGTYPE,SKIP) i386_validate_fix(FIX)
 
#define tc_fix_adjustable(X) tc_i386_fix_adjustable(X)
extern int tc_i386_fix_adjustable (struct fix *);
 
/* Values passed to md_apply_fix don't include the symbol value. */
#define MD_APPLY_SYM_VALUE(FIX) 0
 
/* ELF wants external syms kept, as does PE COFF. */
#if defined (TE_PE) && defined (STRICT_PE_FORMAT)
#define EXTERN_FORCE_RELOC \
(OUTPUT_FLAVOR == bfd_target_elf_flavour \
|| OUTPUT_FLAVOR == bfd_target_coff_flavour)
#else
#define EXTERN_FORCE_RELOC \
(OUTPUT_FLAVOR == bfd_target_elf_flavour)
#endif
 
/* This expression evaluates to true if the relocation is for a local
object for which we still want to do the relocation at runtime.
False if we are willing to perform this relocation while building
the .o file. GOTOFF and GOT32 do not need to be checked here because
they are not pcrel. .*/
 
#define TC_FORCE_RELOCATION_LOCAL(FIX) \
(!(FIX)->fx_pcrel \
|| (FIX)->fx_r_type == BFD_RELOC_386_PLT32 \
|| (FIX)->fx_r_type == BFD_RELOC_386_GOTPC \
|| (FIX)->fx_r_type == BFD_RELOC_X86_64_GOTPCREL \
|| TC_FORCE_RELOCATION (FIX))
 
extern int i386_parse_name (char *, expressionS *, char *);
#define md_parse_name(s, e, m, c) i386_parse_name (s, e, c)
 
extern operatorT i386_operator (const char *name, unsigned int operands, char *);
#define md_operator i386_operator
 
extern int i386_need_index_operator (void);
#define md_need_index_operator i386_need_index_operator
 
#define md_register_arithmetic 0
 
extern const struct relax_type md_relax_table[];
#define TC_GENERIC_RELAX_TABLE md_relax_table
 
extern int optimize_align_code;
 
#define md_do_align(n, fill, len, max, around) \
if ((n) \
&& !need_pass_2 \
&& optimize_align_code \
&& (!(fill) \
|| ((char)*(fill) == (char)0x90 && (len) == 1)) \
&& subseg_text_p (now_seg)) \
{ \
frag_align_code ((n), (max)); \
goto around; \
}
 
#define MAX_MEM_FOR_RS_ALIGN_CODE 31
 
extern void i386_align_code (fragS *, int);
 
#define HANDLE_ALIGN(fragP) \
if (fragP->fr_type == rs_align_code) \
i386_align_code (fragP, (fragP->fr_next->fr_address \
- fragP->fr_address \
- fragP->fr_fix));
 
void i386_print_statistics (FILE *);
#define tc_print_statistics i386_print_statistics
 
extern unsigned int i386_frag_max_var (fragS *);
#define md_frag_max_var i386_frag_max_var
 
#define md_number_to_chars number_to_chars_littleendian
 
enum processor_type
{
PROCESSOR_UNKNOWN,
PROCESSOR_I386,
PROCESSOR_I486,
PROCESSOR_PENTIUM,
PROCESSOR_PENTIUMPRO,
PROCESSOR_PENTIUM4,
PROCESSOR_NOCONA,
PROCESSOR_CORE,
PROCESSOR_CORE2,
PROCESSOR_COREI7,
PROCESSOR_L1OM,
PROCESSOR_K1OM,
PROCESSOR_K6,
PROCESSOR_ATHLON,
PROCESSOR_K8,
PROCESSOR_GENERIC32,
PROCESSOR_GENERIC64,
PROCESSOR_AMDFAM10,
PROCESSOR_BD,
PROCESSOR_BT
};
 
extern enum processor_type cpu_arch_tune;
extern enum processor_type cpu_arch_isa;
extern i386_cpu_flags cpu_arch_isa_flags;
 
struct i386_tc_frag_data
{
enum processor_type isa;
i386_cpu_flags isa_flags;
enum processor_type tune;
};
 
/* We need to emit the right NOP pattern in .align frags. This is
done after the text-to-bits assembly pass, so we need to mark it with
the isa/tune settings at the time the .align was assembled. */
#define TC_FRAG_TYPE struct i386_tc_frag_data
 
#define TC_FRAG_INIT(FRAGP) \
do \
{ \
(FRAGP)->tc_frag_data.isa = cpu_arch_isa; \
(FRAGP)->tc_frag_data.isa_flags = cpu_arch_isa_flags; \
(FRAGP)->tc_frag_data.tune = cpu_arch_tune; \
} \
while (0)
 
#ifdef SCO_ELF
#define tc_init_after_args() sco_id ()
extern void sco_id (void);
#endif
 
#define WORKING_DOT_WORD 1
 
/* We want .cfi_* pseudo-ops for generating unwind info. */
#define TARGET_USE_CFIPOP 1
 
extern unsigned int x86_dwarf2_return_column;
#define DWARF2_DEFAULT_RETURN_COLUMN x86_dwarf2_return_column
 
extern int x86_cie_data_alignment;
#define DWARF2_CIE_DATA_ALIGNMENT x86_cie_data_alignment
 
extern int x86_dwarf2_addr_size (void);
#define DWARF2_ADDR_SIZE(bfd) x86_dwarf2_addr_size ()
 
#define tc_parse_to_dw2regnum tc_x86_parse_to_dw2regnum
extern void tc_x86_parse_to_dw2regnum (expressionS *);
 
#define tc_cfi_frame_initial_instructions tc_x86_frame_initial_instructions
extern void tc_x86_frame_initial_instructions (void);
 
#define md_elf_section_type(str,len) i386_elf_section_type (str, len)
extern int i386_elf_section_type (const char *, size_t);
 
#ifdef TE_SOLARIS
#define md_fix_up_eh_frame(sec) i386_solaris_fix_up_eh_frame (sec)
extern void i386_solaris_fix_up_eh_frame (segT);
#endif
 
/* Support for SHF_X86_64_LARGE */
extern bfd_vma x86_64_section_word (char *, size_t);
extern bfd_vma x86_64_section_letter (int, char **);
#define md_elf_section_letter(LETTER, PTR_MSG) x86_64_section_letter (LETTER, PTR_MSG)
#define md_elf_section_word(STR, LEN) x86_64_section_word (STR, LEN)
 
#ifdef TE_PE
 
#define O_secrel O_md1
 
#define TC_DWARF2_EMIT_OFFSET tc_pe_dwarf2_emit_offset
void tc_pe_dwarf2_emit_offset (symbolS *, unsigned int);
 
#endif /* TE_PE */
 
/* X_add_symbol:X_op_symbol (Intel mode only) */
#define O_full_ptr O_md2
 
#ifdef OBJ_MACH_O
 
#define TC_FORCE_RELOCATION(FIX) (obj_mach_o_force_reloc (FIX))
 
#define TC_FORCE_RELOCATION_SUB_SAME(FIX,SEG) \
(obj_mach_o_force_reloc_sub_same (FIX, SEG))
 
#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX,SEG) \
(obj_mach_o_force_reloc_sub_local (FIX, SEG))
 
#define TC_VALIDATE_FIX_SUB(FIX, SEG) 1
 
#endif /* OBJ_MACH_O */
 
#endif /* TC_I386 */
/contrib/toolchain/binutils/gas/config/te-pe.h
0,0 → 1,26
/* Copyright 2007 Free Software Foundation, Inc.
 
This file is part of GAS, the GNU Assembler.
 
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 3,
or (at your option) any later version.
 
GAS is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
the GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
 
#define TE_PE
#define LEX_AT (LEX_BEGIN_NAME | LEX_NAME) /* Can have @'s inside labels. */
 
/* The PE format supports long section names. */
#define COFF_LONG_SECTION_NAMES
 
#include "obj-format.h"