public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* Calling convention that gets frame pointer register clobbered
@ 2003-12-15 19:20 Latchesar Ionkov
  2003-12-16  2:28 ` Jim Wilson
  2003-12-16 17:48 ` Johan Rydberg
  0 siblings, 2 replies; 18+ messages in thread
From: Latchesar Ionkov @ 2003-12-15 19:20 UTC (permalink / raw)
  To: gcc

Hi,

Does gcc support calling conventions that get the frame pointer register
clobbered?

I am trying to port gcc (the i386 target) to an operating system. The
calling convention is an extreme caller-saves one. It does not guarantee
that any register (except the stack pointer) will be preserved.

Does anybody have an idea how to instruct gcc to save the frame pointer
register before function calls? 


Thanks,
	Lucho

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
  2003-12-15 19:20 Calling convention that gets frame pointer register clobbered Latchesar Ionkov
@ 2003-12-16  2:28 ` Jim Wilson
       [not found]   ` <20031216020218.GA26565@ionkov.net>
  2003-12-16 17:48 ` Johan Rydberg
  1 sibling, 1 reply; 18+ messages in thread
From: Jim Wilson @ 2003-12-16  2:28 UTC (permalink / raw)
  To: Latchesar Ionkov; +Cc: gcc

Latchesar Ionkov wrote:
> I am trying to port gcc (the i386 target) to an operating system. The
> calling convention is an extreme caller-saves one. It does not guarantee
> that any register (except the stack pointer) will be preserved.

If the stack pointer is the only preserved register, then the only place 
you can put the frame pointer is to push it on the stack before the 
call, and pop it off the stack after the call.

That is such a badly designed ABI that there doesn't seem to be much 
point in adding generic support for it.

You can handle this manually by modifying your call patterns to emit 
multiple assembler insns, or alternatively, make your call patterns into 
expanders that emit multiple RTL insns.  You can then emit the push/pop 
along with the call.  You will also probably have to handle some other 
registers the same way, the static chain pointer for instance.  The pic 
base register if you want pic support.
-- 
Jim Wilson, GNU Tools Support, http://www.SpecifixInc.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
       [not found]   ` <20031216020218.GA26565@ionkov.net>
@ 2003-12-16  4:49     ` Jim Wilson
       [not found]       ` <20031216032439.GA26833@ionkov.net>
  0 siblings, 1 reply; 18+ messages in thread
From: Jim Wilson @ 2003-12-16  4:49 UTC (permalink / raw)
  To: Latchesar Ionkov; +Cc: gcc

On Mon, 2003-12-15 at 18:02, Latchesar Ionkov wrote:
> I already thought of that, but emitting the push right before the actual
> call won't work, because it will shift the function arguments.

Ah, right, I should have thought of that myself.

There are probably two places you have to change, the expand_call
function which is used for normal calls, and the
emit_library_call_value_1 function which is used for helper functions
like the libgcc2 adddi3 function.

You might be able to handle this like the existing
structure_value_addr_parm, that is a hidden argument for structure
return values.  So we would have another hidden argument for the frame
pointer.  Except that changes the ABI, so I guess that doesn't work
either.

The compiler may not like seeing saves/restores of the frame pointer,
and may not handle this correctly in the optimizer.  You might have to
do something in the optimizers to deal with that.  This is something
that can be avoided if the fp saves/restores are hidden in the call
patterns, and only emitted as assembly code, but unfortunately that
isn't a choice.
-- 
Jim Wilson, GNU Tools Support, http://www.SpecifixInc.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
  2003-12-15 19:20 Calling convention that gets frame pointer register clobbered Latchesar Ionkov
  2003-12-16  2:28 ` Jim Wilson
@ 2003-12-16 17:48 ` Johan Rydberg
  2003-12-17 10:39   ` Jim Wilson
  1 sibling, 1 reply; 18+ messages in thread
From: Johan Rydberg @ 2003-12-16 17:48 UTC (permalink / raw)
  To: gcc

Latchesar Ionkov <lucho@ionkov.net> wrote:

: Hi,
: 
: Does gcc support calling conventions that get the frame pointer register
: clobbered?

A related question:  Is it possible, by inline assembler, to get GCC
to save the frame pointer? I've tried to adding "ebp" to the clobbered
list, with no effect.  It is of course possible to add push/pop insns
to the asm string, but that seems a bit risky, and does not look very
pretty.

brgds
johan

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
  2003-12-16 17:48 ` Johan Rydberg
@ 2003-12-17 10:39   ` Jim Wilson
  0 siblings, 0 replies; 18+ messages in thread
From: Jim Wilson @ 2003-12-17 10:39 UTC (permalink / raw)
  To: Johan Rydberg; +Cc: gcc

Johan Rydberg wrote:
> A related question:  Is it possible, by inline assembler, to get GCC
> to save the frame pointer? 

Try looking at:
	http://gcc.gnu.org/ml/gcc-patches/2003-12/msg01292.html
This patch hasn't been checked in yet.
-- 
Jim Wilson, GNU Tools Support, http://www.SpecifixInc.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
       [not found]         ` <1071552791.1019.84.camel@leaf.tuliptree.org>
