[PATCH] Force the argument buffer for mmap syscall to be initialized

Jie Zhang jzhang918 at gmail.com
Mon Jun 5 08:14:26 UTC 2006


On 6/5/06, Peter Kjellerstedt <peter.kjellerstedt at axis.com> wrote:
> > -----Original Message-----
> > From: uclibc-bounces at uclibc.org
> > [mailto:uclibc-bounces at uclibc.org] On Behalf Of Jie Zhang
> > Sent: den 5 juni 2006 06:27
> > To: uClibc
> > Subject: [PATCH] Force the argument buffer for mmap syscall
> > to be initialized
> >
> > Some archs still use old mmap syscall, like this:
> >
> > static inline _syscall1(__ptr_t, _mmap, unsigned long *, buffer);
> > __ptr_t mmap(__ptr_t addr, size_t len, int prot,
> >              int flags, int fd, __off_t offset)
> > {
> >     unsigned long buffer[6];
> >
> >     buffer[0] = (unsigned long) addr;
> >     buffer[1] = (unsigned long) len;
> >     buffer[2] = (unsigned long) prot;
> >     buffer[3] = (unsigned long) flags;
> >     buffer[4] = (unsigned long) fd;
> >     buffer[5] = (unsigned long) offset;
> >     return (__ptr_t) _mmap(buffer);
> > }
> >
> > GCC 4.1 will optimize away all the statements which initialize the
> > arguments buffer. this patch should fix it. It also fixes the same
> > issue in ldso code.
> >
> > Is it OK? If yes, please help install it. Thanks.
> >
> > Jie
>
> What gives GCC 4.1 the right to optimize away the assignments?
> Is this a bug in GCC 4.1, or is there some reason to break prefectly
> valid code?
>
This piece of code is valid in the sense that it conforms to the C
standard, but invalid in the sense that it does not do things as
expected. After preprocessed, it looks like (I use the piece of code
from ldso instead of the above one, since both are same except some
names and I have it on hand):

static inline void *
_dl_mmap_real (unsigned long *buffer)
{
  long __res;
  __asm__ __volatile__ ("r0=%2;\n\t" "p0=%1;\n\t" "excpt 0;\n\t"
			"%0=r0;\n\t":"=da" (__res):"i" (90),
			"a" ((long) (buffer)):"CC", "R0", "P0");
  do
    {
      unsigned long __sr2 = (__res);
      if (__builtin_expect
	  ((unsigned long) (__sr2) >= (unsigned long) (-4095), 0))
	{
	  {
	    (_dl_errno) = (-__sr2);
	  };
	  __sr2 = -1;
	}
      return (void *) (__sr2);
    }
  while (0);
};

static inline void *
_dl_mmap (void *addr, unsigned long size, int prot,
	  int flags, int fd, unsigned long offset)
{
  unsigned long buffer[6];

  buffer[0] = (unsigned long) addr;
  buffer[1] = (unsigned long) size;
  buffer[2] = (unsigned long) prot;
  buffer[3] = (unsigned long) flags;
  buffer[4] = (unsigned long) fd;
  buffer[5] = (unsigned long) offset;
  return (void *) _dl_mmap_real (buffer);
}

After inlining, it looks like (have removed unrelative code to make it
more clear):

static inline void *
_dl_mmap (void *addr, unsigned long size, int prot,
	  int flags, int fd, unsigned long offset)
{
  unsigned long buffer[6];
  long __res;

  buffer[0] = (unsigned long) addr;
  buffer[1] = (unsigned long) size;
  buffer[2] = (unsigned long) prot;
  buffer[3] = (unsigned long) flags;
  buffer[4] = (unsigned long) fd;
  buffer[5] = (unsigned long) offset;

  __asm__ __volatile__ ("r0=%2;\n\t" "p0=%1;\n\t" "excpt 0;\n\t"
			"%0=r0;\n\t":"=da" (__res):"i" (90),
			"a" ((long) (buffer)):"CC", "R0", "P0");

  /* error checking code omitted.  */

  return (void *) __res;
}

Now it's very clear that the contents in buffer[] are not used in
inline assembly. So GCC can optimized the assignment away!

We have to tell gcc that the whole buffer[] is used in inline assembly
by adding an input operand with proper constraints. But we cannot add
it in the definition of _syscall1, since it's used by other code. So I
choose to add it as in my patch.

Jie



More information about the uClibc mailing list