delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1997/10/20/21:57:55

From: VANGEL AT vmredipn DOT ipn DOT mx
Message-Id: <199710210156.VAA15453@delorie.com>
Date: Mon, 20 Oct 97 20:52:12 EST
To: djgpp AT delorie DOT com
Subject: Re--> AT&T ASM : tutorials?

> Hello ....

Hi,

	I was just wondering, is there a place where I can download a
tutorial of basic assembly language suitable for use with DJGPP's inline
assembler? I've seen a few which cover differences between intel ASM and
AT&T ASM, and at the moment it seems my only option may be to learn
intel ASM and then do the conversion courses, but this seems needlessly
time filling. Or maybe someone could give me a couple of examples of
AT&T ASM, just to get me started? I have been trying some things, but
they have all spectacularly failed to have worked so far. I have to
learn intel ASM as part of a college course soon anyway (a couple of
months, maybe a half a year) . . . just what does everyone ele suggest?
A nice URL for an AT&T assembler tutorial would be nice. Actually all I
really want to be able to do is load registers, add, shift right and
write to addresses in memory - but I should probably learn the full set
anyway. So what should I do?

		-Thomas

> Well ....  check the fellow  ...  :


Web page: HTTP://www.castle.net:80/~avly/djasm.html
                                               DJGPP QuickAsm Programming Guide
DJGPP QuickAsm Programming Guide

 Okay, so this tutorial has long been overdue, I've been putting it off for a
couple of months; but right now I'm in the mood to write it so here it is. This
is just a short tutorial on doing assembly code using DJGPP. I am NOT teaching
how to code x86 asm (get another tutorial or book); but I'll try to show how to
do both inline and external asm in DJGPP. I assume you are already familiar
with "standard" Intel asm, as used in TASM, MASM, etc.

I highly suggest reading the FAQ lists first, faq102.zip and faq210b.zip , and
the online docs, inside the txi*.zip package. There is also a newsgroup, comp.o
 .msdos.djgpp . The main site is located at DJGPP Homepage , where the most
up-to-date information is available on DJGPP and where the mail archives are
kept. I find many helpful articles in the mail archives.

________________________________________________________________________________

AT&T x86 Asm Syntax

 DJGPP uses AT&T asm syntax. This is a little bit different from the regular
Intel format. The main differences are:

     <*> AT&T syntax uses the opposite order for source and destination
         operands, source followed by destination.
     <*> Register operands are preceded by the "%" character, including
         sections.
     <*> Immediate operands are preceded by the "$" character.
     <*> The size of memory operands are specified using the last character of
         the opcode. These are "b" (8-bit), "w" (16-bit), and "l" (32-bit).

Here are some examples: (Intel equivalent in parentheses)

        movw %bx, %ax   (mov ax, bx)
        xorl %eax, %eax (xor eax, eax)
        movw $1, %ax    (mov ax,1)
        movb X, %ah     (mov ah, byte ptr X)
        movw X, %ax     (mov ax, word ptr X)
        movl X, %eax    (mov eax, X)

Most opcodes are identical between AT&T and Intel format, except for these:

        movsSD (movsx)
        movzSD (movzx)

Where S and D are the source and destination operand size suffixes,
respectively. For example, "movswl %ax, %ecx (movsx ecx, ax)".

        cbtw        (cbw)
        cwtl        (cwde)
        cwtd        (cwd)
        cltd        (cdq)
        lcall $S,$O (call far S:O)
        ljmp $S,$O  (jump far S:O)
        lret $V     (ret far V)

[GOTCHA!] Opcode prefixes should NOT be written on the same line as the
instruction they act upon. For example, "rep" and "stosd" should be two
separate instructions, but the latter immediately following the former.

Memory references are a little bit different too. The usual Intel memory
reference of the form

SECTION:[BASE + INDEX*SCALE + DISP]

is written as

SECTION:DISP(BASE, INDEX, SCALE).

Here are some examples: (Intel equivalent in parentheses)

        movl 4(%ebp), %eax            (mov eax, [ebp+4])
        addl (%eax,%eax,4), %ecx      (add ecx, [eax + eax*4])
        movb $4, %fs:(%eax)           (mov fs:eax, 4)
        movl _array(,%eax,4), %eax    (mov eax, [4*eax + array])
        movw _array(%ebx,%eax,4), %cx (mov cx, [ebx + 4*eax + array])

Jump instructions always use the smallest displacements. The following
instructions always work in byte displacements only, however: "jcxz", "jecxz",
"loop", "loopz", "loope", "loopnz" and "loopne". As suggested in the online
docs, a "jcxz foo" could be expanded to work:

          jcxz cx_zero
          jmp cx_nonzero
        cx_zero:
          jmp foo
        cx_nonzero:

