www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2000/04/09/15:56:55

From: buers AT gmx DOT de (Dieter Buerssner)
Newsgroups: comp.os.msdos.djgpp
Subject: Re: 'retf' in inline?
Date: 9 Apr 2000 19:00:32 GMT
Lines: 131
Message-ID: <8cqr46.3vs4f8r.0@buerssner-17104.user.cis.dfn.de>
References: <38EFFFE0 DOT B217D192 AT home DOT com> <38F02F72 DOT A7C88440 AT mtu-net DOT ru>
NNTP-Posting-Host: pec-105-91.tnt5.s2.uunet.de (149.225.105.91)
Mime-Version: 1.0
X-Trace: fu-berlin.de 955306832 7026263 149.225.105.91 (16 [17104])
X-Posting-Agent: Hamster/1.3.13.0
User-Agent: Xnews/03.02.04
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp
Reply-To: djgpp AT delorie DOT com

Alexei A. Frounze wrote:

A few comments to your ASM guide.

> [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.

You could mention, that instead of writing

  "rep\n"
  "stosd\n"

one can also write

  "rep; stosd\n"

At least, this form is more pleasing to my eyes ;)


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

This may produce wrong code, becauce gcc has no way to know, that
i is modified by the inline assembly. Note, that gcc does not try
interprete the asm code. So, if you use i again after your asm
instruction, gcc may assume, that it is still zero. 

>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

But you should have an output variable.

>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.

You might want to mention "q" for one of eax/ebx/ecx/edx as well.

>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; */

This may produce wrong code as well. With your code gcc is free to
allocate register eax for variable j. The line

  addl %1, %%eax\n

will then be translated to

  addl %eax, %eax

by gcc. 

> [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!). 

Gcc won't modify asm statements. It can reorder, delete ...
asm instructions (from asm(... up to the closing ).

>        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; */

Here you have the same problem as above. If either j or k are
allocated to register eax by gcc, the code won't work.

>        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; */

Why have you put "memory" into the clobber list. This is not needed
here. What could be needed is "cc" for condition code. This would
tell gcc, that your code will modify the flags. (But AFAIK gcc for x86
will always assume, that the flags get modified. Who knows, when this
will change ...)

> [GOTCHA!] ] If we are also touching memory (writing to vars, etc.), it's
>recommended to specify '"memory"' in the registers-modified field. This

You don't need "memory", when you modify a variable. You need memory
when i.e. a variable is a pointer, and you modify the memory where
it points to. A typical example would be a memmove/memcopy implementation.

Also, an other example, that shows how to write code for clobbered
input registers might be useful here. At least you should mention,
that an input register may not be in the clobber list.

Finally, an example the shows what to do when you need an register
as input and output could be helpful.

-- 
Regards, Dieter


- Raw text -


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