@ 2003-12-17 22:42           ` Latchesar Ionkov
  0 siblings, 0 replies; 18+ messages in thread
From: Latchesar Ionkov @ 2003-12-17 22:42 UTC (permalink / raw)
  To: Jim Wilson; +Cc: gcc

It doesn't work if the parameters have variable size. For example:

void f(int n, ...) {
...
}

void g(int n) {
	struct {
		int x[n];
	} d;

	f(n, d);
}

won't work. I think it is impossible to implement it if the ABI doesn't
preserve at least one more register except SP :((

Thanks,
	Lucho

On Mon, Dec 15, 2003 at 09:33:10PM -0800, Jim Wilson said:
> On Mon, 2003-12-15 at 19:24, Latchesar Ionkov wrote:
> > Does it make sense?
> 
> It sounds like a reasonable thing to try.
> -- 
> Jim Wilson, GNU Tools Support, http://www.SpecifixInc.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
  2004-01-05 13:34       ` Etienne Lorrain
@ 2004-01-05 20:44         ` Jim Wilson
  0 siblings, 0 replies; 18+ messages in thread
From: Jim Wilson @ 2004-01-05 20:44 UTC (permalink / raw)
  To: Etienne Lorrain; +Cc: gcc

On Mon, 2004-01-05 at 05:34, Etienne Lorrain wrote:
>   I am not sure, but I think that GCC manage BLKmode objects in registers
>  by having their _address_ in register.
>  Just for my curiosity, a question you may know how to answer: When a
>  function returns a structure (bigger than 32 bits) - does it return
>  a BLKmode object?

There is no relationship between constraints and calling conventions. 
They are completely different things.  Using a register constraint means
that the entire object is to be loaded into the register.  This is true
for all targets, regardless of what the ABI says about the object.

How a structure is returned is target dependent.  It is dictated by the
target's ABI.  Different targets do it different ways.  Some load
BLKmode objects into a register, some load the address.  This has
nothing to do with constraints.
-- 
Jim Wilson, GNU Tools Support, http://www.SpecifixInc.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
  2003-12-31  1:52     ` Jim Wilson
@ 2004-01-05 13:34       ` Etienne Lorrain
  2004-01-05 20:44         ` Jim Wilson
  0 siblings, 1 reply; 18+ messages in thread
From: Etienne Lorrain @ 2004-01-05 13:34 UTC (permalink / raw)
  To: Jim Wilson; +Cc: gcc

 --- Jim Wilson wrote: 
> On Mon, 2003-12-22 at 01:54, Etienne Lorrain wrote:
> >   The code is compiling if the structure is small enough to fit in
> >  a 32 bits register, not if it has to be in memory - I should have
> >  said it.
> > tmp.c:12: internal compiler error: in emit_move_insn, at expr.c:3159
> 
> The structure has a size larger than its alignment, so it is given
> BLKmode.  We can't copy BLKmode objects into registers, which gives the
> abort.

  I am not sure, but I think that GCC manage BLKmode objects in registers
 by having their _address_ in register.
 Just for my curiosity, a question you may know how to answer: When a
 function returns a structure (bigger than 32 bits) - does it return
 a BLKmode object?

> Using "=S" (*ebiosinfo) means load the entire structure into the S reg. 
> We can't fit a large structure into a 32-bit register, so what you are
> trying to do can not be made to work.

 I have re-written the code the way I have understood GCC likes it,
 I did not read GCC source code itself here. The structure is simplified,
 but just compare (with my previous message) how (*ebiosinfo) is
 passed to the asm().

--------------------------------------
typedef struct {
    unsigned short      buffersize;
    unsigned short      infobit;
    unsigned            nbcylinder;
    unsigned            nbhead;
    unsigned            nbsectorpertrack;
    unsigned long long  nbtotalsector;
    unsigned short      bytepersector;
    unsigned short signature0xBEDD;
    unsigned char  lendevicepath;
    unsigned char  reserved[3];
    unsigned char  bustype[4];
    unsigned char  Interface[8];
    union interface_path_u {
        struct {
            unsigned short addr;
            unsigned char pad[6];
            } __attribute__ ((packed)) isa;
        } bus;
    union device_path_u {
        struct {
            unsigned char slave;
            unsigned char pad[7];
            unsigned long long  reserved;
          } __attribute__ ((packed)) ata;
      } device;
    unsigned char zero;
    unsigned char bytechecksum;
    } __attribute__ ((packed)) ebiosinfo_t;