[GOTCHA!] The online docs also caution on "mul" and "imul" instructions. The
expanding multiply instructions are done using ONE operand. For example, "imul
$ebx, $ebx" will NOT put the result in "edx:eax". Use the single operand form
"imul %ebx" to get the expanded result.

________________________________________________________________________________

Inline Asm

 I'll start with inline asm first, because it seems to be the more frequently
asked question. This is the basic syntax, as described in the online help:

__asm__(asm statements : outputs : inputs : registers-modified);

The four fields are:

     <*> asm statements - AT&T form, separated by newline
     <*> outputs - constraint followed by name in parentheses, separated by
         comma
     <*> inputs - constraint followed by name in parentheses, separated by comma
     <*> registers-modified - names separated by comma

The simplest example:

        __asm__("
          pushl %eax\n
          movl $1, %eax\n
          popl %eax"
        );

[GOTCHA!] You don't always have to use the other three fields, as long as you
don't want to specify any input/output variables and you're NOT accidentally
clobbering any registers.

Let's spice it up with input variables .

        int i = 0;
        __asm__("
          pushl %%eax\n
          movl %0, %%eax\n
          addl $1, %%eax\n
          movl %%eax, %0\n
          popl %%eax"
          :
          : "g" (i)
        );
          /* i++; */

Don't panic yet! =) I'll try to explain first. Our input variable is "i" and we
want to increment it by 1. We don't have any output variables, nor clobbered
registers (we save "eax" ourselves). Therefore the second and last fields are
empty.

[GOTCHA!] Since the input field is specified, we need to leave a blank colon
for the output field, but none for the last field, since it isn't used. Leave a
newline or at least one space between two blank colons.

Let's move on to the input field . Constraints are just instructions you give
to the compiler to handle the variables they act upon. They are enclosed in
double quotes. So what does the '"g"' mean? '"g"' lets the compiler decide
where to load the value of "i" into, as long as the asm instructions accept it.
In general, most of your input variables can be constrained as '"g"', letting
the compiler decide how to load them (gcc might even optimize it!). Other
commonly used constraints are "r" (load into any available register), "a"
(ax/eax), "b" (bx/ebx), "c" (cx/ecx), "d" (dx/edx), "D" (di/edi), "S" (si/esi),
etc.

The one input we have will be referred to as "%0" inside the asm statements. If
we have two inputs, they will be "%0" and "%1", in the order listed in the
input fields (see next example). For N inputs and NO outputs, "%0" through
"%N-1" will correspond to the inputs, in the order they are listed.

[GOTCHA!] If ANY of the input, output, or registers-modified fields are used,
register names inside the asm statements must be preceded with two percent
("%") characters, instead of one. Contrast this example with the first one,
which didn't use any of the last three fields.

Let's do two inputs and introduce " volatile ":

        int i=0, j=1;
        __asm__ __volatile__("
          pushl %%eax\n
          movl %0, %%eax\n
          addl %1, %%eax\n
          movl %%eax, %0\n
          popl %%eax"
          :
          : "g" (i), "g" (j)
        );
          /* i = i + j; */

Okay, this time around we have two inputs. No problem, the only thing we have
to remember is "%0" corresponds to the first input ("i" in this case), and "%1"
to "j", which is listed after "i".

[GOTCHA!] Oh yeah, what exactly is this " volatile " thing? It just prevents
the compiler from modifying your asm statements (reordering, deleting,
combining, etc.), and assemble them as they are (yes, gcc will optimize if it
feels like it!). I suggest using "volatile" most of the time, and from here on
we'll be using it.

Let's do one which uses the output field this time.

        int i=0;
        __asm__ __volatile__("
          pushl %%eax\n
          movl $1, %%eax\n
          movl %%eax, %0\n
          popl %%eax"
          : "=g" (i)
        );
          /* i=1; */

This looks almost exactly like one of our previous input field examples; and it
is really not very different. All output constraints are preceded by an equal
("=") character. They are also referred from "%0" to "%N-1" inside the asm
statements, in the order they are listed in the output field. You might ask
what happens if one uses both the input and output fields ? Well, the next
example will show you how to use them together.

        int i=0, j=1, k=0;
        __asm__ __volatile__("
          pushl %%eax\n
          movl %1, %%eax\n
          addl %2, %%eax\n
          movl %%eax, %0\n
          popl %%eax"
          : "=g" (k)
          : "g" (i), "g" (j)
        );
          /* k = i + j; */

Okay, the only unclear part is just the numbering of the variables inside the
asm statements. I'll explain.

When using both input and output fields :

