552 lines
20 KiB
HTML
552 lines
20 KiB
HTML
<HTML>
|
|
<HEAD>
|
|
<!-- This HTML file has been created by texi2html 1.52
|
|
from ../texi/as.texinfo on 24 April 1999 -->
|
|
|
|
<TITLE>Using as - 80386 Dependent Features</TITLE>
|
|
</HEAD>
|
|
<BODY>
|
|
Go to the <A HREF="as_1.html">first</A>, <A HREF="as_15.html">previous</A>, <A HREF="as_17.html">next</A>, <A HREF="as_27.html">last</A> section, <A HREF="as_toc.html">table of contents</A>.
|
|
<P><HR><P>
|
|
|
|
|
|
<H1><A NAME="SEC196" HREF="as_toc.html#TOC196">80386 Dependent Features</A></H1>
|
|
|
|
<P>
|
|
<A NAME="IDX577"></A>
|
|
<A NAME="IDX578"></A>
|
|
|
|
</P>
|
|
|
|
|
|
<H2><A NAME="SEC197" HREF="as_toc.html#TOC197">Options</A></H2>
|
|
|
|
<P>
|
|
<A NAME="IDX579"></A>
|
|
<A NAME="IDX580"></A>
|
|
The 80386 has no machine dependent options.
|
|
|
|
</P>
|
|
|
|
|
|
<H2><A NAME="SEC198" HREF="as_toc.html#TOC198">AT&T Syntax versus Intel Syntax</A></H2>
|
|
|
|
<P>
|
|
<A NAME="IDX581"></A>
|
|
<A NAME="IDX582"></A>
|
|
In order to maintain compatibility with the output of <CODE>gcc</CODE>,
|
|
<CODE>as</CODE> supports AT&T System V/386 assembler syntax. This is quite
|
|
different from Intel syntax. We mention these differences because
|
|
almost all 80386 documents used only Intel syntax. Notable differences
|
|
between the two syntaxes are:
|
|
|
|
</P>
|
|
<P>
|
|
<A NAME="IDX583"></A>
|
|
<A NAME="IDX584"></A>
|
|
<A NAME="IDX585"></A>
|
|
<A NAME="IDX586"></A>
|
|
<A NAME="IDX587"></A>
|
|
<A NAME="IDX588"></A>
|
|
<A NAME="IDX589"></A>
|
|
|
|
<UL>
|
|
<LI>
|
|
|
|
AT&T immediate operands are preceded by <SAMP>`$'</SAMP>; Intel immediate
|
|
operands are undelimited (Intel <SAMP>`push 4'</SAMP> is AT&T <SAMP>`pushl $4'</SAMP>).
|
|
AT&T register operands are preceded by <SAMP>`%'</SAMP>; Intel register operands
|
|
are undelimited. AT&T absolute (as opposed to PC relative) jump/call
|
|
operands are prefixed by <SAMP>`*'</SAMP>; they are undelimited in Intel syntax.
|
|
|
|
<A NAME="IDX590"></A>
|
|
<A NAME="IDX591"></A>
|
|
<LI>
|
|
|
|
AT&T and Intel syntax use the opposite order for source and destination
|
|
operands. Intel <SAMP>`add eax, 4'</SAMP> is <SAMP>`addl $4, %eax'</SAMP>. The
|
|
<SAMP>`source, dest'</SAMP> convention is maintained for compatibility with
|
|
previous Unix assemblers.
|
|
|
|
<A NAME="IDX592"></A>
|
|
<A NAME="IDX593"></A>
|
|
<A NAME="IDX594"></A>
|
|
<LI>
|
|
|
|
In AT&T syntax the size of memory operands is determined from the last
|
|
character of the opcode name. Opcode suffixes of <SAMP>`b'</SAMP>, <SAMP>`w'</SAMP>,
|
|
and <SAMP>`l'</SAMP> specify byte (8-bit), word (16-bit), and long (32-bit)
|
|
memory references. Intel syntax accomplishes this by prefixes memory
|
|
operands (<EM>not</EM> the opcodes themselves) with <SAMP>`byte ptr'</SAMP>,
|
|
<SAMP>`word ptr'</SAMP>, and <SAMP>`dword ptr'</SAMP>. Thus, Intel <SAMP>`mov al, byte
|
|
ptr <VAR>foo</VAR>'</SAMP> is <SAMP>`movb <VAR>foo</VAR>, %al'</SAMP> in AT&T syntax.
|
|
|
|
<A NAME="IDX595"></A>
|
|
<A NAME="IDX596"></A>
|
|
<LI>
|
|
|
|
Immediate form long jumps and calls are
|
|
<SAMP>`lcall/ljmp $<VAR>section</VAR>, $<VAR>offset</VAR>'</SAMP> in AT&T syntax; the
|
|
Intel syntax is
|
|
<SAMP>`call/jmp far <VAR>section</VAR>:<VAR>offset</VAR>'</SAMP>. Also, the far return
|
|
instruction
|
|
is <SAMP>`lret $<VAR>stack-adjust</VAR>'</SAMP> in AT&T syntax; Intel syntax is
|
|
<SAMP>`ret far <VAR>stack-adjust</VAR>'</SAMP>.
|
|
|
|
<A NAME="IDX597"></A>
|
|
<A NAME="IDX598"></A>
|
|
<LI>
|
|
|
|
The AT&T assembler does not provide support for multiple section
|
|
programs. Unix style systems expect all programs to be single sections.
|
|
</UL>
|
|
|
|
|
|
|
|
<H2><A NAME="SEC199" HREF="as_toc.html#TOC199">Opcode Naming</A></H2>
|
|
|
|
<P>
|
|
<A NAME="IDX599"></A>
|
|
<A NAME="IDX600"></A>
|
|
Opcode names are suffixed with one character modifiers which specify the
|
|
size of operands. The letters <SAMP>`b'</SAMP>, <SAMP>`w'</SAMP>, and <SAMP>`l'</SAMP> specify
|
|
byte, word, and long operands. If no suffix is specified by an
|
|
instruction and it contains no memory operands then <CODE>as</CODE> tries to
|
|
fill in the missing suffix based on the destination register operand
|
|
(the last one by convention). Thus, <SAMP>`mov %ax, %bx'</SAMP> is equivalent
|
|
to <SAMP>`movw %ax, %bx'</SAMP>; also, <SAMP>`mov $1, %bx'</SAMP> is equivalent to
|
|
<SAMP>`movw $1, %bx'</SAMP>. Note that this is incompatible with the AT&T Unix
|
|
assembler which assumes that a missing opcode suffix implies long
|
|
operand size. (This incompatibility does not affect compiler output
|
|
since compilers always explicitly specify the opcode suffix.)
|
|
|
|
</P>
|
|
<P>
|
|
Almost all opcodes have the same names in AT&T and Intel format. There
|
|
are a few exceptions. The sign extend and zero extend instructions need
|
|
two sizes to specify them. They need a size to sign/zero extend
|
|
<EM>from</EM> and a size to zero extend <EM>to</EM>. This is accomplished
|
|
by using two opcode suffixes in AT&T syntax. Base names for sign extend
|
|
and zero extend are <SAMP>`movs...'</SAMP> and <SAMP>`movz...'</SAMP> in AT&T
|
|
syntax (<SAMP>`movsx'</SAMP> and <SAMP>`movzx'</SAMP> in Intel syntax). The opcode
|
|
suffixes are tacked on to this base name, the <EM>from</EM> suffix before
|
|
the <EM>to</EM> suffix. Thus, <SAMP>`movsbl %al, %edx'</SAMP> is AT&T syntax for
|
|
"move sign extend <EM>from</EM> %al <EM>to</EM> %edx." Possible suffixes,
|
|
thus, are <SAMP>`bl'</SAMP> (from byte to long), <SAMP>`bw'</SAMP> (from byte to word),
|
|
and <SAMP>`wl'</SAMP> (from word to long).
|
|
|
|
</P>
|
|
<P>
|
|
<A NAME="IDX601"></A>
|
|
<A NAME="IDX602"></A>
|
|
The Intel-syntax conversion instructions
|
|
|
|
</P>
|
|
|
|
<UL>
|
|
<LI>
|
|
|
|
<SAMP>`cbw'</SAMP> -- sign-extend byte in <SAMP>`%al'</SAMP> to word in <SAMP>`%ax'</SAMP>,
|
|
|
|
<LI>
|
|
|
|
<SAMP>`cwde'</SAMP> -- sign-extend word in <SAMP>`%ax'</SAMP> to long in <SAMP>`%eax'</SAMP>,
|
|
|
|
<LI>
|
|
|
|
<SAMP>`cwd'</SAMP> -- sign-extend word in <SAMP>`%ax'</SAMP> to long in <SAMP>`%dx:%ax'</SAMP>,
|
|
|
|
<LI>
|
|
|
|
<SAMP>`cdq'</SAMP> -- sign-extend dword in <SAMP>`%eax'</SAMP> to quad in <SAMP>`%edx:%eax'</SAMP>,
|
|
</UL>
|
|
|
|
<P>
|
|
are called <SAMP>`cbtw'</SAMP>, <SAMP>`cwtl'</SAMP>, <SAMP>`cwtd'</SAMP>, and <SAMP>`cltd'</SAMP> in
|
|
AT&T naming. <CODE>as</CODE> accepts either naming for these instructions.
|
|
|
|
</P>
|
|
<P>
|
|
<A NAME="IDX603"></A>
|
|
<A NAME="IDX604"></A>
|
|
Far call/jump instructions are <SAMP>`lcall'</SAMP> and <SAMP>`ljmp'</SAMP> in
|
|
AT&T syntax, but are <SAMP>`call far'</SAMP> and <SAMP>`jump far'</SAMP> in Intel
|
|
convention.
|
|
|
|
</P>
|
|
|
|
|
|
<H2><A NAME="SEC200" HREF="as_toc.html#TOC200">Register Naming</A></H2>
|
|
|
|
<P>
|
|
<A NAME="IDX605"></A>
|
|
<A NAME="IDX606"></A>
|
|
Register operands are always prefixes with <SAMP>`%'</SAMP>. The 80386 registers
|
|
consist of
|
|
|
|
</P>
|
|
|
|
<UL>
|
|
<LI>
|
|
|
|
the 8 32-bit registers <SAMP>`%eax'</SAMP> (the accumulator), <SAMP>`%ebx'</SAMP>,
|
|
<SAMP>`%ecx'</SAMP>, <SAMP>`%edx'</SAMP>, <SAMP>`%edi'</SAMP>, <SAMP>`%esi'</SAMP>, <SAMP>`%ebp'</SAMP> (the
|
|
frame pointer), and <SAMP>`%esp'</SAMP> (the stack pointer).
|
|
|
|
<LI>
|
|
|
|
the 8 16-bit low-ends of these: <SAMP>`%ax'</SAMP>, <SAMP>`%bx'</SAMP>, <SAMP>`%cx'</SAMP>,
|
|
<SAMP>`%dx'</SAMP>, <SAMP>`%di'</SAMP>, <SAMP>`%si'</SAMP>, <SAMP>`%bp'</SAMP>, and <SAMP>`%sp'</SAMP>.
|
|
|
|
<LI>
|
|
|
|
the 8 8-bit registers: <SAMP>`%ah'</SAMP>, <SAMP>`%al'</SAMP>, <SAMP>`%bh'</SAMP>,
|
|
<SAMP>`%bl'</SAMP>, <SAMP>`%ch'</SAMP>, <SAMP>`%cl'</SAMP>, <SAMP>`%dh'</SAMP>, and <SAMP>`%dl'</SAMP> (These
|
|
are the high-bytes and low-bytes of <SAMP>`%ax'</SAMP>, <SAMP>`%bx'</SAMP>,
|
|
<SAMP>`%cx'</SAMP>, and <SAMP>`%dx'</SAMP>)
|
|
|
|
<LI>
|
|
|
|
the 6 section registers <SAMP>`%cs'</SAMP> (code section), <SAMP>`%ds'</SAMP>
|
|
(data section), <SAMP>`%ss'</SAMP> (stack section), <SAMP>`%es'</SAMP>, <SAMP>`%fs'</SAMP>,
|
|
and <SAMP>`%gs'</SAMP>.
|
|
|
|
<LI>
|
|
|
|
the 3 processor control registers <SAMP>`%cr0'</SAMP>, <SAMP>`%cr2'</SAMP>, and
|
|
<SAMP>`%cr3'</SAMP>.
|
|
|
|
<LI>
|
|
|
|
the 6 debug registers <SAMP>`%db0'</SAMP>, <SAMP>`%db1'</SAMP>, <SAMP>`%db2'</SAMP>,
|
|
<SAMP>`%db3'</SAMP>, <SAMP>`%db6'</SAMP>, and <SAMP>`%db7'</SAMP>.
|
|
|
|
<LI>
|
|
|
|
the 2 test registers <SAMP>`%tr6'</SAMP> and <SAMP>`%tr7'</SAMP>.
|
|
|
|
<LI>
|
|
|
|
the 8 floating point register stack <SAMP>`%st'</SAMP> or equivalently
|
|
<SAMP>`%st(0)'</SAMP>, <SAMP>`%st(1)'</SAMP>, <SAMP>`%st(2)'</SAMP>, <SAMP>`%st(3)'</SAMP>,
|
|
<SAMP>`%st(4)'</SAMP>, <SAMP>`%st(5)'</SAMP>, <SAMP>`%st(6)'</SAMP>, and <SAMP>`%st(7)'</SAMP>.
|
|
</UL>
|
|
|
|
|
|
|
|
<H2><A NAME="SEC201" HREF="as_toc.html#TOC201">Opcode Prefixes</A></H2>
|
|
|
|
<P>
|
|
<A NAME="IDX607"></A>
|
|
<A NAME="IDX608"></A>
|
|
<A NAME="IDX609"></A>
|
|
Opcode prefixes are used to modify the following opcode. They are used
|
|
to repeat string instructions, to provide section overrides, to perform
|
|
bus lock operations, and to give operand and address size (16-bit
|
|
operands are specified in an instruction by prefixing what would
|
|
normally be 32-bit operands with a "operand size" opcode prefix).
|
|
Opcode prefixes are usually given as single-line instructions with no
|
|
operands, and must directly precede the instruction they act upon. For
|
|
example, the <SAMP>`scas'</SAMP> (scan string) instruction is repeated with:
|
|
|
|
<PRE>
|
|
repne
|
|
scas
|
|
</PRE>
|
|
|
|
<P>
|
|
Here is a list of opcode prefixes:
|
|
|
|
</P>
|
|
<P>
|
|
<A NAME="IDX610"></A>
|
|
|
|
<UL>
|
|
<LI>
|
|
|
|
Section override prefixes <SAMP>`cs'</SAMP>, <SAMP>`ds'</SAMP>, <SAMP>`ss'</SAMP>, <SAMP>`es'</SAMP>,
|
|
<SAMP>`fs'</SAMP>, <SAMP>`gs'</SAMP>. These are automatically added by specifying
|
|
using the <VAR>section</VAR>:<VAR>memory-operand</VAR> form for memory references.
|
|
|
|
<A NAME="IDX611"></A>
|
|
<LI>
|
|
|
|
Operand/Address size prefixes <SAMP>`data16'</SAMP> and <SAMP>`addr16'</SAMP>
|
|
change 32-bit operands/addresses into 16-bit operands/addresses. Note
|
|
that 16-bit addressing modes (i.e. 8086 and 80286 addressing modes)
|
|
are not supported (yet).
|
|
|
|
<A NAME="IDX612"></A>
|
|
<A NAME="IDX613"></A>
|
|
<LI>
|
|
|
|
The bus lock prefix <SAMP>`lock'</SAMP> inhibits interrupts during
|
|
execution of the instruction it precedes. (This is only valid with
|
|
certain instructions; see a 80386 manual for details).
|
|
|
|
<A NAME="IDX614"></A>
|
|
<LI>
|
|
|
|
The wait for coprocessor prefix <SAMP>`wait'</SAMP> waits for the
|
|
coprocessor to complete the current instruction. This should never be
|
|
needed for the 80386/80387 combination.
|
|
|
|
<A NAME="IDX615"></A>
|
|
<LI>
|
|
|
|
The <SAMP>`rep'</SAMP>, <SAMP>`repe'</SAMP>, and <SAMP>`repne'</SAMP> prefixes are added
|
|
to string instructions to make them repeat <SAMP>`%ecx'</SAMP> times.
|
|
</UL>
|
|
|
|
|
|
|
|
<H2><A NAME="SEC202" HREF="as_toc.html#TOC202">Memory References</A></H2>
|
|
|
|
<P>
|
|
<A NAME="IDX616"></A>
|
|
<A NAME="IDX617"></A>
|
|
An Intel syntax indirect memory reference of the form
|
|
|
|
</P>
|
|
|
|
<PRE>
|
|
<VAR>section</VAR>:[<VAR>base</VAR> + <VAR>index</VAR>*<VAR>scale</VAR> + <VAR>disp</VAR>]
|
|
</PRE>
|
|
|
|
<P>
|
|
is translated into the AT&T syntax
|
|
|
|
</P>
|
|
|
|
<PRE>
|
|
<VAR>section</VAR>:<VAR>disp</VAR>(<VAR>base</VAR>, <VAR>index</VAR>, <VAR>scale</VAR>)
|
|
</PRE>
|
|
|
|
<P>
|
|
where <VAR>base</VAR> and <VAR>index</VAR> are the optional 32-bit base and
|
|
index registers, <VAR>disp</VAR> is the optional displacement, and
|
|
<VAR>scale</VAR>, taking the values 1, 2, 4, and 8, multiplies <VAR>index</VAR>
|
|
to calculate the address of the operand. If no <VAR>scale</VAR> is
|
|
specified, <VAR>scale</VAR> is taken to be 1. <VAR>section</VAR> specifies the
|
|
optional section register for the memory operand, and may override the
|
|
default section register (see a 80386 manual for section register
|
|
defaults). Note that section overrides in AT&T syntax <EM>must</EM> have
|
|
be preceded by a <SAMP>`%'</SAMP>. If you specify a section override which
|
|
coincides with the default section register, <CODE>as</CODE> does <EM>not</EM>
|
|
output any section register override prefixes to assemble the given
|
|
instruction. Thus, section overrides can be specified to emphasize which
|
|
section register is used for a given memory operand.
|
|
|
|
</P>
|
|
<P>
|
|
Here are some examples of Intel and AT&T style memory references:
|
|
|
|
</P>
|
|
<DL COMPACT>
|
|
|
|
<DT>AT&T: <SAMP>`-4(%ebp)'</SAMP>, Intel: <SAMP>`[ebp - 4]'</SAMP>
|
|
<DD>
|
|
<VAR>base</VAR> is <SAMP>`%ebp'</SAMP>; <VAR>disp</VAR> is <SAMP>`-4'</SAMP>. <VAR>section</VAR> is
|
|
missing, and the default section is used (<SAMP>`%ss'</SAMP> for addressing with
|
|
<SAMP>`%ebp'</SAMP> as the base register). <VAR>index</VAR>, <VAR>scale</VAR> are both missing.
|
|
|
|
<DT>AT&T: <SAMP>`foo(,%eax,4)'</SAMP>, Intel: <SAMP>`[foo + eax*4]'</SAMP>
|
|
<DD>
|
|
<VAR>index</VAR> is <SAMP>`%eax'</SAMP> (scaled by a <VAR>scale</VAR> 4); <VAR>disp</VAR> is
|
|
<SAMP>`foo'</SAMP>. All other fields are missing. The section register here
|
|
defaults to <SAMP>`%ds'</SAMP>.
|
|
|
|
<DT>AT&T: <SAMP>`foo(,1)'</SAMP>; Intel <SAMP>`[foo]'</SAMP>
|
|
<DD>
|
|
This uses the value pointed to by <SAMP>`foo'</SAMP> as a memory operand.
|
|
Note that <VAR>base</VAR> and <VAR>index</VAR> are both missing, but there is only
|
|
<EM>one</EM> <SAMP>`,'</SAMP>. This is a syntactic exception.
|
|
|
|
<DT>AT&T: <SAMP>`%gs:foo'</SAMP>; Intel <SAMP>`gs:foo'</SAMP>
|
|
<DD>
|
|
This selects the contents of the variable <SAMP>`foo'</SAMP> with section
|
|
register <VAR>section</VAR> being <SAMP>`%gs'</SAMP>.
|
|
</DL>
|
|
|
|
<P>
|
|
Absolute (as opposed to PC relative) call and jump operands must be
|
|
prefixed with <SAMP>`*'</SAMP>. If no <SAMP>`*'</SAMP> is specified, <CODE>as</CODE>
|
|
always chooses PC relative addressing for jump/call labels.
|
|
|
|
</P>
|
|
<P>
|
|
Any instruction that has a memory operand <EM>must</EM> specify its size (byte,
|
|
word, or long) with an opcode suffix (<SAMP>`b'</SAMP>, <SAMP>`w'</SAMP>, or <SAMP>`l'</SAMP>,
|
|
respectively).
|
|
|
|
</P>
|
|
|
|
|
|
<H2><A NAME="SEC203" HREF="as_toc.html#TOC203">Handling of Jump Instructions</A></H2>
|
|
|
|
<P>
|
|
<A NAME="IDX618"></A>
|
|
<A NAME="IDX619"></A>
|
|
Jump instructions are always optimized to use the smallest possible
|
|
displacements. This is accomplished by using byte (8-bit) displacement
|
|
jumps whenever the target is sufficiently close. If a byte displacement
|
|
is insufficient a long (32-bit) displacement is used. We do not support
|
|
word (16-bit) displacement jumps (i.e. prefixing the jump instruction
|
|
with the <SAMP>`addr16'</SAMP> opcode prefix), since the 80386 insists upon masking
|
|
<SAMP>`%eip'</SAMP> to 16 bits after the word displacement is added.
|
|
|
|
</P>
|
|
<P>
|
|
Note that the <SAMP>`jcxz'</SAMP>, <SAMP>`jecxz'</SAMP>, <SAMP>`loop'</SAMP>, <SAMP>`loopz'</SAMP>,
|
|
<SAMP>`loope'</SAMP>, <SAMP>`loopnz'</SAMP> and <SAMP>`loopne'</SAMP> instructions only come in byte
|
|
displacements, so that if you use these instructions (<CODE>gcc</CODE> does
|
|
not use them) you may get an error message (and incorrect code). The AT&T
|
|
80386 assembler tries to get around this problem by expanding <SAMP>`jcxz foo'</SAMP>
|
|
to
|
|
|
|
</P>
|
|
|
|
<PRE>
|
|
jcxz cx_zero
|
|
jmp cx_nonzero
|
|
cx_zero: jmp foo
|
|
cx_nonzero:
|
|
</PRE>
|
|
|
|
|
|
|
|
<H2><A NAME="SEC204" HREF="as_toc.html#TOC204">Floating Point</A></H2>
|
|
|
|
<P>
|
|
<A NAME="IDX620"></A>
|
|
<A NAME="IDX621"></A>
|
|
All 80387 floating point types except packed BCD are supported.
|
|
(BCD support may be added without much difficulty). These data
|
|
types are 16-, 32-, and 64- bit integers, and single (32-bit),
|
|
double (64-bit), and extended (80-bit) precision floating point.
|
|
Each supported type has an opcode suffix and a constructor
|
|
associated with it. Opcode suffixes specify operand's data
|
|
types. Constructors build these data types into memory.
|
|
|
|
</P>
|
|
<P>
|
|
<A NAME="IDX622"></A>
|
|
<A NAME="IDX623"></A>
|
|
<A NAME="IDX624"></A>
|
|
<A NAME="IDX625"></A>
|
|
|
|
<UL>
|
|
<LI>
|
|
|
|
Floating point constructors are <SAMP>`.float'</SAMP> or <SAMP>`.single'</SAMP>,
|
|
<SAMP>`.double'</SAMP>, and <SAMP>`.tfloat'</SAMP> for 32-, 64-, and 80-bit formats.
|
|
These correspond to opcode suffixes <SAMP>`s'</SAMP>, <SAMP>`l'</SAMP>, and <SAMP>`t'</SAMP>.
|
|
<SAMP>`t'</SAMP> stands for temporary real, and that the 80387 only supports
|
|
this format via the <SAMP>`fldt'</SAMP> (load temporary real to stack top) and
|
|
<SAMP>`fstpt'</SAMP> (store temporary real and pop stack) instructions.
|
|
|
|
<A NAME="IDX626"></A>
|
|
<A NAME="IDX627"></A>
|
|
<A NAME="IDX628"></A>
|
|
<A NAME="IDX629"></A>
|
|
<LI>
|
|
|
|
Integer constructors are <SAMP>`.word'</SAMP>, <SAMP>`.long'</SAMP> or <SAMP>`.int'</SAMP>, and
|
|
<SAMP>`.quad'</SAMP> for the 16-, 32-, and 64-bit integer formats. The corresponding
|
|
opcode suffixes are <SAMP>`s'</SAMP> (single), <SAMP>`l'</SAMP> (long), and <SAMP>`q'</SAMP>
|
|
(quad). As with the temporary real format the 64-bit <SAMP>`q'</SAMP> format is
|
|
only present in the <SAMP>`fildq'</SAMP> (load quad integer to stack top) and
|
|
<SAMP>`fistpq'</SAMP> (store quad integer and pop stack) instructions.
|
|
</UL>
|
|
|
|
<P>
|
|
Register to register operations do not require opcode suffixes,
|
|
so that <SAMP>`fst %st, %st(1)'</SAMP> is equivalent to <SAMP>`fstl %st, %st(1)'</SAMP>.
|
|
|
|
</P>
|
|
|
|
|
|
<H2><A NAME="SEC205" HREF="as_toc.html#TOC205">Writing 16-bit Code</A></H2>
|
|
|
|
<P>
|
|
<A NAME="IDX630"></A>
|
|
<A NAME="IDX631"></A>
|
|
<A NAME="IDX632"></A>
|
|
<A NAME="IDX633"></A>
|
|
<A NAME="IDX634"></A>
|
|
While GAS normally writes only "pure" 32-bit i386 code, it has limited
|
|
support for writing code to run in real mode or in 16-bit protected mode
|
|
code segments. To do this, insert a <SAMP>`.code16'</SAMP> directive before the
|
|
assembly language instructions to be run in 16-bit mode. You can switch
|
|
GAS back to writing normal 32-bit code with the <SAMP>`.code32'</SAMP> directive.
|
|
|
|
</P>
|
|
<P>
|
|
GAS understands exactly the same assembly language syntax in 16-bit mode as
|
|
in 32-bit mode. The function of any given instruction is exactly the same
|
|
regardless of mode, as long as the resulting object code is executed in the
|
|
mode for which GAS wrote it. So, for example, the <SAMP>`ret'</SAMP> mnemonic
|
|
produces a 32-bit return instruction regardless of whether it is to be run
|
|
in 16-bit or 32-bit mode. (If GAS is in 16-bit mode, it will add an
|
|
operand size prefix to the instruction to force it to be a 32-bit return.)
|
|
|
|
</P>
|
|
<P>
|
|
This means, for one thing, that you can use GNU CC to write code to be run
|
|
in real mode or 16-bit protected mode. Just insert the statement
|
|
<SAMP>`asm(".code16");'</SAMP> at the beginning of your C source file, and while
|
|
GNU CC will still be generating 32-bit code, GAS will automatically add
|
|
all the necessary size prefixes to make that code run in 16-bit mode. Of
|
|
course, since GNU CC only writes small-model code (it doesn't know how to
|
|
attach segment selectors to pointers like native x86 compilers do), any
|
|
16-bit code you write with GNU CC will essentially be limited to a 64K
|
|
address space. Also, there will be a code size and performance penalty
|
|
due to all the extra address and operand size prefixes GAS has to add to
|
|
the instructions.
|
|
|
|
</P>
|
|
<P>
|
|
Note that placing GAS in 16-bit mode does not mean that the resulting
|
|
code will necessarily run on a 16-bit pre-80386 processor. To write code
|
|
that runs on such a processor, you would have to refrain from using
|
|
<EM>any</EM> 32-bit constructs which require GAS to output address or
|
|
operand size prefixes. At the moment this would be rather difficult,
|
|
because GAS currently supports <EM>only</EM> 32-bit addressing modes: when
|
|
writing 16-bit code, it <EM>always</EM> outputs address size prefixes for any
|
|
instruction that uses a non-register addressing mode. So you can write
|
|
code that runs on 16-bit processors, but only if that code never references
|
|
memory.
|
|
|
|
</P>
|
|
|
|
|
|
<H2><A NAME="SEC206" HREF="as_toc.html#TOC206">Notes</A></H2>
|
|
|
|
<P>
|
|
<A NAME="IDX635"></A>
|
|
<A NAME="IDX636"></A>
|
|
<A NAME="IDX637"></A>
|
|
There is some trickery concerning the <SAMP>`mul'</SAMP> and <SAMP>`imul'</SAMP>
|
|
instructions that deserves mention. The 16-, 32-, and 64-bit expanding
|
|
multiplies (base opcode <SAMP>`0xf6'</SAMP>; extension 4 for <SAMP>`mul'</SAMP> and 5
|
|
for <SAMP>`imul'</SAMP>) can be output only in the one operand form. Thus,
|
|
<SAMP>`imul %ebx, %eax'</SAMP> does <EM>not</EM> select the expanding multiply;
|
|
the expanding multiply would clobber the <SAMP>`%edx'</SAMP> register, and this
|
|
would confuse <CODE>gcc</CODE> output. Use <SAMP>`imul %ebx'</SAMP> to get the
|
|
64-bit product in <SAMP>`%edx:%eax'</SAMP>.
|
|
|
|
</P>
|
|
<P>
|
|
We have added a two operand form of <SAMP>`imul'</SAMP> when the first operand
|
|
is an immediate mode expression and the second operand is a register.
|
|
This is just a shorthand, so that, multiplying <SAMP>`%eax'</SAMP> by 69, for
|
|
example, can be done with <SAMP>`imul $69, %eax'</SAMP> rather than <SAMP>`imul
|
|
$69, %eax, %eax'</SAMP>.
|
|
|
|
</P>
|
|
|
|
<P><HR><P>
|
|
Go to the <A HREF="as_1.html">first</A>, <A HREF="as_15.html">previous</A>, <A HREF="as_17.html">next</A>, <A HREF="as_27.html">last</A> section, <A HREF="as_toc.html">table of contents</A>.
|
|
</BODY>
|
|
</HTML>
|