unsigned char
_EBIOSDISK_getparam (unsigned char disk, ebiosinfo_t *ebiosinfo,
                     unsigned char *status)
  {
  unsigned char carry;

  asm (
"       lea     %2,%%esi                                \n"
"       int     $0x13           # _EBIOSDISK_getparam   \n"
"       mov     %%ah,%1                                 \n"
"       setc    %0                                      \n"
        : "=qm" (carry), "=qm" (*status), "=g" (*ebiosinfo)
        : "a"((unsigned short)0x4800), "d" (disk)
        : "esi"
        );

  return carry;
  }
--------------------------------------

  This code does compile without warning - I still did not test
 the executable. It is not really clean to say "=g" and then
 do a lea (load effective address) into %esi but should work.

> You are trying to explain for alias analysis purposes that a structure
> is written by the asm.

  Yes.

> We don't have any explicit way to represent that other than by
> using "=m" (*ebiosinfo).

  "=g" also works, which could randomly select %esi register to pass
 the parameter...
 I think that "=m" would not cover a variable in the current stack
 frame - just a variable in memory - from some debugging I did
 quite long ago. The variables/structures in the current stack
 frame can be optimised further (even removed if not used).

> The asm syntax could perhaps be extended to do what you want.

  It is maybe already complex enought...

  Cheers,
  Etienne.


_________________________________________________________________
Do You Yahoo!? -- Une adresse @yahoo.fr gratuite et en français !
Yahoo! Mail : http://fr.mail.yahoo.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
  2003-12-22 10:54   ` Etienne Lorrain
  2003-12-22 12:03     ` Falk Hueffner
@ 2003-12-31  1:52     ` Jim Wilson
  2004-01-05 13:34       ` Etienne Lorrain
  1 sibling, 1 reply; 18+ messages in thread
From: Jim Wilson @ 2003-12-31  1:52 UTC (permalink / raw)
  To: Etienne Lorrain; +Cc: gcc

On Mon, 2003-12-22 at 01:54, Etienne Lorrain wrote:
>   The code is compiling if the structure is small enough to fit in
>  a 32 bits register, not if it has to be in memory - I should have
>  said it.
> tmp.c:12: internal compiler error: in emit_move_insn, at expr.c:3159

The structure has a size larger than its alignment, so it is given
BLKmode.  We can't copy BLKmode objects into registers, which gives the
abort.

The abort is pretty easy to fix, we just disallow BLKmode objects.  We
now get a reasonable error instead of an abort.  I have attached a patch
which I have not tested yet.

Using "=S" (*ebiosinfo) means load the entire structure into the S reg. 
We can't fit a large structure into a 32-bit register, so what you are
trying to do can not be made to work.  This could not have worked in
earlier gcc versions as you claim.  Probably what happened is that we
didn't give proper errors for this in earlier gcc versions, which is a
common problem with asms.

I see in another message you explained what you are trying to do, but
this is not the way to do it.  You are trying to explain for alias
analysis purposes that a structure is written by the asm.  We don't have
any explicit way to represent that other than by using "=m"
(*ebiosinfo).  The asm syntax could perhaps be extended to do what you
want.  I am not volunteering to do that though.

2003-12-30  James E Wilson  <wilson@specifixinc.com>

	* stmt.c (expand_asm_operands): Don't pass BLKmode to force_reg.