*** %0 ... %K are the outputs

*** %K+1 ... %N are the inputs

In our example, "%0" refers to "k", "%1" to "i", and "%2" to "j". Simple, no?

So far we haven't used the last field, registers-modified , at all. If we need
to use any register inside our asm statements, we either have to "push" or
"pop" them explicitly, or list them in this field and let gcc take care of
that. Here's the previous example, without the explicit "eax" save and restore.

        int i=0, j=1, k=0;
        __asm__ __volatile__("
          movl %1, %%eax\n
          addl %2, %%eax\n
          movl %%eax, %0"
          : "=g" (k)
          : "g" (i), "g" (j)
          : "ax", "memory"
        );
          /* k = i + j; */

We tell gcc that we're using register "eax" in the registers-modified field and
it will take care of saving or restoring, if necessary. A 16-bit register name
covers 32-, 16- or 8-bit registers.

[GOTCHA!] If we are also touching memory (writing to vars, etc.), it's
recommended to specify '"memory"' in the registers-modified field. This means
all our examples here should have had this specified (well, except the very
first one), but I chose not to bring this up until now, just for simplicity.

 Local labels inside your inline asm should be terminated with either "b" or
"f", for backward and forward references, respectively.

For example,

        __asm__ __volatile__("
        0:\n
          ...
          jmp 0b\n
          ...
          jmp 1f\n
          ...
        1:\n
          ...
        );

________________________________________________________________________________

External Asm

 Blah... Okay fine. Here's a clue: Get some of your C/C++ files, and compile
them as "gcc -S file.c" Then inspect file.S. The basic layout is:

  .file "myasm.S"

  .data
    somedata: .word 0
    ...

  .text
    .globl __myasmfunc
    __myasmfunc:
      ...
      ret

Macros, macros! There's a header file <libc/asmdefs.h> that is convenient for
writing external asm. Just include it on top of your asm source and use the
macros accordingly. For example, here's myasm.S:

  #include <libc/asmdefs.h>

  .file "myasm.S"

  .data
    .align 2
    somedata: .word  0
    ...

  .text
    .align 4
    FUNC(__MyExternalAsmFunc)
    ENTER
      movl   ARG1, %eax
      ...
      jmp    mylabel
      ...
    mylabel:
      ...
    LEAVE

That should be a good skeleton for your external asm code.

________________________________________________________________________________

Other Resources

 The best way to learn all these is to look at others' code. There's some
inline asm code in the <sys/farptr.h>. Also, if you run Linux, FreeBSD, etc.,
somewhere in the kernel source tree (i386/ or something), there are plenty of
asm sources. Check the djgpp2/ dir at x2ftp.oulu.fi, for graphics/gaming
libraries that have sources.

If you have asm code that needs to be converted from Intel to AT&T syntax, or
just want to stick with regular Intel syntax, you can:

     <*> Get NASM , a free assembler which takes Intel asm format and produces
         COFF binaries compatible with DJGPP
     <*> Get MASM and compile your sources to COFF format (object file format
         used by DJGPP)
     <*> Get ta2asv08.zip , a TASM to AT&T asm converter
     <*> Get o2cv10.arj to convert .OBJ/.LIB between TASM and DJGPP
     <*> Search the mail archives for a sed script that converts Intel to AT&T
         syntax

________________________________________________________________________________
July 26, 1997 icbm AT IRC

GREETS IdealNet & EFNET IRC #c and #gamecode

Thanks to all people behind DJGPP!

Mail me corrections/suggestions/complaints/crap at avly AT castle DOT net

Copyright (c) 1996-97 avly AT castle DOT net All Rights Reserved

 Standard Disclaimer: All trademarks mentioned are owned by their respective
 companies. There are absolutely no guarantees, expressed or implied, on
 anything that you find in this document. I cannot be held responsible for
 anything that results from the use or misuse of this document.
-------------------------------------------------------------------------------

> Good Look .....    :) .....   ( Check the Page ---> www.delorie.com/djgpp/man
> uals/ .....

> Greetings ....


บบบบบบบบบบบบบบบบบบบบบบบบบบบบบบบบบบบบบบ
บบบ                                บบบ
บบบ   Victor Angel Huerta          บบบ
บบบ                                บบบ
บบบ   Estudent of Engineer         บบบ
บบบ   Electronic and Comunications บบบ
บบบ                                บบบ
บบบ   vangel AT vmredipn DOT ipn DOT mx       บบบ
บบบบบบบบบบบบบบบบบบบบบบบบบบบบบบบบบบบบบบ

- Raw text -


  webmaster     delorie software   privacy  
  Copyright ฉ 2019   by DJ Delorie     Updated Jul 2019