Index: stmt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/stmt.c,v
retrieving revision 1.340
diff -p -r1.340 stmt.c
*** stmt.c	20 Dec 2003 03:21:23 -0000	1.340
--- stmt.c	30 Dec 2003 23:25:46 -0000
*************** expand_asm_operands (tree string, tree o
*** 1703,1709 ****
  
        if (asm_operand_ok (op, constraint) <= 0)
  	{
! 	  if (allows_reg)
  	    op = force_reg (TYPE_MODE (type), op);
  	  else if (!allows_mem)
  	    warning ("asm operand %d probably doesn't match constraints",
--- 1703,1711 ----
  
        if (asm_operand_ok (op, constraint) <= 0)
  	{
! 	  /* BLKmode will trigger an abort in emit_move_insn, so we must
! 	     disallow it.  */
! 	  if (allows_reg && TYPE_MODE (type) != BLKmode)
  	    op = force_reg (TYPE_MODE (type), op);
  	  else if (!allows_mem)
  	    warning ("asm operand %d probably doesn't match constraints",
-- 
Jim Wilson, GNU Tools Support, http://www.SpecifixInc.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
  2003-12-22 15:22         ` Kai Henningsen
@ 2003-12-22 16:59           ` Etienne Lorrain
  0 siblings, 0 replies; 18+ messages in thread
From: Etienne Lorrain @ 2003-12-22 16:59 UTC (permalink / raw)
  To: Kai Henningsen; +Cc: gcc

 --- Kai Henningsen <kaih@khms.westfalen.de> wrote:
> > unsigned char
> > _EBIOSDISK_getparam (unsigned char disk, ebiosinfo_t *ebiosinfo,
> >                      unsigned char *status)
> >   {
> >   unsigned char carry;
> >
> >   asm (
> > "       int     $0x13           # _EBIOSDISK_getparam   \n"
> > "       mov     %%ah,%1                                 \n"
> > "       setc    %0                                      \n"
> >         : "=qm" (carry), "=qm" (*status), "=S" (*ebiosinfo)
> >         : "a"((unsigned short)0x4800), "d" (disk)
> >         );
> >
> >   return carry;
> >   }

  This BIOS service (interrupt 0x13, service in register %ax 0x4800)
 is initialising the complete structure pointed by ebiosinfo for the
 disk in register %dl - variable "disk".
 The inputs are:
    %ax = 0x4800             (16 bits)
    %dl = disk BIOS number   (8 bits)
    %ds:%si = the address of the buffer to fill-in (16 + 16 bits)
 The outputs are:
    the carry flag set if error
    If carry set the reason of the error in 8 bit register %ah
    If carry clear the structure filled-in (75 bytes)

> >   Using output "=m" (*ebiosinfo) and input "S" (ebiosinfo) is not
> >  completely equivalent because the output part may generate strange
> >  code on some compiler version - but that is the best approximation.
> 
> In any case, that's where your error is. You're claiming to move
> the whole structure when actually you're only trying to move
> the pointer.

 This BIOS service (could be any O.S.) is not moving anything, just
 filling a complete structure of 75 bytes with a meaningfull
 description of the disk. The special thing here is that even if the
 complete structure is an output, its address has to be given somehow
 to int 0x13.

 It is not like if the O.S. service would give the address of a constant
 structure - in this later case the return value would be a pointer.

> Don't lie to the compiler, or the compiler will bite you.

  To get GCC to compile the code, right now you have to lie to it.
  Note what is the lie:
 You say you have one more input, the pointer of your buffer, in
 register %ds:%si
 You say that there is a buffer in memory (not in current stack
 frame - that may be the lie) which will be modified.

  What this code need to correctly compile without lying is that
 instead of writing the output "=m" (*ebiosinfo) you can say
 "=S" (*ebiosinfo).

  What happen is exactly the same as:

typedef struct { char a,b; } s1_t;
typedef struct { long long a,b; } s2_t;

s1_t fct1 (int x) {
  s1_t ret = { x + 1, x - 1};
  return ret;
  }

s2_t fct2 (int x) {
  s2_t ret = { x + 1, x - 1};
  return ret;
  }

  Sorry to not be explicit enought at the first time.
  Etienne.

_________________________________________________________________
Do You Yahoo!? -- Une adresse @yahoo.fr gratuite et en français !
Yahoo! Mail : http://fr.mail.yahoo.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
  2003-12-22 14:12       ` Etienne Lorrain
@ 2003-12-22 15:22         ` Kai Henningsen
  2003-12-22 16:59           ` Etienne Lorrain
  0 siblings, 1 reply; 18+ messages in thread
From: Kai Henningsen @ 2003-12-22 15:22 UTC (permalink / raw)
  To: etienne_lorrain; +Cc: gcc

etienne_lorrain@yahoo.fr (Etienne Lorrain)  wrote on 22.12.03 in <20031222105958.13221.qmail@web11801.mail.yahoo.com>:

> unsigned char
> _EBIOSDISK_getparam (unsigned char disk, ebiosinfo_t *ebiosinfo,
>                      unsigned char *status)
>   {
>   unsigned char carry;
>
>   asm (
> "       int     $0x13           # _EBIOSDISK_getparam   \n"
> "       mov     %%ah,%1                                 \n"
> "       setc    %0                                      \n"
>         : "=qm" (carry), "=qm" (*status), "=S" (*ebiosinfo)
>         : "a"((unsigned short)0x4800), "d" (disk)
>         );
>
>   return carry;
>   }

>   Using output "=m" (*ebiosinfo) and input "S" (ebiosinfo) is not
>  completely equivalent because the output part may generate strange
>  code on some compiler version - but that is the best approximation.

In any case, that's where your error is. You're claiming to move the whole  
structure when actually you're only trying to move the pointer.

Don't lie to the compiler, or the compiler will bite you.

MfG Kai

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
  2003-12-22 12:03     ` Falk Hueffner
@ 2003-12-22 14:12       ` Etienne Lorrain
  2003-12-22 15:22         ` Kai Henningsen
  0 siblings, 1 reply; 18+ messages in thread
From: Etienne Lorrain @ 2003-12-22 14:12 UTC (permalink / raw)
  To: Falk Hueffner; +Cc: gcc

 --- Falk Hueffner wrote:
> You've hit PR inline-asm/8788. As I mentioned there, IMHO we should
> error out on this, but nobody else has commented on it yet...

  But inline-asm/8788 is said to be invalid code.
 Anything can be invalid-ated, but the code:

-------
typedef unsigned farptr;

typedef struct {
    unsigned short	buffersize;
    unsigned short	infobit;
    unsigned		nbcylinder;
    unsigned		nbhead;
    unsigned		nbsectorpertrack;
    unsigned long long	nbtotalsector;
    unsigned short	bytepersector;
    /* V2.0+ : */
    farptr	configptr; /* for instance ebiosPhoenix realmode address */
    /* V3.0+ : */
    unsigned short signature0xBEDD;
    unsigned char  lendevicepath; /* 0x24 for v3.0 */
    unsigned char  reserved[3];
    unsigned char  bustype[4]; /* exactly "ISA" or "PCI" */
    unsigned char  Interface[8]; /* exactly "ATA", "ATAPI", "SCSI",
"USB"...*/
    union interface_path_u {
	struct {
	    unsigned short addr;
	    unsigned char pad[6];
	    } __attribute__ ((packed)) isa;
	struct {
	    unsigned char busnr;
	    unsigned char devicenr;
	    unsigned char functionnr;
	    unsigned char pad[5];
	    } __attribute__ ((packed)) pci;
	} bus;
    union device_path_u {
	struct {
	    unsigned char slave; /* 0 if master, 1 if slave */
	    unsigned char pad[7];
	    unsigned long long	reserved; // Not present in some docs...
	  } __attribute__ ((packed)) ata;
	struct {
	    unsigned char slave; /* 0 if master, 1 if slave */
	    unsigned char logical_unit_nr;
	    unsigned char pad[6];
	    unsigned long long	reserved; // Not present in some docs...
	  } __attribute__ ((packed)) atapi;
	struct {
	    unsigned char logical_unit_nr;
	    unsigned char pad[7];
	    unsigned long long	reserved; // Not present in some docs...
	  } __attribute__ ((packed)) scsi;
	struct {
	    unsigned char tobedefined;
	    unsigned char pad[7];
	    unsigned long long	reserved; // Not present in some docs...
	  } __attribute__ ((packed)) usb;
	struct {
	    unsigned long long FireWireGeneralUniqueID;
	    unsigned long long	reserved; // Not present in some docs...
	  } __attribute__ ((packed)) ieee1394;
	struct {
	    unsigned long long WorldWideNumber;
	    unsigned long long	reserved; // Not present in some docs...
	  } __attribute__ ((packed)) FibreChannel;
      } device;
    unsigned char zero;
    unsigned char bytechecksum; /* byte sum [0x1E..0x49] = 0 */
    } __attribute__ ((packed)) ebiosinfo_t;

unsigned char
_EBIOSDISK_getparam (unsigned char disk, ebiosinfo_t *ebiosinfo,
                     unsigned char *status)
  {
  unsigned char carry;

  asm (
"       int     $0x13           # _EBIOSDISK_getparam   \n"
"       mov     %%ah,%1                                 \n"
"       setc    %0                                      \n"
        : "=qm" (carry), "=qm" (*status), "=S" (*ebiosinfo)
        : "a"((unsigned short)0x4800), "d" (disk)
        );

  return carry;
  }
-------

  This code has a real use in a real (at least for me) application...

$ gcc -O2 t.c
t.c: In function `_EBIOSDISK_getparam':
t.c:72: error: impossible constraint in `asm'

  The change of error is because it is _EBIOSDISK_getparam() so it
 is an output - for _EBIOSDISK_setparam() or equivalent it would
 be an input.
  Using output "=m" (*ebiosinfo) and input "S" (ebiosinfo) is not
 completely equivalent because the output part may generate strange
 code on some compiler version - but that is the best approximation.
 Using "memory" after ": : :" does not have the intended effect if
 the structure is declared locally in the current stack frame (and
 if the _EBIOSDISK_getparam() function is inlined).
  The system saying "if the structure fit in a register, it is
 inside the register - else the register contains its base address"
 seems to be already used in GCC when a real C function returns a
 structure (C extension of GCC).

  Etienne.



_________________________________________________________________
Do You Yahoo!? -- Une adresse @yahoo.fr gratuite et en français !
Yahoo! Mail : http://fr.mail.yahoo.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
  2003-12-22 10:54   ` Etienne Lorrain
@ 2003-12-22 12:03     ` Falk Hueffner
  2003-12-22 14:12       ` Etienne Lorrain
  2003-12-31  1:52     ` Jim Wilson
  1 sibling, 1 reply; 18+ messages in thread
From: Falk Hueffner @ 2003-12-22 12:03 UTC (permalink / raw)
  To: Etienne Lorrain; +Cc: Jim Wilson, gcc

Etienne Lorrain <etienne_lorrain@yahoo.fr> writes:

>   The code is compiling if the structure is small enough to fit in
>  a 32 bits register, not if it has to be in memory - I should have
>  said it. With the compiler I have nearby, this code is only
>  compiling if the line "//    unsigned c, d, e, f;" is commented out:
> 
> ---------------------------
> typedef struct {
>     unsigned char a,b;
> //    unsigned c, d, e, f;
>     } ebiosinfo_t;
> 
> unsigned char
> _EBIOSDISK_getparam (unsigned char disk, ebiosinfo_t *ebiosinfo,
>                      unsigned char *status)
>   {
>   unsigned char carry;
> 
>   asm (
> "       int     $0x13           # _EBIOSDISK_getparam   \n"
> "       mov     %%ah,%1                                 \n"
> "       setc    %0                                      \n"
>         : "=qm" (carry), "=qm" (*status)
>         : "a"((unsigned short)0x4800), "d" (disk), "S" (*ebiosinfo)
>         );

You've hit PR inline-asm/8788. As I mentioned there, IMHO we should
error out on this, but nobody else has commented on it yet...

-- 
	Falk

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
  2003-12-19 21:12 ` Jim Wilson
@ 2003-12-22 10:54   ` Etienne Lorrain
  2003-12-22 12:03     ` Falk Hueffner
  2003-12-31  1:52     ` Jim Wilson
  0 siblings, 2 replies; 18+ messages in thread
From: Etienne Lorrain @ 2003-12-22 10:54 UTC (permalink / raw)
  To: Jim Wilson; +Cc: gcc

 --- Jim Wilson wrote:
> Etienne Lorrain wrote:
> >  You cannot compile the logical (%si containning the address of a
> >  structure to be filled by the disk BIOS service int $0x13):
> 
> I don't understand what the complaint is here.  The example you gave 
> doesn't compile because ebiosinfo_t is undefined.  If I add a simple 
> structure, then it does compiler.  I don't get an error with gcc-3.3 or 
> current mainline.  I don't see anything obviously wrong with the 
> resulting assembly code.

  The code is compiling if the structure is small enough to fit in
 a 32 bits register, not if it has to be in memory - I should have
 said it. With the compiler I have nearby, this code is only
 compiling if the line "//    unsigned c, d, e, f;" is commented out:

---------------------------
typedef struct {
    unsigned char a,b;
//    unsigned c, d, e, f;
    } ebiosinfo_t;

unsigned char
_EBIOSDISK_getparam (unsigned char disk, ebiosinfo_t *ebiosinfo,
                     unsigned char *status)
  {
  unsigned char carry;

  asm (
"       int     $0x13           # _EBIOSDISK_getparam   \n"
"       mov     %%ah,%1                                 \n"
"       setc    %0                                      \n"
        : "=qm" (carry), "=qm" (*status)
        : "a"((unsigned short)0x4800), "d" (disk), "S" (*ebiosinfo)
        );

  return carry;
  }
---------------------------

$ gcc -v
Reading specs from /usr/lib/gcc-lib/i686-pc-cygwin/3.3.1/specs
Configured with: /GCC/gcc-3.3.1-3/configure --with-gcc --with-gnu-ld
--with-gnu-as --prefix=/usr --e
xec-prefix=/usr --sysconfdir=/etc --libdir=/usr/lib --libexecdir=/usr/sbin
--mandir=/usr/share/man -
-infodir=/usr/share/info --enable-languages=c,ada,c++,f77,pascal,java,objc
--enable-libgcj --enable-
threads=posix --with-system-zlib --enable-nls --without-included-gettext
--enable-interpreter --enab
le-sjlj-exceptions --disable-version-specific-runtime-libs --enable-shared
--disable-win32-registry
--enable-java-gc=boehm --disable-hash-synchronization --verbose
--target=i686-pc-cygwin --host=i686-
pc-cygwin --build=i686-pc-cygwin
Thread model: posix
gcc version 3.3.1 (cygming special)

$ gcc -O2 tmp.c
/usr/lib/gcc-lib/i686-pc-cygwin/3.3.1/../../../libcygwin.a(libcmain.o)(.text+0x7c):
undefined refere
nce to `_WinMain@16'
collect2: ld returned 1 exit status

$ vi tmp.c # to uncomment line 3:

$ gcc -O2 tmp.c
tmp.c: In function `_EBIOSDISK_getparam':
tmp.c:12: internal compiler error: in emit_move_insn, at expr.c:3159
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://gcc.gnu.org/bugs.html> for instructions.

  Note that I did not notice the change of message in later versions,
 and cygwin is not my usual reference - but this code does not compile
 since at least gcc-2.95.

  Etienne.

_________________________________________________________________
Do You Yahoo!? -- Une adresse @yahoo.fr gratuite et en français !
Yahoo! Mail : http://fr.mail.yahoo.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
  2003-12-19 13:11 Etienne Lorrain
  2003-12-19 13:14 ` Andrew Haley
@ 2003-12-19 21:12 ` Jim Wilson
  2003-12-22 10:54   ` Etienne Lorrain
  1 sibling, 1 reply; 18+ messages in thread
From: Jim Wilson @ 2003-12-19 21:12 UTC (permalink / raw)
  To: Etienne Lorrain; +Cc: gcc

Etienne Lorrain wrote:
>  Another related question: Is it possible, by inline assembler, to get GCC
>  to save segment registers?

Gcc doesn't know about the segment registers.  Support for them would 
have to be added in: new registers, register classes, constraint 
letters, instructions for saving and restoring them.  That won't happen 
unless someone volunteers a patch.

>  You cannot compile the logical (%si containning the address of a
>  structure to be filled by the disk BIOS service int $0x13):

I don't understand what the complaint is here.  The example you gave 
doesn't compile because ebiosinfo_t is undefined.  If I add a simple 
structure, then it does compiler.  I don't get an error with gcc-3.3 or 
current mainline.  I don't see anything obviously wrong with the 
resulting assembly code.
-- 
Jim Wilson, GNU Tools Support, http://www.SpecifixInc.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
  2003-12-19 13:14 ` Andrew Haley
@ 2003-12-19 16:25   ` Etienne Lorrain
  0 siblings, 0 replies; 18+ messages in thread
From: Etienne Lorrain @ 2003-12-19 16:25 UTC (permalink / raw)
  To: gcc; +Cc: Andrew Haley

 --- Andrew Haley wrote :
> This is really getting to be off-topic for the gcc developer's list.
> 
> Etienne Lorrain writes:
>  >     short ret, tmp;
>  >     asm (
>  > " pushl %es           \n"
>  > " int $0x15           \n"
>  > " movw %es:3(%bp),%ax \n"
>  > " movzbl %ah,%0        \n"
>  > " popl %es            \n"
>  >         : "=g" (ret), "=a" (tmp)
>  >         :
>  >         : "ebp"
>  >         };
>  >     return ret;
>  >     }
>  >   Does not work if "=g" (ret) is a stack reference because the
>  >  stack pointer is modified by push/pop %es - it does work for
>  >  anything else.
> 
> Why not use "=r" (ret)  ?

  It is basically what I do to get a working executable, but when
 looking at the assembler generated on ia32, you can often see the
 price of forcing something in register by the number of instruction
 added (save/restore/reload around your asm()). On ia32 you also have
 the problem of the size of the access, a "=g" would fit
 byte/half word/word but you have to do "=q" for byte registers -
 there is just four of them, just two which shall not be invariant
 through function calls: %ax and %dx...
 This function is inlined so it depends where and how many
 time it is called - I cannot give you a real use case where it
 had matter that much.
  What I can remember is how long it takes to find the bug - previous
 GCC not optimising that much had a free register at that point.

  I can still say that asm("") efficiency does matter sometimes,
 for instance on my graphic library (see gujin on sourceforge),
 I have to use asm("") to access the "gs:" segment to print a pixel,
 to finally print letters and the whole screen at high definition.

 Then you can see in the assembler the price of not using the
 standard access method for variable/pointer but a mere
 " movl %1,%gs:%2 " : : "g" (data) : "g" (address)
 It seem transparent enough but, for instance, will not be optimised
 to movs or stos when some optimisation would have been done on
 usual variable. Or a movzbl or movzwl would have been detected
 by the optimiser. Or the processor flags are destroyed by asm()
 and a test has to be re-done.

 No, no - I am not claiming that you should be able to do:
unsigned short *pixel16bpp attribute ((segment("gs")));
 because I cannot pay anybody to do the patch.
 That would also be usefull for (search "FS base and GS base" in):
http://www.sandpile.org/aa64/msr.htm
 if someone would like to find a "real" application.
 And it would have to be generic across processor:
union {
  unsigned all;
  struct {
    unsigne bitfields:3;
    ...;
    } bits;
  } powerpc_spr_35 attribute ((packed, segment("spr")));
 to use "mfspr"/"mtspr" instead of load/store to access
 the value.
 Shall not do on ia32 neither:
struct uart_t uart attribute ((segment("ioport")));

 I hope I gonna have a nice turkey for Xmas,
 Etienne.


_________________________________________________________________
Do You Yahoo!? -- Une adresse @yahoo.fr gratuite et en français !
Yahoo! Mail : http://fr.mail.yahoo.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
  2003-12-19 13:11 Etienne Lorrain
@ 2003-12-19 13:14 ` Andrew Haley
  2003-12-19 16:25   ` Etienne Lorrain
  2003-12-19 21:12 ` Jim Wilson
  1 sibling, 1 reply; 18+ messages in thread
From: Andrew Haley @ 2003-12-19 13:14 UTC (permalink / raw)
  To: Etienne Lorrain; +Cc: gcc

This is really getting to be off-topic for the gcc developer's list.

Etienne Lorrain writes:
 >     short ret, tmp;
 >     asm (
 > " pushl %es           \n"
 > " int $0x15           \n"
 > " movw %es:3(%bp),%ax \n"
 > " movzbl %ah,%0        \n"
 > " popl %es            \n"
 >         : "=g" (ret), "=a" (tmp)
 >         :
 >         : "ebp"
 >         };
 >     return ret;
 >     }
 >   Does not work if "=g" (ret) is a stack reference because the
 >  stack pointer is modified by push/pop %es - it does work for
 >  anything else.

Why not use "=r" (ret)  ?

Andrew.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: Calling convention that gets frame pointer register clobbered
@ 2003-12-19 13:11 Etienne Lorrain
  2003-12-19 13:14 ` Andrew Haley
  2003-12-19 21:12 ` Jim Wilson
  0 siblings, 2 replies; 18+ messages in thread
From: Etienne Lorrain @ 2003-12-19 13:11 UTC (permalink / raw)
  To: gcc

> : Does gcc support calling conventions that get the frame pointer register
> : clobbered?
>
> A related question:  Is it possible, by inline assembler, to get GCC
> to save the frame pointer? I've tried to adding "ebp" to the clobbered
> list, with no effect.  It is of course possible to add push/pop insns
> to the asm string, but that seems a bit risky, and does not look very
> pretty.

 Another related question: Is it possible, by inline assembler, to get GCC
 to save segment registers?
 Not to manage them, just push before, pop after (but manage the stack
 offset induced by push/pop).

 - Real code use: interface with BIOS (who uses %es:%bp pointers and more)

 - Why cannot easily do it by hand:
inline short fct (short param) {
    short ret, tmp;
    asm (
" pushl %es           \n"
" int $0x15           \n"
" movw %es:3(%bp),%ax \n"
" movzbl %ah,%0        \n"
" popl %es            \n"
        : "=g" (ret), "=a" (tmp)
        :
        : "ebp"
        };
    return ret;
    }
  Does not work if "=g" (ret) is a stack reference because the
 stack pointer is modified by push/pop %es - it does work for
 anything else. This would always work:
inline short fct (short param) {
    short ret, tmp;
    asm (
" int $0x15           \n"
" movw %es:3(%bp),%ax \n"
" movzbl %ah,%0        \n"
        : "=g" (ret), "=a" (tmp)
        :
        : "ebp", "es"
        };
    return ret;
    }

  Note also, while talking about asm()s, there seem to be a small
 problem on asm's input/output of structures with their base address
 in registers instead of memory:

 You cannot compile the logical (%si containning the address of a
 structure to be filled by the disk BIOS service int $0x13):

extern inline unsigned char
_EBIOSDISK_getparam (unsigned char disk, ebiosinfo_t *ebiosinfo,
		     unsigned char *status)
  {
  unsigned char carry;

  asm (
"	int	$0x13		# _EBIOSDISK_getparam	\n"
"	mov	%%ah,%1					\n"
"	setc	%0					\n"
	: "=qm" (carry), "=qm" (*status)
	: "a"((unsigned short)0x4800), "d" (disk), "S" (*ebiosinfo)
	);

  return carry;
  }

  You have to do (the "=m" may generate stange assembly):

extern inline unsigned char
_EBIOSDISK_getparam (unsigned char disk, ebiosinfo_t *ebiosinfo,
		     unsigned char *status)
  {
  unsigned char carry;

  asm (
"	int	$0x13		# _EBIOSDISK_getparam	\n"
"	mov	%%ah,%1					\n"
"	setc	%0					\n"
	: "=qm" (carry), "=qm" (*status), "=m" (*ebiosinfo)
	: "a"((unsigned short)0x4800), "d" (disk), "S" (ebiosinfo)
	);

  return carry;
  }

  The "=m" (*ebiosinfo) is needed to explain that it will modify
 the content of the structure (which may be in the stack so
 asm ("" : : : "memory") would not work).
 I may be totally wrong but if the error message is removed, the
 first asm() will/should behave as for function returning big structure
 in GCC.

  Happy Xmas anyways,
  Etienne.

_________________________________________________________________
Do You Yahoo!? -- Une adresse @yahoo.fr gratuite et en français !
Yahoo! Mail : http://fr.mail.yahoo.com

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2004-01-05 20:44 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-12-15 19:20 Calling convention that gets frame pointer register clobbered Latchesar Ionkov
2003-12-16  2:28 ` Jim Wilson
     [not found]   ` <20031216020218.GA26565@ionkov.net>
2003-12-16  4:49     ` Jim Wilson
     [not found]       ` <20031216032439.GA26833@ionkov.net>
     [not found]         ` <1071552791.1019.84.camel@leaf.tuliptree.org>
2003-12-17 22:42           ` Latchesar Ionkov
2003-12-16 17:48 ` Johan Rydberg
2003-12-17 10:39   ` Jim Wilson
2003-12-19 13:11 Etienne Lorrain
2003-12-19 13:14 ` Andrew Haley
2003-12-19 16:25   ` Etienne Lorrain
2003-12-19 21:12 ` Jim Wilson
2003-12-22 10:54   ` Etienne Lorrain
2003-12-22 12:03     ` Falk Hueffner
2003-12-22 14:12       ` Etienne Lorrain
2003-12-22 15:22         ` Kai Henningsen
2003-12-22 16:59           ` Etienne Lorrain
2003-12-31  1:52     ` Jim Wilson
2004-01-05 13:34       ` Etienne Lorrain
2004-01-05 20:44         ` Jim Wilson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).