diff mbox series

Add SYSCALL_LONG/SYSCALL_ULONG to pass long to syscall [BZ #25810]

Message ID 20200410212249.3529885-1-hjl.tools@gmail.com
State New
Headers show
Series Add SYSCALL_LONG/SYSCALL_ULONG to pass long to syscall [BZ #25810] | expand

Commit Message

H.J. Lu April 10, 2020, 9:22 p.m. UTC
X32 has 32-bit long and pointer with 64-bit off_t.  Since x32 psABI
requires that pointers passed in registers must be zero-extended to
64bit, x32 can share many syscall interfaces with LP64.  When a LP64
syscall with long and unsigned long arguments is used for x32, these
arguments must be properly extended to 64-bit.  Otherwise if the upper
32 bits of the register have undefined value, such a syscall will be
rejected by kernel.

For inline syscalls, SYSCALL_LONG and SYSCALL_ULONG are introduced as
wrappers for long and unsigned long arguments.

For syscalls implemented in assembly codes, 'U' is added to syscall
signature key letters for unsigned long.  SYSCALL_ULONG_ARG_1 and
SYSCALL_ULONG_ARG_2 are passed to syscall-template.S for the first
and the second unsigned long arguments.  They are used by x32 to
zero-extend 32-bit arguments to 64 bits.

Tested on i386, x86-64 and 32 as well as with build-many-glibcs.py.
---
 misc/Makefile                                 |   2 +-
 misc/tst-syscalls.c                           | 146 ++++++++++++++++++
 sysdeps/unix/make-syscalls.sh                 |  88 +++++++++++
 sysdeps/unix/syscall-template.S               |  37 ++++-
 sysdeps/unix/sysv/linux/copy_file_range.c     |   2 +-
 sysdeps/unix/sysv/linux/getcwd.c              |   2 +-
 sysdeps/unix/sysv/linux/getdents.c            |   3 +-
 sysdeps/unix/sysv/linux/getdents64.c          |   6 +-
 sysdeps/unix/sysv/linux/getentropy.c          |   4 +-
 sysdeps/unix/sysv/linux/getrandom.c           |   3 +-
 sysdeps/unix/sysv/linux/mlock2.c              |   8 +-
 sysdeps/unix/sysv/linux/mmap64.c              |   7 +-
 sysdeps/unix/sysv/linux/mq_timedreceive.c     |  12 +-
 sysdeps/unix/sysv/linux/mq_timedsend.c        |  14 +-
 sysdeps/unix/sysv/linux/msgrcv.c              |   7 +-
 sysdeps/unix/sysv/linux/msgsnd.c              |   7 +-
 sysdeps/unix/sysv/linux/msync.c               |   2 +-
 sysdeps/unix/sysv/linux/pkey_mprotect.c       |   3 +-
 sysdeps/unix/sysv/linux/pread.c               |   3 +-
 sysdeps/unix/sysv/linux/pread64.c             |   3 +-
 sysdeps/unix/sysv/linux/pread64_nocancel.c    |   3 +-
 sysdeps/unix/sysv/linux/pwrite.c              |   3 +-
 sysdeps/unix/sysv/linux/pwrite64.c            |   3 +-
 sysdeps/unix/sysv/linux/read.c                |   2 +-
 sysdeps/unix/sysv/linux/read_nocancel.c       |   2 +-
 sysdeps/unix/sysv/linux/readahead.c           |   2 +-
 sysdeps/unix/sysv/linux/recv.c                |   7 +-
 sysdeps/unix/sysv/linux/recvfrom.c            |   8 +-
 sysdeps/unix/sysv/linux/sched_setaffinity.c   |   3 +-
 sysdeps/unix/sysv/linux/semtimedop.c          |   6 +-
 sysdeps/unix/sysv/linux/send.c                |   7 +-
 sysdeps/unix/sysv/linux/sendto.c              |   8 +-
 sysdeps/unix/sysv/linux/shmget.c              |   6 +-
 sysdeps/unix/sysv/linux/splice.c              |   3 +-
 sysdeps/unix/sysv/linux/sysdep.h              |   5 +
 sysdeps/unix/sysv/linux/tee.c                 |   2 +-
 sysdeps/unix/sysv/linux/vmsplice.c            |   2 +-
 sysdeps/unix/sysv/linux/write.c               |   2 +-
 sysdeps/unix/sysv/linux/write_nocancel.c      |   2 +-
 sysdeps/unix/sysv/linux/x86_64/sysdep.h       |  57 +++++--
 .../unix/sysv/linux/x86_64/x32/syscalls.list  |  10 ++
 sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h   |  30 ++++
 42 files changed, 450 insertions(+), 82 deletions(-)
 create mode 100644 misc/tst-syscalls.c

Comments

Florian Weimer April 11, 2020, 10:01 a.m. UTC | #1
* H. J. Lu via Libc-alpha:

> For inline syscalls, SYSCALL_LONG and SYSCALL_ULONG are introduced as
> wrappers for long and unsigned long arguments.

Do the arguments have the correct types?  Then I think you can do the
adjustment in the guts of INLINE_SYSCALL machinery, and we do not have
to remember to annotate each and every call site with the new macros.

Changes to sysdeps/unix/make-syscalls.sh and syscalls.list appear
unavoidable, but I think tget should be made to the global Linux
version, not the x32 variant, so that other targets with the same
issue can benefit from them.  (I have not reviewed the
make-syscalls.sh changes.)

The core problem is that the psABI has a different calling convention
than the syscall interface, right?  This looks like a cautionary tale
that one should not do this.
H.J. Lu April 11, 2020, 1:26 p.m. UTC | #2
On Sat, Apr 11, 2020 at 3:01 AM Florian Weimer <fw@deneb.enyo.de> wrote:
>
> * H. J. Lu via Libc-alpha:
>
> > For inline syscalls, SYSCALL_LONG and SYSCALL_ULONG are introduced as
> > wrappers for long and unsigned long arguments.
>
> Do the arguments have the correct types?  Then I think you can do the

Yes, they have correct types.  But it is not the problem.  Take this example:

int munmap(void *addr, size_t length);

The type of length is unsigned int (size_t) for x32 and is unsigned long
(64bit) in kernel.  We have no way to know the type which kernel expects.

> adjustment in the guts of INLINE_SYSCALL machinery, and we do not have
> to remember to annotate each and every call site with the new macros.
>
> Changes to sysdeps/unix/make-syscalls.sh and syscalls.list appear
> unavoidable, but I think tget should be made to the global Linux
> version, not the x32 variant, so that other targets with the same

Will do.

> issue can benefit from them.  (I have not reviewed the
> make-syscalls.sh changes.)
>
> The core problem is that the psABI has a different calling convention
> than the syscall interface, right?  This looks like a cautionary tale
> that one should not do this.

Something to consider for the new kernel interface.
Florian Weimer April 11, 2020, 2:45 p.m. UTC | #3
* H. J. Lu:

> On Sat, Apr 11, 2020 at 3:01 AM Florian Weimer <fw@deneb.enyo.de> wrote:
>>
>> * H. J. Lu via Libc-alpha:
>>
>> > For inline syscalls, SYSCALL_LONG and SYSCALL_ULONG are introduced as
>> > wrappers for long and unsigned long arguments.
>>
>> Do the arguments have the correct types?  Then I think you can do the
>
> Yes, they have correct types.  But it is not the problem.  Take this example:
>
> int munmap(void *addr, size_t length);
>
> The type of length is unsigned int (size_t) for x32 and is unsigned long
> (64bit) in kernel.  We have no way to know the type which kernel expects.

Is it possible to extend all 32-bit arguments?  Ot is this incorrect
for negative int arguments, which must not have their upper bits set?
H.J. Lu April 11, 2020, 3:04 p.m. UTC | #4
On Sat, Apr 11, 2020 at 7:45 AM Florian Weimer <fw@deneb.enyo.de> wrote:
>
> * H. J. Lu:
>
> > On Sat, Apr 11, 2020 at 3:01 AM Florian Weimer <fw@deneb.enyo.de> wrote:
> >>
> >> * H. J. Lu via Libc-alpha:
> >>
> >> > For inline syscalls, SYSCALL_LONG and SYSCALL_ULONG are introduced as
> >> > wrappers for long and unsigned long arguments.
> >>
> >> Do the arguments have the correct types?  Then I think you can do the
> >
> > Yes, they have correct types.  But it is not the problem.  Take this example:
> >
> > int munmap(void *addr, size_t length);
> >
> > The type of length is unsigned int (size_t) for x32 and is unsigned long
> > (64bit) in kernel.  We have no way to know the type which kernel expects.
>
> Is it possible to extend all 32-bit arguments?  Ot is this incorrect
> for negative int arguments, which must not have their upper bits set?

      ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
                      int msgflg);

      * If msgtyp is 0, then the first message in the queue is read.

       * If  msgtyp  is greater than 0, then the first message in the queue of
         type msgtyp is read, unless MSG_EXCEPT was specified  in  msgflg,  in
         which case the first message in the queue of type not equal to msgtyp
         will be read.

       * If msgtyp is less than 0, then the first message in  the  queue  with
         the  lowest  type  less than or equal to the absolute value of msgtyp
         will be read.

In this syscall, msgtyp should be sign-extended to 64-bit.


H.J.
Florian Weimer April 11, 2020, 3:10 p.m. UTC | #5
* H. J. Lu:

> On Sat, Apr 11, 2020 at 7:45 AM Florian Weimer <fw@deneb.enyo.de> wrote:
>>
>> * H. J. Lu:
>>
>> > On Sat, Apr 11, 2020 at 3:01 AM Florian Weimer <fw@deneb.enyo.de> wrote:
>> >>
>> >> * H. J. Lu via Libc-alpha:
>> >>
>> >> > For inline syscalls, SYSCALL_LONG and SYSCALL_ULONG are introduced as
>> >> > wrappers for long and unsigned long arguments.
>> >>
>> >> Do the arguments have the correct types?  Then I think you can do the
>> >
>> > Yes, they have correct types.  But it is not the problem.  Take this example:
>> >
>> > int munmap(void *addr, size_t length);
>> >
>> > The type of length is unsigned int (size_t) for x32 and is unsigned long
>> > (64bit) in kernel.  We have no way to know the type which kernel expects.
>>
>> Is it possible to extend all 32-bit arguments?  Ot is this incorrect
>> for negative int arguments, which must not have their upper bits set?
>
>       ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
>                       int msgflg);
>
>       * If msgtyp is 0, then the first message in the queue is read.
>
>        * If  msgtyp  is greater than 0, then the first message in the queue of
>          type msgtyp is read, unless MSG_EXCEPT was specified  in  msgflg,  in
>          which case the first message in the queue of type not equal to msgtyp
>          will be read.
>
>        * If msgtyp is less than 0, then the first message in  the  queue  with
>          the  lowest  type  less than or equal to the absolute value of msgtyp
>          will be read.
>
> In this syscall, msgtyp should be sign-extended to 64-bit.

As far as I can tell, this is not a problematic exception.
H.J. Lu April 11, 2020, 3:23 p.m. UTC | #6
On Sat, Apr 11, 2020 at 8:10 AM Florian Weimer <fw@deneb.enyo.de> wrote:
>
> * H. J. Lu:
>
> > On Sat, Apr 11, 2020 at 7:45 AM Florian Weimer <fw@deneb.enyo.de> wrote:
> >>
> >> * H. J. Lu:
> >>
> >> > On Sat, Apr 11, 2020 at 3:01 AM Florian Weimer <fw@deneb.enyo.de> wrote:
> >> >>
> >> >> * H. J. Lu via Libc-alpha:
> >> >>
> >> >> > For inline syscalls, SYSCALL_LONG and SYSCALL_ULONG are introduced as
> >> >> > wrappers for long and unsigned long arguments.
> >> >>
> >> >> Do the arguments have the correct types?  Then I think you can do the
> >> >
> >> > Yes, they have correct types.  But it is not the problem.  Take this example:
> >> >
> >> > int munmap(void *addr, size_t length);
> >> >
> >> > The type of length is unsigned int (size_t) for x32 and is unsigned long
> >> > (64bit) in kernel.  We have no way to know the type which kernel expects.
> >>
> >> Is it possible to extend all 32-bit arguments?  Ot is this incorrect
> >> for negative int arguments, which must not have their upper bits set?
> >
> >       ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
> >                       int msgflg);
> >
> >       * If msgtyp is 0, then the first message in the queue is read.
> >
> >        * If  msgtyp  is greater than 0, then the first message in the queue of
> >          type msgtyp is read, unless MSG_EXCEPT was specified  in  msgflg,  in
> >          which case the first message in the queue of type not equal to msgtyp
> >          will be read.
> >
> >        * If msgtyp is less than 0, then the first message in  the  queue  with
> >          the  lowest  type  less than or equal to the absolute value of msgtyp
> >          will be read.
> >
> > In this syscall, msgtyp should be sign-extended to 64-bit.
>
> As far as I can tell, this is not a problematic exception.

There is no need to extend int nor unsigned int passed to kernel.
Only long and unsigned long are the problem.
Florian Weimer April 11, 2020, 3:31 p.m. UTC | #7
* H. J. Lu:

> On Sat, Apr 11, 2020 at 8:10 AM Florian Weimer <fw@deneb.enyo.de> wrote:
>>
>> * H. J. Lu:
>>
>> > On Sat, Apr 11, 2020 at 7:45 AM Florian Weimer <fw@deneb.enyo.de> wrote:
>> >>
>> >> * H. J. Lu:
>> >>
>> >> > On Sat, Apr 11, 2020 at 3:01 AM Florian Weimer <fw@deneb.enyo.de> wrote:
>> >> >>
>> >> >> * H. J. Lu via Libc-alpha:
>> >> >>
>> >> >> > For inline syscalls, SYSCALL_LONG and SYSCALL_ULONG are introduced as
>> >> >> > wrappers for long and unsigned long arguments.
>> >> >>
>> >> >> Do the arguments have the correct types?  Then I think you can do the
>> >> >
>> >> > Yes, they have correct types.  But it is not the problem.  Take this example:
>> >> >
>> >> > int munmap(void *addr, size_t length);
>> >> >
>> >> > The type of length is unsigned int (size_t) for x32 and is unsigned long
>> >> > (64bit) in kernel.  We have no way to know the type which kernel expects.
>> >>
>> >> Is it possible to extend all 32-bit arguments?  Ot is this incorrect
>> >> for negative int arguments, which must not have their upper bits set?
>> >
>> >       ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
>> >                       int msgflg);
>> >
>> >       * If msgtyp is 0, then the first message in the queue is read.
>> >
>> >        * If  msgtyp  is greater than 0, then the first message in the queue of
>> >          type msgtyp is read, unless MSG_EXCEPT was specified  in  msgflg,  in
>> >          which case the first message in the queue of type not equal to msgtyp
>> >          will be read.
>> >
>> >        * If msgtyp is less than 0, then the first message in  the  queue  with
>> >          the  lowest  type  less than or equal to the absolute value of msgtyp
>> >          will be read.
>> >
>> > In this syscall, msgtyp should be sign-extended to 64-bit.
>>
>> As far as I can tell, this is not a problematic exception.
>
> There is no need to extend int nor unsigned int passed to kernel.
> Only long and unsigned long are the problem.

But is there harm in sign-extending int?

I'm not convinced to annotate INLINE_SYSCALLs in this way just to
avoid argument extensions for a subset of the x32 system calls.
H.J. Lu April 11, 2020, 8:25 p.m. UTC | #8
On Sat, Apr 11, 2020 at 8:31 AM Florian Weimer <fw@deneb.enyo.de> wrote:
>
> * H. J. Lu:
>
> > On Sat, Apr 11, 2020 at 8:10 AM Florian Weimer <fw@deneb.enyo.de> wrote:
> >>
> >> * H. J. Lu:
> >>
> >> > On Sat, Apr 11, 2020 at 7:45 AM Florian Weimer <fw@deneb.enyo.de> wrote:
> >> >>
> >> >> * H. J. Lu:
> >> >>
> >> >> > On Sat, Apr 11, 2020 at 3:01 AM Florian Weimer <fw@deneb.enyo.de> wrote:
> >> >> >>
> >> >> >> * H. J. Lu via Libc-alpha:
> >> >> >>
> >> >> >> > For inline syscalls, SYSCALL_LONG and SYSCALL_ULONG are introduced as
> >> >> >> > wrappers for long and unsigned long arguments.
> >> >> >>
> >> >> >> Do the arguments have the correct types?  Then I think you can do the
> >> >> >
> >> >> > Yes, they have correct types.  But it is not the problem.  Take this example:
> >> >> >
> >> >> > int munmap(void *addr, size_t length);
> >> >> >
> >> >> > The type of length is unsigned int (size_t) for x32 and is unsigned long
> >> >> > (64bit) in kernel.  We have no way to know the type which kernel expects.
> >> >>
> >> >> Is it possible to extend all 32-bit arguments?  Ot is this incorrect
> >> >> for negative int arguments, which must not have their upper bits set?
> >> >
> >> >       ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
> >> >                       int msgflg);
> >> >
> >> >       * If msgtyp is 0, then the first message in the queue is read.
> >> >
> >> >        * If  msgtyp  is greater than 0, then the first message in the queue of
> >> >          type msgtyp is read, unless MSG_EXCEPT was specified  in  msgflg,  in
> >> >          which case the first message in the queue of type not equal to msgtyp
> >> >          will be read.
> >> >
> >> >        * If msgtyp is less than 0, then the first message in  the  queue  with
> >> >          the  lowest  type  less than or equal to the absolute value of msgtyp
> >> >          will be read.
> >> >
> >> > In this syscall, msgtyp should be sign-extended to 64-bit.
> >>
> >> As far as I can tell, this is not a problematic exception.
> >
> > There is no need to extend int nor unsigned int passed to kernel.
> > Only long and unsigned long are the problem.
>
> But is there harm in sign-extending int?
>
> I'm not convinced to annotate INLINE_SYSCALLs in this way just to
> avoid argument extensions for a subset of the x32 system calls.

What x32 needs are

1. Pointer arguments: no cast.
2. 64-bit integer arguments:  no cast.
3. 32-bit integer arguments: extend to 64 bits.

I am having a very hard time to do it  in INLINE_SYSCALLs.   If
SYSCALL_LONG and SYSCALL_ULONG isn't an option, I can
duplicate the whole set of these functions and convert them in
x32 directory.
Florian Weimer April 11, 2020, 8:47 p.m. UTC | #9
* H. J. Lu:

> What x32 needs are
>
> 1. Pointer arguments: no cast.
> 2. 64-bit integer arguments:  no cast.
> 3. 32-bit integer arguments: extend to 64 bits.
>
> I am having a very hard time to do it  in INLINE_SYSCALLs.

Is the problem avoiding sign extension on pointer values?

I'm not sure if that is actually necessary to distinguish pointers and
integer.  It should be possible to lump pointers together with
unsigned 32-bit arguments, like this:

#define ARGIFY(X) \
  (((__typeof__ (X)) 0 < (__typeof__ (X)) -1 &&  sizeof (X) == 4)
   ? (long long int) (uintptr_t) (X) \
   : (long long int) (X))

The first branch is used for pointers and unsigned int values,
resulting in zero extension.  The other branch uses zero or sign
extension, depending on the type of X.
H.J. Lu April 11, 2020, 9:58 p.m. UTC | #10
On Sat, Apr 11, 2020 at 1:47 PM Florian Weimer <fw@deneb.enyo.de> wrote:
>
> * H. J. Lu:
>
> > What x32 needs are
> >
> > 1. Pointer arguments: no cast.
> > 2. 64-bit integer arguments:  no cast.
> > 3. 32-bit integer arguments: extend to 64 bits.
> >
> > I am having a very hard time to do it  in INLINE_SYSCALLs.
>
> Is the problem avoiding sign extension on pointer values?
>
> I'm not sure if that is actually necessary to distinguish pointers and
> integer.  It should be possible to lump pointers together with
> unsigned 32-bit arguments, like this:
>
> #define ARGIFY(X) \
>   (((__typeof__ (X)) 0 < (__typeof__ (X)) -1 &&  sizeof (X) == 4)
>    ? (long long int) (uintptr_t) (X) \
>    : (long long int) (X))
>
> The first branch is used for pointers and unsigned int values,
> resulting in zero extension.  The other branch uses zero or sign
> extension, depending on the type of X.

I tried variants of this.  I got


/usr/gcc-9.3.1-x32/bin/gcc -mx32 ../sysdeps/unix/sysv/linux/fexecve.c
-c -std=gnu11 -fgnu89-inline  -O2 -g -Wall -Wwrite-strings -Wundef
-Werror -fmerge-all-constants -frounding-math -fno-stack-protector
-Wstrict-prototypes -Wold-style-definition -fmath-errno
-ftls-model=initial-exec      -I../include
-I/export/build/gnu/tools-build/glibc-x32-gitlab/build-x86_64-linux/posix
 -I/export/build/gnu/tools-build/glibc-x32-gitlab/build-x86_64-linux
-I../sysdeps/unix/sysv/linux/x86_64/x32
-I../sysdeps/unix/sysv/linux/x86_64
-I../sysdeps/unix/sysv/linux/x86/include
-I../sysdeps/unix/sysv/linux/x86  -I../sysdeps/x86/nptl
-I../sysdeps/unix/sysv/linux/wordsize-64  -I../sysdeps/x86_64/nptl
-I../sysdeps/unix/sysv/linux/include -I../sysdeps/unix/sysv/linux
-I../sysdeps/nptl  -I../sysdeps/pthread  -I../sysdeps/gnu
-I../sysdeps/unix/inet  -I../sysdeps/unix/sysv
-I../sysdeps/unix/x86_64  -I../sysdeps/unix  -I../sysdeps/posix
-I../sysdeps/x86_64/x32/fpu  -I../sysdeps/x86_64/x32
-I../sysdeps/x86_64/fpu/multiarch  -I../sysdeps/x86_64/fpu
-I../sysdeps/x86/fpu  -I../sysdeps/x86_64/multiarch
-I../sysdeps/x86_64  -I../sysdeps/x86  -I../sysdeps/ieee754/float128
-I../sysdeps/ieee754/ldbl-96/include -I../sysdeps/ieee754/ldbl-96
-I../sysdeps/ieee754/dbl-64/wordsize-64  -I../sysdeps/ieee754/dbl-64
-I../sysdeps/ieee754/flt-32  -I../sysdeps/wordsize-32
-I../sysdeps/ieee754  -I../sysdeps/generic  -I.. -I../libio -I.
-D_LIBC_REENTRANT -include
/export/build/gnu/tools-build/glibc-x32-gitlab/build-x86_64-linux/libc-modules.h
-DMODULE_NAME=libc -include ../include/libc-symbols.h
-DTOP_NAMESPACE=glibc -o
/export/build/gnu/tools-build/glibc-x32-gitlab/build-x86_64-linux/posix/fexecve.o
-MD -MP -MF /export/build/gnu/tools-build/glibc-x32-gitlab/build-x86_64-linux/posix/fexecve.o.dt
-MT /export/build/gnu/tools-build/glibc-x32-gitlab/build-x86_64-linux/posix/fexecve.o

nohup: ignoring input and appending output to 'nohup.out'
gnu-tools-1:pts/5[130]> m nohup.out
In file included from ../sysdeps/x86_64/nptl/tls.h:28,
                 from ../include/errno.h:25,
                 from ../sysdeps/unix/sysv/linux/fexecve.c:18:
../sysdeps/unix/sysv/linux/fexecve.c: In function ‘fexecve’:
../sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h:56:6: error: cast from pointer to
 integer of different size [-Werror=pointer-to-int-cast]
   56 |    : (long long int) (X))
      |      ^
../sysdeps/unix/sysv/linux/x86_64/sysdep.h:313:29: note: in expansion of macro ‘
ARGIFY’
  313 |     TYPEFY (arg4, __arg4) = ARGIFY (arg4);     \
      |                             ^~~~~~
../sysdeps/unix/sysv/linux/x86_64/sysdep.h:222:2: note: in expansion of macro ‘i
nternal_syscall5’
  222 |  internal_syscall##nr (SYS_ify (name), args)
      |  ^~~~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/sysdep.h:43:23: note: in expansion of macro ‘INTERNAL
_SYSCALL’
   43 |     long int sc_ret = INTERNAL_SYSCALL (name, nr, args);  \
      |                       ^~~~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/fexecve.c:43:3: note: in expansion of macro ‘INLINE_S
YSCALL’
   43 |   INLINE_SYSCALL (execveat, 5, fd, "", &argv[0], &envp[0], AT_EMPTY_PATH
gnu-tools-1:pts/5[131]> cat nohup.out
In file included from ../sysdeps/x86_64/nptl/tls.h:28,
                 from ../include/errno.h:25,
                 from ../sysdeps/unix/sysv/linux/fexecve.c:18:
../sysdeps/unix/sysv/linux/fexecve.c: In function ‘fexecve’:
../sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h:56:6: error: cast from
pointer to integer of different size [-Werror=pointer-to-int-cast]
   56 |    : (long long int) (X))
      |      ^
../sysdeps/unix/sysv/linux/x86_64/sysdep.h:313:29: note: in expansion
of macro ‘ARGIFY’
  313 |     TYPEFY (arg4, __arg4) = ARGIFY (arg4);     \
      |                             ^~~~~~
../sysdeps/unix/sysv/linux/x86_64/sysdep.h:222:2: note: in expansion
of macro ‘internal_syscall5’
  222 |  internal_syscall##nr (SYS_ify (name), args)
      |  ^~~~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/sysdep.h:43:23: note: in expansion of macro
‘INTERNAL_SYSCALL’
   43 |     long int sc_ret = INTERNAL_SYSCALL (name, nr, args);  \
      |                       ^~~~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/fexecve.c:43:3: note: in expansion of macro
‘INLINE_SYSCALL’
   43 |   INLINE_SYSCALL (execveat, 5, fd, "", &argv[0], &envp[0],
AT_EMPTY_PATH);
      |   ^~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h:56:6: error: cast from
pointer to integer of different size [-Werror=pointer-to-int-cast]
   56 |    : (long long int) (X))
      |      ^
../sysdeps/unix/sysv/linux/x86_64/sysdep.h:314:29: note: in expansion
of macro ‘ARGIFY’
  314 |     TYPEFY (arg3, __arg3) = ARGIFY (arg3);     \
      |                             ^~~~~~
../sysdeps/unix/sysv/linux/x86_64/sysdep.h:222:2: note: in expansion
of macro ‘internal_syscall5’
  222 |  internal_syscall##nr (SYS_ify (name), args)
      |  ^~~~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/sysdep.h:43:23: note: in expansion of macro
‘INTERNAL_SYSCALL’
   43 |     long int sc_ret = INTERNAL_SYSCALL (name, nr, args);  \
      |                       ^~~~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/fexecve.c:43:3: note: in expansion of macro
‘INLINE_SYSCALL’
   43 |   INLINE_SYSCALL (execveat, 5, fd, "", &argv[0], &envp[0],
AT_EMPTY_PATH);
      |   ^~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h:54:5: error: cast
specifies array type
   54 |   (((__typeof__ (X)) 0 < (__typeof__ (X)) -1 &&  sizeof (X) == 4) \
      |     ^
../sysdeps/unix/sysv/linux/x86_64/sysdep.h:315:29: note: in expansion
of macro ‘ARGIFY’
  315 |     TYPEFY (arg2, __arg2) = ARGIFY (arg2);     \
      |                             ^~~~~~
../sysdeps/unix/sysv/linux/x86_64/sysdep.h:222:2: note: in expansion
of macro ‘internal_syscall5’
  222 |  internal_syscall##nr (SYS_ify (name), args)
      |  ^~~~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/sysdep.h:43:23: note: in expansion of macro
‘INTERNAL_SYSCALL’
   43 |     long int sc_ret = INTERNAL_SYSCALL (name, nr, args);  \
      |                       ^~~~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/fexecve.c:43:3: note: in expansion of macro
‘INLINE_SYSCALL’
   43 |   INLINE_SYSCALL (execveat, 5, fd, "", &argv[0], &envp[0],
AT_EMPTY_PATH);
      |   ^~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h:54:26: error: cast
specifies array type
   54 |   (((__typeof__ (X)) 0 < (__typeof__ (X)) -1 &&  sizeof (X) == 4) \
      |                          ^
../sysdeps/unix/sysv/linux/x86_64/sysdep.h:315:29: note: in expansion
of macro ‘ARGIFY’
  315 |     TYPEFY (arg2, __arg2) = ARGIFY (arg2);     \
      |                             ^~~~~~
../sysdeps/unix/sysv/linux/x86_64/sysdep.h:222:2: note: in expansion
of macro ‘internal_syscall5’
  222 |  internal_syscall##nr (SYS_ify (name), args)
      |  ^~~~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/sysdep.h:43:23: note: in expansion of macro
‘INTERNAL_SYSCALL’
   43 |     long int sc_ret = INTERNAL_SYSCALL (name, nr, args);  \
      |                       ^~~~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/fexecve.c:43:3: note: in expansion of macro
‘INLINE_SYSCALL’
   43 |   INLINE_SYSCALL (execveat, 5, fd, "", &argv[0], &envp[0],
AT_EMPTY_PATH);
      |   ^~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h:56:6: error: cast from
pointer to integer of different size [-Werror=pointer-to-int-cast]
   56 |    : (long long int) (X))
      |      ^
../sysdeps/unix/sysv/linux/x86_64/sysdep.h:315:29: note: in expansion
of macro ‘ARGIFY’
  315 |     TYPEFY (arg2, __arg2) = ARGIFY (arg2);     \
      |                             ^~~~~~
../sysdeps/unix/sysv/linux/x86_64/sysdep.h:222:2: note: in expansion
of macro ‘internal_syscall5’
  222 |  internal_syscall##nr (SYS_ify (name), args)
      |  ^~~~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/sysdep.h:43:23: note: in expansion of macro
‘INTERNAL_SYSCALL’
   43 |     long int sc_ret = INTERNAL_SYSCALL (name, nr, args);  \
      |                       ^~~~~~~~~~~~~~~~
../sysdeps/unix/sysv/linux/fexecve.c:43:3: note: in expansion of macro
‘INLINE_SYSCALL’
   43 |   INLINE_SYSCALL (execveat, 5, fd, "", &argv[0], &envp[0],
AT_EMPTY_PATH);
      |   ^~~~~~~~~~~~~~
Florian Weimer April 12, 2020, 8:44 p.m. UTC | #11
* H. J. Lu:

> nohup: ignoring input and appending output to 'nohup.out'
> gnu-tools-1:pts/5[130]> m nohup.out
> In file included from ../sysdeps/x86_64/nptl/tls.h:28,
>                  from ../include/errno.h:25,
>                  from ../sysdeps/unix/sysv/linux/fexecve.c:18:
> ../sysdeps/unix/sysv/linux/fexecve.c: In function ‘fexecve’:
> ../sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h:56:6: error: cast from pointer to
>  integer of different size [-Werror=pointer-to-int-cast]
>    56 |    : (long long int) (X))
>       |      ^

Please try something like this:

#define ARGIFY(X)                                                       \
  ({                                                                    \
    _Pragma ("GCC diagnostic push");                                    \
    _Pragma ("GCC diagnostic ignored \"-Wpointer-to-int-cast\"");       \
    (sizeof (X) <= 4 && (__typeof__ (X)) 0 < (__typeof__ (X)) -1)       \
      ? (long long int) (unsigned long int) (X)                         \
      : (long int long) (X);                                            \
    _Pragma ("GCC diagnostic pop");                                     \
  })

(__builtin_choose_expr does not work because it only suppresses
errors, not warnings.)

It may not work in some cases because (__typeof__ (X)) 0 is not valid
if X is an array.
H.J. Lu April 12, 2020, 10:42 p.m. UTC | #12
On Sun, Apr 12, 2020 at 1:44 PM Florian Weimer <fw@deneb.enyo.de> wrote:
>
> * H. J. Lu:
>
> > nohup: ignoring input and appending output to 'nohup.out'
> > gnu-tools-1:pts/5[130]> m nohup.out
> > In file included from ../sysdeps/x86_64/nptl/tls.h:28,
> >                  from ../include/errno.h:25,
> >                  from ../sysdeps/unix/sysv/linux/fexecve.c:18:
> > ../sysdeps/unix/sysv/linux/fexecve.c: In function ‘fexecve’:
> > ../sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h:56:6: error: cast from pointer to
> >  integer of different size [-Werror=pointer-to-int-cast]
> >    56 |    : (long long int) (X))
> >       |      ^
>
> Please try something like this:
>
> #define ARGIFY(X)                                                       \
>   ({                                                                    \
>     _Pragma ("GCC diagnostic push");                                    \
>     _Pragma ("GCC diagnostic ignored \"-Wpointer-to-int-cast\"");       \
>     (sizeof (X) <= 4 && (__typeof__ (X)) 0 < (__typeof__ (X)) -1)       \
>       ? (long long int) (unsigned long int) (X)                         \
>       : (long int long) (X);                                            \
>     _Pragma ("GCC diagnostic pop");                                     \
>   })
>
> (__builtin_choose_expr does not work because it only suppresses
> errors, not warnings.)
>
> It may not work in some cases because (__typeof__ (X)) 0 is not valid
> if X is an array.

It compiles, but doesn't work.  We need to cast the input of

#define TYPEFY(X, name) __typeof__ ((X) - (X)) name
#define ARGIFY(X) ((__typeof__ ((X) - (X))) (X))

to unsigned long long.
Florian Weimer April 13, 2020, 8:23 a.m. UTC | #13
* H. J. Lu:

> On Sun, Apr 12, 2020 at 1:44 PM Florian Weimer <fw@deneb.enyo.de> wrote:
>>
>> * H. J. Lu:
>>
>> > nohup: ignoring input and appending output to 'nohup.out'
>> > gnu-tools-1:pts/5[130]> m nohup.out
>> > In file included from ../sysdeps/x86_64/nptl/tls.h:28,
>> >                  from ../include/errno.h:25,
>> >                  from ../sysdeps/unix/sysv/linux/fexecve.c:18:
>> > ../sysdeps/unix/sysv/linux/fexecve.c: In function ‘fexecve’:
>> > ../sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h:56:6: error: cast from pointer to
>> >  integer of different size [-Werror=pointer-to-int-cast]
>> >    56 |    : (long long int) (X))
>> >       |      ^
>>
>> Please try something like this:
>>
>> #define ARGIFY(X)                                                       \
>>   ({                                                                    \
>>     _Pragma ("GCC diagnostic push");                                    \
>>     _Pragma ("GCC diagnostic ignored \"-Wpointer-to-int-cast\"");       \
>>     (sizeof (X) <= 4 && (__typeof__ (X)) 0 < (__typeof__ (X)) -1)       \
>>       ? (long long int) (unsigned long int) (X)                         \
>>       : (long int long) (X);                                            \
>>     _Pragma ("GCC diagnostic pop");                                     \
>>   })
>>
>> (__builtin_choose_expr does not work because it only suppresses
>> errors, not warnings.)
>>
>> It may not work in some cases because (__typeof__ (X)) 0 is not valid
>> if X is an array.
>
> It compiles, but doesn't work.  We need to cast the input of
>
> #define TYPEFY(X, name) __typeof__ ((X) - (X)) name
> #define ARGIFY(X) ((__typeof__ ((X) - (X))) (X))
>
> to unsigned long long.

Why does it fail?  Are there any arguments besides pointers which must
not be sign-extended to 64 bits?  According to syscall(2), I don't
think, so I still think we can make this work if we just avoid
sign-extending pointers.
H.J. Lu April 13, 2020, 11:44 a.m. UTC | #14
On Mon, Apr 13, 2020 at 1:23 AM Florian Weimer <fw@deneb.enyo.de> wrote:
>
> * H. J. Lu:
>
> > On Sun, Apr 12, 2020 at 1:44 PM Florian Weimer <fw@deneb.enyo.de> wrote:
> >>
> >> * H. J. Lu:
> >>
> >> > nohup: ignoring input and appending output to 'nohup.out'
> >> > gnu-tools-1:pts/5[130]> m nohup.out
> >> > In file included from ../sysdeps/x86_64/nptl/tls.h:28,
> >> >                  from ../include/errno.h:25,
> >> >                  from ../sysdeps/unix/sysv/linux/fexecve.c:18:
> >> > ../sysdeps/unix/sysv/linux/fexecve.c: In function ‘fexecve’:
> >> > ../sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h:56:6: error: cast from pointer to
> >> >  integer of different size [-Werror=pointer-to-int-cast]
> >> >    56 |    : (long long int) (X))
> >> >       |      ^
> >>
> >> Please try something like this:
> >>
> >> #define ARGIFY(X)                                                       \
> >>   ({                                                                    \
> >>     _Pragma ("GCC diagnostic push");                                    \
> >>     _Pragma ("GCC diagnostic ignored \"-Wpointer-to-int-cast\"");       \
> >>     (sizeof (X) <= 4 && (__typeof__ (X)) 0 < (__typeof__ (X)) -1)       \
> >>       ? (long long int) (unsigned long int) (X)                         \
> >>       : (long int long) (X);                                            \
> >>     _Pragma ("GCC diagnostic pop");                                     \
> >>   })
> >>
> >> (__builtin_choose_expr does not work because it only suppresses
> >> errors, not warnings.)
> >>
> >> It may not work in some cases because (__typeof__ (X)) 0 is not valid
> >> if X is an array.
> >
> > It compiles, but doesn't work.  We need to cast the input of
> >
> > #define TYPEFY(X, name) __typeof__ ((X) - (X)) name
> > #define ARGIFY(X) ((__typeof__ ((X) - (X))) (X))
> >
> > to unsigned long long.
>
> Why does it fail?  Are there any arguments besides pointers which must
> not be sign-extended to 64 bits?  According to syscall(2), I don't
> think, so I still think we can make this work if we just avoid
> sign-extending pointers.

Here is a simple testcase:

---
#define TYPEFY(X, name) __typeof__ ((X) - (X)) name
#define ARGIFY(X) ((__typeof__ ((X) - (X))) (X))

int
foo (unsigned int arg1)
{
  unsigned long int resultvar;
  TYPEFY (arg1, __arg1) = ARGIFY (arg1);
  register TYPEFY (arg1, _a1) asm ("rdi") = __arg1;
  asm volatile ("syscall\n\t"
: "=a" (resultvar)
: "0" (0xff), "r" (_a1)
: "memory");
  return resultvar;
}
---

When compiled with -O2 -mx32, we need "movl %edi, %edi" before
syscall
H.J. Lu April 13, 2020, 11:54 a.m. UTC | #15
On Mon, Apr 13, 2020 at 4:44 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Mon, Apr 13, 2020 at 1:23 AM Florian Weimer <fw@deneb.enyo.de> wrote:
> >
> > * H. J. Lu:
> >
> > > On Sun, Apr 12, 2020 at 1:44 PM Florian Weimer <fw@deneb.enyo.de> wrote:
> > >>
> > >> * H. J. Lu:
> > >>
> > >> > nohup: ignoring input and appending output to 'nohup.out'
> > >> > gnu-tools-1:pts/5[130]> m nohup.out
> > >> > In file included from ../sysdeps/x86_64/nptl/tls.h:28,
> > >> >                  from ../include/errno.h:25,
> > >> >                  from ../sysdeps/unix/sysv/linux/fexecve.c:18:
> > >> > ../sysdeps/unix/sysv/linux/fexecve.c: In function ‘fexecve’:
> > >> > ../sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h:56:6: error: cast from pointer to
> > >> >  integer of different size [-Werror=pointer-to-int-cast]
> > >> >    56 |    : (long long int) (X))
> > >> >       |      ^
> > >>
> > >> Please try something like this:
> > >>
> > >> #define ARGIFY(X)                                                       \
> > >>   ({                                                                    \
> > >>     _Pragma ("GCC diagnostic push");                                    \
> > >>     _Pragma ("GCC diagnostic ignored \"-Wpointer-to-int-cast\"");       \
> > >>     (sizeof (X) <= 4 && (__typeof__ (X)) 0 < (__typeof__ (X)) -1)       \
> > >>       ? (long long int) (unsigned long int) (X)                         \
> > >>       : (long int long) (X);                                            \
> > >>     _Pragma ("GCC diagnostic pop");                                     \
> > >>   })
> > >>
> > >> (__builtin_choose_expr does not work because it only suppresses
> > >> errors, not warnings.)
> > >>
> > >> It may not work in some cases because (__typeof__ (X)) 0 is not valid
> > >> if X is an array.
> > >
> > > It compiles, but doesn't work.  We need to cast the input of
> > >
> > > #define TYPEFY(X, name) __typeof__ ((X) - (X)) name
> > > #define ARGIFY(X) ((__typeof__ ((X) - (X))) (X))
> > >
> > > to unsigned long long.
> >
> > Why does it fail?  Are there any arguments besides pointers which must
> > not be sign-extended to 64 bits?  According to syscall(2), I don't
> > think, so I still think we can make this work if we just avoid
> > sign-extending pointers.
>
> Here is a simple testcase:
>
> ---
> #define TYPEFY(X, name) __typeof__ ((X) - (X)) name
> #define ARGIFY(X) ((__typeof__ ((X) - (X))) (X))
>
> int
> foo (unsigned int arg1)
> {
>   unsigned long int resultvar;
>   TYPEFY (arg1, __arg1) = ARGIFY (arg1);
>   register TYPEFY (arg1, _a1) asm ("rdi") = __arg1;
>   asm volatile ("syscall\n\t"
> : "=a" (resultvar)
> : "0" (0xff), "r" (_a1)
> : "memory");
>   return resultvar;
> }
> ---
>
> When compiled with -O2 -mx32, we need "movl %edi, %edi" before
> syscall
>

I may have found a solution.
H.J. Lu April 13, 2020, 2:26 p.m. UTC | #16
On Mon, Apr 13, 2020 at 4:54 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Mon, Apr 13, 2020 at 4:44 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > On Mon, Apr 13, 2020 at 1:23 AM Florian Weimer <fw@deneb.enyo.de> wrote:
> > >
> > > * H. J. Lu:
> > >
> > > > On Sun, Apr 12, 2020 at 1:44 PM Florian Weimer <fw@deneb.enyo.de> wrote:
> > > >>
> > > >> * H. J. Lu:
> > > >>
> > > >> > nohup: ignoring input and appending output to 'nohup.out'
> > > >> > gnu-tools-1:pts/5[130]> m nohup.out
> > > >> > In file included from ../sysdeps/x86_64/nptl/tls.h:28,
> > > >> >                  from ../include/errno.h:25,
> > > >> >                  from ../sysdeps/unix/sysv/linux/fexecve.c:18:
> > > >> > ../sysdeps/unix/sysv/linux/fexecve.c: In function ‘fexecve’:
> > > >> > ../sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h:56:6: error: cast from pointer to
> > > >> >  integer of different size [-Werror=pointer-to-int-cast]
> > > >> >    56 |    : (long long int) (X))
> > > >> >       |      ^
> > > >>
> > > >> Please try something like this:
> > > >>
> > > >> #define ARGIFY(X)                                                       \
> > > >>   ({                                                                    \
> > > >>     _Pragma ("GCC diagnostic push");                                    \
> > > >>     _Pragma ("GCC diagnostic ignored \"-Wpointer-to-int-cast\"");       \
> > > >>     (sizeof (X) <= 4 && (__typeof__ (X)) 0 < (__typeof__ (X)) -1)       \
> > > >>       ? (long long int) (unsigned long int) (X)                         \
> > > >>       : (long int long) (X);                                            \
> > > >>     _Pragma ("GCC diagnostic pop");                                     \
> > > >>   })
> > > >>
> > > >> (__builtin_choose_expr does not work because it only suppresses
> > > >> errors, not warnings.)
> > > >>
> > > >> It may not work in some cases because (__typeof__ (X)) 0 is not valid
> > > >> if X is an array.
> > > >
> > > > It compiles, but doesn't work.  We need to cast the input of
> > > >
> > > > #define TYPEFY(X, name) __typeof__ ((X) - (X)) name
> > > > #define ARGIFY(X) ((__typeof__ ((X) - (X))) (X))
> > > >
> > > > to unsigned long long.
> > >
> > > Why does it fail?  Are there any arguments besides pointers which must
> > > not be sign-extended to 64 bits?  According to syscall(2), I don't
> > > think, so I still think we can make this work if we just avoid
> > > sign-extending pointers.
> >
> > Here is a simple testcase:
> >
> > ---
> > #define TYPEFY(X, name) __typeof__ ((X) - (X)) name
> > #define ARGIFY(X) ((__typeof__ ((X) - (X))) (X))
> >
> > int
> > foo (unsigned int arg1)
> > {
> >   unsigned long int resultvar;
> >   TYPEFY (arg1, __arg1) = ARGIFY (arg1);
> >   register TYPEFY (arg1, _a1) asm ("rdi") = __arg1;
> >   asm volatile ("syscall\n\t"
> > : "=a" (resultvar)
> > : "0" (0xff), "r" (_a1)
> > : "memory");
> >   return resultvar;
> > }
> > ---
> >
> > When compiled with -O2 -mx32, we need "movl %edi, %edi" before
> > syscall
> >
>
> I may have found a solution.

A new patch set is posted at

https://sourceware.org/pipermail/libc-alpha/2020-April/112748.html
diff mbox series

Patch

diff --git a/misc/Makefile b/misc/Makefile
index b8fed5783d..67c5237f97 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -87,7 +87,7 @@  tests := tst-dirname tst-tsearch tst-fdset tst-mntent tst-hsearch \
 	 tst-preadvwritev tst-preadvwritev64 tst-makedev tst-empty \
 	 tst-preadvwritev2 tst-preadvwritev64v2 tst-warn-wide \
 	 tst-ldbl-warn tst-ldbl-error tst-dbl-efgcvt tst-ldbl-efgcvt \
-	 tst-mntent-autofs
+	 tst-mntent-autofs tst-syscalls
 
 # Tests which need libdl.
 ifeq (yes,$(build-shared))
diff --git a/misc/tst-syscalls.c b/misc/tst-syscalls.c
new file mode 100644
index 0000000000..d07f03633b
--- /dev/null
+++ b/misc/tst-syscalls.c
@@ -0,0 +1,146 @@ 
+/* Test for syscall interfaces.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+
+struct Array
+{
+  size_t length;
+  void *ptr;
+};
+
+static int error_count;
+
+__attribute__ ((noclone, noinline))
+struct Array
+allocate (size_t bytes)
+{
+  if (!bytes)
+    return __extension__ (struct Array) {0, 0};
+
+  void *p = mmap (0x0, bytes, PROT_READ | PROT_WRITE,
+		  MAP_PRIVATE | MAP_ANON, -1, 0);
+  if (p == MAP_FAILED)
+    return __extension__ (struct Array) {0, 0};
+
+  return __extension__ (struct Array) {bytes, p};
+}
+
+__attribute__ ((noclone, noinline))
+void
+deallocate (struct Array b)
+{
+  if (b.length && munmap (b.ptr, b.length))
+    {
+      printf ("munmap error: %m\n");
+      error_count++;
+    }
+}
+
+__attribute__ ((noclone, noinline))
+void *
+do_mmap (void *addr, size_t length)
+{
+  return mmap (addr, length, PROT_READ | PROT_WRITE,
+	       MAP_PRIVATE | MAP_ANON, -1, 0);
+}
+
+__attribute__ ((noclone, noinline))
+void *
+reallocate (struct Array b)
+{
+  if (b.length)
+    return do_mmap (b.ptr, b.length);
+  return NULL;
+}
+
+__attribute__ ((noclone, noinline))
+void
+protect (struct Array b)
+{
+  if (b.length)
+    {
+      if (mprotect (b.ptr, b.length,
+		    PROT_READ | PROT_WRITE | PROT_EXEC))
+	{
+	  printf ("mprotect error: %m\n");
+	  error_count++;
+	}
+    }
+}
+
+__attribute__ ((noclone, noinline))
+ssize_t
+do_read (int fd, void *ptr, struct Array b)
+{
+  if (b.length)
+    return read (fd, ptr, b.length);
+  return 0;
+}
+
+__attribute__ ((noclone, noinline))
+ssize_t
+do_write (int fd, void *ptr, struct Array b)
+{
+  if (b.length)
+    return write (fd, ptr, b.length);
+  return 0;
+}
+
+static int
+do_test (void)
+{
+  struct Array array;
+
+  array = allocate (1);
+  protect (array);
+  deallocate (array);
+  void *p = reallocate (array);
+  if (p == MAP_FAILED)
+    {
+      printf ("mmap error: %m\n");
+      error_count++;
+    }
+  array.ptr = p;
+  protect (array);
+  deallocate (array);
+
+  int fd = xopen ("/dev/null", O_RDWR, 0);
+  char buf[2];
+  array.ptr = buf;
+  if (do_read (fd, array.ptr, array) == -1)
+    {
+      printf ("read error: %m\n");
+      error_count++;
+    }
+  if (do_write (fd, array.ptr, array) == -1)
+    {
+      printf ("write error: %m\n");
+      error_count++;
+    }
+  xclose (fd);
+
+  return error_count ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/make-syscalls.sh b/sysdeps/unix/make-syscalls.sh
index c07626677f..52cf7e2f16 100644
--- a/sysdeps/unix/make-syscalls.sh
+++ b/sysdeps/unix/make-syscalls.sh
@@ -30,6 +30,7 @@ 
 # P: optionally-NULL pointer to typed object (e.g., 3rd argument to sigaction)
 # s: non-NULL string (e.g., 1st arg to open)
 # S: optionally-NULL string (e.g., 1st arg to acct)
+# U: unsigned long
 # v: vararg scalar (e.g., optional 3rd arg to open)
 # V: byte-per-page vector (3rd arg to mincore)
 # W: wait status, optionally-NULL pointer to int (e.g., 2nd arg of wait4)
@@ -184,6 +185,91 @@  while read file srcfile caller syscall args strong weak; do
   ?:?????????) nargs=9;;
   esac
 
+  # Derive the long arguments from the argument signature
+  ulong_arg_1=0
+  ulong_arg_2=0
+  case $args in
+  ?:U*)
+    ulong_arg_1=1
+    case $args in
+    ?:UU*) ulong_arg_2=2;;
+    ?:U?U*) ulong_arg_2=3;;
+    ?:U??U*) ulong_arg_2=4;;
+    ?:U???U*) ulong_arg_2=5;;
+    ?:U????U*) ulong_arg_2=6;;
+    ?:U?????U*) ulong_arg_2=7;;
+    ?:U??????U*) ulong_arg_2=8;;
+    ?:U???????U) ulong_arg_2=9;;
+    esac
+    ;;
+  ?:?U*)
+    ulong_arg_1=2
+    case $args in
+    ?:?UU*) ulong_arg_2=3;;
+    ?:?U?U*) ulong_arg_2=4;;
+    ?:?U??U*) ulong_arg_2=5;;
+    ?:?U???U*) ulong_arg_2=6;;
+    ?:?U????U*) ulong_arg_2=7;;
+    ?:?U?????U*) ulong_arg_2=8;;
+    ?:?U??????U) ulong_arg_2=9;;
+    esac
+    ;;
+  ?:??U*)
+    ulong_arg_1=3
+    case $args in
+    ?:??UU*) ulong_arg_2=4;;
+    ?:??U?U*) ulong_arg_2=5;;
+    ?:??U??U*) ulong_arg_2=6;;
+    ?:??U???U*) ulong_arg_2=7;;
+    ?:??U????U*) ulong_arg_2=8;;
+    ?:??U?????U) ulong_arg_2=9;;
+    esac
+    ;;
+  ?:???U*)
+    ulong_arg_1=4
+    case $args in
+    ?:???UU*) ulong_arg_2=5;;
+    ?:???U?U*) ulong_arg_2=6;;
+    ?:???U??U*) ulong_arg_2=7;;
+    ?:???U???U*) ulong_arg_2=8;;
+    ?:???U????U) ulong_arg_2=9;;
+    esac
+    ;;
+  ?:????U*)
+    ulong_arg_1=5
+    case $args in
+    ?:????UU*) ulong_arg_2=6;;
+    ?:????U?U*) ulong_arg_2=7;;
+    ?:????U??U*) ulong_arg_2=8;;
+    ?:????U???U) ulong_arg_2=9;;
+    esac
+    ;;
+  ?:?????U*)
+    ulong_arg_1=6
+    case $args in
+    ?:?????UU*) ulong_arg_2=7;;
+    ?:?????U?U*) ulong_arg_2=8;;
+    ?:?????U??U) ulong_arg_2=9;;
+    esac
+    ;;
+  ?:??????U*)
+    ulong_arg_1=7
+    case $args in
+    ?:??????UU*) ulong_arg_2=8;;
+    ?:??????U?U) ulong_arg_2=9;;
+    esac
+    ;;
+  ?:???????U*)
+    ulong_arg_1=8
+    case $args in
+    ?:??????UU) ulong_arg_2=9;;
+    esac
+    ;;
+  ?:????????U)
+    ulong_arg_1=9
+    ;;
+  esac
+
   # Make sure only the first syscall rule is used, if multiple dirs
   # define the same syscall.
   echo ''
@@ -245,6 +331,8 @@  while read file srcfile caller syscall args strong weak; do
 	\$(make-target-directory)
 	(echo '#define SYSCALL_NAME $syscall'; \\
 	 echo '#define SYSCALL_NARGS $nargs'; \\
+	 echo '#define SYSCALL_ULONG_ARG_1 $ulong_arg_1'; \\
+	 echo '#define SYSCALL_ULONG_ARG_2 $ulong_arg_2'; \\
 	 echo '#define SYSCALL_SYMBOL $strong'; \\
 	 echo '#define SYSCALL_NOERRNO $noerrno'; \\
 	 echo '#define SYSCALL_ERRVAL $errval'; \\
diff --git a/sysdeps/unix/syscall-template.S b/sysdeps/unix/syscall-template.S
index cf6c7a58fb..e8d6d59b15 100644
--- a/sysdeps/unix/syscall-template.S
+++ b/sysdeps/unix/syscall-template.S
@@ -25,6 +25,10 @@ 
    defining a few macros:
 	SYSCALL_NAME		syscall name
 	SYSCALL_NARGS		number of arguments this call takes
+	SYSCALL_ULONG_ARG_1	the first unsigned long argument this
+				call takes
+	SYSCALL_ULONG_ARG_2	the second unsigned long argument this
+				call takes
 	SYSCALL_SYMBOL		primary symbol name
 	SYSCALL_NOERRNO		1 to define a no-errno version (see below)
 	SYSCALL_ERRVAL		1 to define an error-value version (see below)
@@ -44,9 +48,21 @@ 
 /* This indirection is needed so that SYMBOL gets macro-expanded.  */
 #define syscall_hidden_def(SYMBOL)		hidden_def (SYMBOL)
 
-#define T_PSEUDO(SYMBOL, NAME, N)		PSEUDO (SYMBOL, NAME, N)
-#define T_PSEUDO_NOERRNO(SYMBOL, NAME, N)	PSEUDO_NOERRNO (SYMBOL, NAME, N)
-#define T_PSEUDO_ERRVAL(SYMBOL, NAME, N)	PSEUDO_ERRVAL (SYMBOL, NAME, N)
+#if SYSCALL_ULONG_ARG_1
+# define T_PSEUDO(SYMBOL, NAME, N, U1, U2) \
+  PSEUDO (SYMBOL, NAME, N, U1, U2)
+# define T_PSEUDO_NOERRNO(SYMBOL, NAME, N, U1, U2) \
+  PSEUDO_NOERRNO (SYMBOL, NAME, N, U1, U2)
+# define T_PSEUDO_ERRVAL(SYMBOL, NAME, N, U1, U2) \
+  PSEUDO_ERRVAL (SYMBOL, NAME, N, U1, U2)
+#else
+# define T_PSEUDO(SYMBOL, NAME, N) \
+  PSEUDO (SYMBOL, NAME, N)
+# define T_PSEUDO_NOERRNO(SYMBOL, NAME, N) \
+  PSEUDO_NOERRNO (SYMBOL, NAME, N)
+# define T_PSEUDO_ERRVAL(SYMBOL, NAME, N) \
+  PSEUDO_ERRVAL (SYMBOL, NAME, N)
+#endif
 #define T_PSEUDO_END(SYMBOL)			PSEUDO_END (SYMBOL)
 #define T_PSEUDO_END_NOERRNO(SYMBOL)		PSEUDO_END_NOERRNO (SYMBOL)
 #define T_PSEUDO_END_ERRVAL(SYMBOL)		PSEUDO_END_ERRVAL (SYMBOL)
@@ -56,7 +72,12 @@ 
 /* This kind of system call stub never returns an error.
    We return the return value register to the caller unexamined.  */
 
+# if SYSCALL_ULONG_ARG_1
+T_PSEUDO_NOERRNO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS,
+		  SYSCALL_ULONG_ARG_1, SYSCALL_ULONG_ARG_2)
+# else
 T_PSEUDO_NOERRNO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
+# endif
 	ret_NOERRNO
 T_PSEUDO_END_NOERRNO (SYSCALL_SYMBOL)
 
@@ -66,7 +87,12 @@  T_PSEUDO_END_NOERRNO (SYSCALL_SYMBOL)
    value, or zero for success.  We may massage the kernel's return value
    to meet that ABI, but we never set errno here.  */
 
+# if SYSCALL_ULONG_ARG_1
+T_PSEUDO_ERRVAL (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS,
+		 SYSCALL_ULONG_ARG_1, SYSCALL_ULONG_ARG_2)
+# else
 T_PSEUDO_ERRVAL (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
+# endif
 	ret_ERRVAL
 T_PSEUDO_END_ERRVAL (SYSCALL_SYMBOL)
 
@@ -75,7 +101,12 @@  T_PSEUDO_END_ERRVAL (SYSCALL_SYMBOL)
 /* This is a "normal" system call stub: if there is an error,
    it returns -1 and sets errno.  */
 
+# if SYSCALL_ULONG_ARG_1
+T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS,
+	  SYSCALL_ULONG_ARG_1, SYSCALL_ULONG_ARG_2)
+# else
 T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
+# endif
 	ret
 T_PSEUDO_END (SYSCALL_SYMBOL)
 
diff --git a/sysdeps/unix/sysv/linux/copy_file_range.c b/sysdeps/unix/sysv/linux/copy_file_range.c
index a73c89f079..50487df77c 100644
--- a/sysdeps/unix/sysv/linux/copy_file_range.c
+++ b/sysdeps/unix/sysv/linux/copy_file_range.c
@@ -26,5 +26,5 @@  copy_file_range (int infd, __off64_t *pinoff,
                  size_t length, unsigned int flags)
 {
   return SYSCALL_CANCEL (copy_file_range, infd, pinoff, outfd, poutoff,
-                         length, flags);
+                         SYSCALL_ULONG (length), flags);
 }
diff --git a/sysdeps/unix/sysv/linux/getcwd.c b/sysdeps/unix/sysv/linux/getcwd.c
index fabc4bb8cc..d228467edf 100644
--- a/sysdeps/unix/sysv/linux/getcwd.c
+++ b/sysdeps/unix/sysv/linux/getcwd.c
@@ -75,7 +75,7 @@  __getcwd (char *buf, size_t size)
 
   int retval;
 
-  retval = INLINE_SYSCALL (getcwd, 2, path, alloc_size);
+  retval = INLINE_SYSCALL (getcwd, 2, path, SYSCALL_ULONG (alloc_size));
   if (retval > 0 && path[0] == '/')
     {
 #ifndef NO_ALLOCATION
diff --git a/sysdeps/unix/sysv/linux/getdents.c b/sysdeps/unix/sysv/linux/getdents.c
index a76be2e5e7..fc8da0caae 100644
--- a/sysdeps/unix/sysv/linux/getdents.c
+++ b/sysdeps/unix/sysv/linux/getdents.c
@@ -53,7 +53,8 @@  __getdents (int fd, void *buf0, size_t nbytes)
   if (nbytes <= sizeof (struct dirent))
     kbuf = (void*) kbuftmp;
 
-  retval = INLINE_SYSCALL_CALL (getdents64, fd, kbuf, kbytes);
+  retval = INLINE_SYSCALL_CALL (getdents64, fd, kbuf,
+				SYSCALL_ULONG (kbytes));
   if (retval == -1)
     return -1;
 
diff --git a/sysdeps/unix/sysv/linux/getdents64.c b/sysdeps/unix/sysv/linux/getdents64.c
index 75892c2823..63c89c7d60 100644
--- a/sysdeps/unix/sysv/linux/getdents64.c
+++ b/sysdeps/unix/sysv/linux/getdents64.c
@@ -29,7 +29,8 @@  __getdents64 (int fd, void *buf, size_t nbytes)
      checks in the kernel use an int type.  */
   if (nbytes > INT_MAX)
     nbytes = INT_MAX;
-  return INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes);
+  return INLINE_SYSCALL_CALL (getdents64, fd, buf,
+			      SYSCALL_ULONG (nbytes));
 }
 libc_hidden_def (__getdents64)
 weak_alias (__getdents64, getdents64)
@@ -74,7 +75,8 @@  __old_getdents64 (int fd, char *buf, size_t nbytes)
 		  <= __alignof__ (struct dirent64),
 		  "alignment of __old_dirent64 is larger than dirent64");
 
-  ssize_t retval = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes);
+  ssize_t retval = INLINE_SYSCALL_CALL (getdents64, fd, buf,
+					SYSCALL_ULONG (nbytes));
   if (retval > 0)
     {
       /* This is the marker for the first entry.  Offset 0 is reserved
diff --git a/sysdeps/unix/sysv/linux/getentropy.c b/sysdeps/unix/sysv/linux/getentropy.c
index 2f3a4e4692..f99d2783a1 100644
--- a/sysdeps/unix/sysv/linux/getentropy.c
+++ b/sysdeps/unix/sysv/linux/getentropy.c
@@ -41,7 +41,9 @@  getentropy (void *buffer, size_t length)
   while (buffer < end)
     {
       /* NB: No cancellation point.  */
-      ssize_t bytes = INLINE_SYSCALL_CALL (getrandom, buffer, end - buffer, 0);
+      ssize_t bytes = INLINE_SYSCALL_CALL (getrandom, buffer,
+					   SYSCALL_ULONG (end - buffer),
+					   0);
       if (bytes < 0)
         {
           if (errno == EINTR)
diff --git a/sysdeps/unix/sysv/linux/getrandom.c b/sysdeps/unix/sysv/linux/getrandom.c
index 63b8d36bf4..8008890939 100644
--- a/sysdeps/unix/sysv/linux/getrandom.c
+++ b/sysdeps/unix/sysv/linux/getrandom.c
@@ -26,7 +26,8 @@ 
 ssize_t
 __getrandom (void *buffer, size_t length, unsigned int flags)
 {
-  return SYSCALL_CANCEL (getrandom, buffer, length, flags);
+  return SYSCALL_CANCEL (getrandom, buffer, SYSCALL_ULONG (length),
+			 flags);
 }
 libc_hidden_def (__getrandom)
 weak_alias (__getrandom, getrandom)
diff --git a/sysdeps/unix/sysv/linux/mlock2.c b/sysdeps/unix/sysv/linux/mlock2.c
index e52f43f35c..599ed5c351 100644
--- a/sysdeps/unix/sysv/linux/mlock2.c
+++ b/sysdeps/unix/sysv/linux/mlock2.c
@@ -23,11 +23,13 @@  int
 mlock2 (const void *addr, size_t length, unsigned int flags)
 {
 #ifdef __ASSUME_MLOCK2
-  return INLINE_SYSCALL_CALL (mlock2, addr, length, flags);
+  return INLINE_SYSCALL_CALL (mlock2, addr, SYSCALL_ULONG (length),
+			      flags);
 #else
   if (flags == 0)
-    return INLINE_SYSCALL_CALL (mlock, addr, length);
-  int ret = INLINE_SYSCALL_CALL (mlock2, addr, length, flags);
+    return INLINE_SYSCALL_CALL (mlock, addr, SYSCALL_ULONG (length));
+  int ret = INLINE_SYSCALL_CALL (mlock2, addr, SYSCALL_ULONG (length),
+				 flags);
   if (ret == 0 || errno != ENOSYS)
     return ret;
   /* Treat the missing system call as an invalid (non-zero) flag
diff --git a/sysdeps/unix/sysv/linux/mmap64.c b/sysdeps/unix/sysv/linux/mmap64.c
index 8074deb466..7efe7f171d 100644
--- a/sysdeps/unix/sysv/linux/mmap64.c
+++ b/sysdeps/unix/sysv/linux/mmap64.c
@@ -53,10 +53,11 @@  __mmap64 (void *addr, size_t len, int prot, int flags, int fd, off64_t offset)
 
   MMAP_PREPARE (addr, len, prot, flags, fd, offset);
 #ifdef __NR_mmap2
-  return (void *) MMAP_CALL (mmap2, addr, len, prot, flags, fd,
-			     (off_t) (offset / MMAP2_PAGE_UNIT));
+  return (void *) MMAP_CALL (mmap2, addr, SYSCALL_ULONG (len), prot, flags,
+			     fd, (off_t) (offset / MMAP2_PAGE_UNIT));
 #else
-  return (void *) MMAP_CALL (mmap, addr, len, prot, flags, fd, offset);
+  return (void *) MMAP_CALL (mmap, addr, SYSCALL_ULONG (len), prot, flags,
+			     fd, offset);
 #endif
 }
 weak_alias (__mmap64, mmap64)
diff --git a/sysdeps/unix/sysv/linux/mq_timedreceive.c b/sysdeps/unix/sysv/linux/mq_timedreceive.c
index 728a63d1ec..aae1443196 100644
--- a/sysdeps/unix/sysv/linux/mq_timedreceive.c
+++ b/sysdeps/unix/sysv/linux/mq_timedreceive.c
@@ -30,11 +30,12 @@  __mq_timedreceive_time64 (mqd_t mqdes, char *__restrict msg_ptr, size_t msg_len,
 # ifndef __NR_mq_timedreceive_time64
 #  define __NR_mq_timedreceive_time64 __NR_mq_timedreceive
 # endif
-  return SYSCALL_CANCEL (mq_timedreceive_time64, mqdes, msg_ptr, msg_len,
-                         msg_prio, abs_timeout);
+  return SYSCALL_CANCEL (mq_timedreceive_time64, mqdes, msg_ptr,
+			 SYSCALL_ULONG (msg_len), msg_prio, abs_timeout);
 #else
-  int ret = SYSCALL_CANCEL (mq_timedreceive_time64, mqdes, msg_ptr, msg_len,
-                            msg_prio, abs_timeout);
+  int ret = SYSCALL_CANCEL (mq_timedreceive_time64, mqdes, msg_ptr,
+			    SYSCALL_ULONG (msg_len), msg_prio,
+			    abs_timeout);
   if (ret == 0 || errno != ENOSYS)
     return ret;
 
@@ -50,7 +51,8 @@  __mq_timedreceive_time64 (mqd_t mqdes, char *__restrict msg_ptr, size_t msg_len,
       ts32 = valid_timespec64_to_timespec (*abs_timeout);
     }
 
-  return SYSCALL_CANCEL (mq_timedreceive, mqdes, msg_ptr, msg_len, msg_prio,
+  return SYSCALL_CANCEL (mq_timedreceive, mqdes, msg_ptr,
+			 SYSCALL_ULONG (msg_len), msg_prio,
                          abs_timeout != NULL ? &ts32 : NULL);
 #endif
 }
diff --git a/sysdeps/unix/sysv/linux/mq_timedsend.c b/sysdeps/unix/sysv/linux/mq_timedsend.c
index f2a43df300..7e174df888 100644
--- a/sysdeps/unix/sysv/linux/mq_timedsend.c
+++ b/sysdeps/unix/sysv/linux/mq_timedsend.c
@@ -30,11 +30,11 @@  __mq_timedsend_time64 (mqd_t mqdes, const char *msg_ptr, size_t msg_len,
 # ifndef __NR_mq_timedsend_time64
 #  define __NR_mq_timedsend_time64 __NR_mq_timedsend
 # endif
-  return SYSCALL_CANCEL (mq_timedsend_time64, mqdes, msg_ptr, msg_len,
-                         msg_prio, abs_timeout);
+  return SYSCALL_CANCEL (mq_timedsend_time64, mqdes, msg_ptr,
+			 SYSCALL_ULONG (msg_len), msg_prio, abs_timeout);
 #else
-  int ret = SYSCALL_CANCEL (mq_timedsend_time64, mqdes, msg_ptr, msg_len,
-                            msg_prio, abs_timeout);
+  int ret = SYSCALL_CANCEL (mq_timedsend_time64, mqdes, msg_ptr,
+			    SYSCALL_ULONG (msg_len), msg_prio, abs_timeout);
   if (ret == 0 || errno != ENOSYS)
     return ret;
 
@@ -50,7 +50,8 @@  __mq_timedsend_time64 (mqd_t mqdes, const char *msg_ptr, size_t msg_len,
       ts32 = valid_timespec64_to_timespec (*abs_timeout);
     }
 
-  return SYSCALL_CANCEL (mq_timedsend, mqdes, msg_ptr, msg_len, msg_prio,
+  return SYSCALL_CANCEL (mq_timedsend, mqdes, msg_ptr,
+			 SYSCALL_ULONG (msg_len), msg_prio,
                          abs_timeout != NULL ? &ts32 : NULL);
 #endif
 }
@@ -66,7 +67,8 @@  __mq_timedsend (mqd_t mqdes, const char *msg_ptr, size_t msg_len,
   if (abs_timeout != NULL)
     ts64 = valid_timespec_to_timespec64 (*abs_timeout);
 
-  return __mq_timedsend_time64 (mqdes, msg_ptr, msg_len, msg_prio,
+  return __mq_timedsend_time64 (mqdes, msg_ptr,
+				SYSCALL_ULONG (msg_len), msg_prio,
                                 abs_timeout != NULL ? &ts64 : NULL);
 }
 #endif
diff --git a/sysdeps/unix/sysv/linux/msgrcv.c b/sysdeps/unix/sysv/linux/msgrcv.c
index 95edc7a787..ecfa2df4fb 100644
--- a/sysdeps/unix/sysv/linux/msgrcv.c
+++ b/sysdeps/unix/sysv/linux/msgrcv.c
@@ -25,10 +25,11 @@  __libc_msgrcv (int msqid, void *msgp, size_t msgsz, long int msgtyp,
 	       int msgflg)
 {
 #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
-  return SYSCALL_CANCEL (msgrcv, msqid, msgp, msgsz, msgtyp, msgflg);
+  return SYSCALL_CANCEL (msgrcv, msqid, msgp, SYSCALL_ULONG (msgsz),
+			 SYSCALL_LONG (msgtyp), msgflg);
 #else
-  return SYSCALL_CANCEL (ipc, IPCOP_msgrcv, msqid, msgsz, msgflg,
-			 MSGRCV_ARGS (msgp, msgtyp));
+  return SYSCALL_CANCEL (ipc, IPCOP_msgrcv, msqid, SYSCALL_ULONG (msgsz),
+			 msgflg, MSGRCV_ARGS (msgp, SYSCALL_LONG (msgtyp)));
 #endif
 }
 weak_alias (__libc_msgrcv, msgrcv)
diff --git a/sysdeps/unix/sysv/linux/msgsnd.c b/sysdeps/unix/sysv/linux/msgsnd.c
index 554516f2ca..9e329d8e72 100644
--- a/sysdeps/unix/sysv/linux/msgsnd.c
+++ b/sysdeps/unix/sysv/linux/msgsnd.c
@@ -24,10 +24,11 @@  int
 __libc_msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg)
 {
 #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
-  return SYSCALL_CANCEL (msgsnd, msqid, msgp, msgsz, msgflg);
+  return SYSCALL_CANCEL (msgsnd, msqid, msgp, SYSCALL_ULONG (msgsz),
+			 msgflg);
 #else
-  return SYSCALL_CANCEL (ipc, IPCOP_msgsnd, msqid, msgsz, msgflg,
-			 msgp);
+  return SYSCALL_CANCEL (ipc, IPCOP_msgsnd, msqid, SYSCALL_ULONG (msgsz),
+			 msgflg, msgp);
 #endif
 }
 weak_alias (__libc_msgsnd, msgsnd)
diff --git a/sysdeps/unix/sysv/linux/msync.c b/sysdeps/unix/sysv/linux/msync.c
index de1dd2ac5e..0ef48a1eaf 100644
--- a/sysdeps/unix/sysv/linux/msync.c
+++ b/sysdeps/unix/sysv/linux/msync.c
@@ -22,5 +22,5 @@ 
 int
 msync (void *addr, size_t length, int flags)
 {
-  return SYSCALL_CANCEL (msync, addr, length, flags);
+  return SYSCALL_CANCEL (msync, addr, SYSCALL_ULONG (length), flags);
 }
diff --git a/sysdeps/unix/sysv/linux/pkey_mprotect.c b/sysdeps/unix/sysv/linux/pkey_mprotect.c
index 4ec1feba2e..9130bbdef6 100644
--- a/sysdeps/unix/sysv/linux/pkey_mprotect.c
+++ b/sysdeps/unix/sysv/linux/pkey_mprotect.c
@@ -28,5 +28,6 @@  pkey_mprotect (void *addr, size_t len, int prot, int pkey)
     /* If the key is -1, the system call is precisely equivalent to
        mprotect.  */
     return __mprotect (addr, len, prot);
-  return INLINE_SYSCALL_CALL (pkey_mprotect, addr, len, prot, pkey);
+  return INLINE_SYSCALL_CALL (pkey_mprotect, addr, SYSCALL_ULONG (len),
+			      prot, pkey);
 }
diff --git a/sysdeps/unix/sysv/linux/pread.c b/sysdeps/unix/sysv/linux/pread.c
index 8dd87b3976..41d51d810c 100644
--- a/sysdeps/unix/sysv/linux/pread.c
+++ b/sysdeps/unix/sysv/linux/pread.c
@@ -24,7 +24,8 @@ 
 ssize_t
 __libc_pread (int fd, void *buf, size_t count, off_t offset)
 {
-  return SYSCALL_CANCEL (pread64, fd, buf, count, SYSCALL_LL_PRW (offset));
+  return SYSCALL_CANCEL (pread64, fd, buf, SYSCALL_ULONG (count),
+			 SYSCALL_LL_PRW (offset));
 }
 
 strong_alias (__libc_pread, __pread)
diff --git a/sysdeps/unix/sysv/linux/pread64.c b/sysdeps/unix/sysv/linux/pread64.c
index 3d4ffbafc1..7a7bf7076c 100644
--- a/sysdeps/unix/sysv/linux/pread64.c
+++ b/sysdeps/unix/sysv/linux/pread64.c
@@ -22,7 +22,8 @@ 
 ssize_t
 __libc_pread64 (int fd, void *buf, size_t count, off64_t offset)
 {
-  return SYSCALL_CANCEL (pread64, fd, buf, count, SYSCALL_LL64_PRW (offset));
+  return SYSCALL_CANCEL (pread64, fd, buf, SYSCALL_ULONG (count),
+			 SYSCALL_LL64_PRW (offset));
 }
 
 weak_alias (__libc_pread64, __pread64)
diff --git a/sysdeps/unix/sysv/linux/pread64_nocancel.c b/sysdeps/unix/sysv/linux/pread64_nocancel.c
index af33985959..ea9e3be552 100644
--- a/sysdeps/unix/sysv/linux/pread64_nocancel.c
+++ b/sysdeps/unix/sysv/linux/pread64_nocancel.c
@@ -23,6 +23,7 @@ 
 ssize_t
 __pread64_nocancel (int fd, void *buf, size_t count, off64_t offset)
 {
-  return INLINE_SYSCALL_CALL (pread64, fd, buf, count, SYSCALL_LL64_PRW (offset));
+  return INLINE_SYSCALL_CALL (pread64, fd, buf, SYSCALL_ULONG (count),
+			      SYSCALL_LL64_PRW (offset));
 }
 hidden_def (__pread64_nocancel)
diff --git a/sysdeps/unix/sysv/linux/pwrite.c b/sysdeps/unix/sysv/linux/pwrite.c
index 17964686e5..c1cddbfe81 100644
--- a/sysdeps/unix/sysv/linux/pwrite.c
+++ b/sysdeps/unix/sysv/linux/pwrite.c
@@ -24,7 +24,8 @@ 
 ssize_t
 __libc_pwrite (int fd, const void *buf, size_t count, off_t offset)
 {
-  return SYSCALL_CANCEL (pwrite64, fd, buf, count, SYSCALL_LL_PRW (offset));
+  return SYSCALL_CANCEL (pwrite64, fd, buf, SYSCALL_ULONG (count),
+			 SYSCALL_LL_PRW (offset));
 }
 
 strong_alias (__libc_pwrite, __pwrite)
diff --git a/sysdeps/unix/sysv/linux/pwrite64.c b/sysdeps/unix/sysv/linux/pwrite64.c
index 709775c207..a47c309144 100644
--- a/sysdeps/unix/sysv/linux/pwrite64.c
+++ b/sysdeps/unix/sysv/linux/pwrite64.c
@@ -22,7 +22,8 @@ 
 ssize_t
 __libc_pwrite64 (int fd, const void *buf, size_t count, off64_t offset)
 {
-  return SYSCALL_CANCEL (pwrite64, fd, buf, count, SYSCALL_LL64_PRW (offset));
+  return SYSCALL_CANCEL (pwrite64, fd, buf, SYSCALL_ULONG (count),
+			 SYSCALL_LL64_PRW (offset));
 }
 
 weak_alias (__libc_pwrite64, __pwrite64)
diff --git a/sysdeps/unix/sysv/linux/read.c b/sysdeps/unix/sysv/linux/read.c
index 64f558a587..6c37b4fba9 100644
--- a/sysdeps/unix/sysv/linux/read.c
+++ b/sysdeps/unix/sysv/linux/read.c
@@ -23,7 +23,7 @@ 
 ssize_t
 __libc_read (int fd, void *buf, size_t nbytes)
 {
-  return SYSCALL_CANCEL (read, fd, buf, nbytes);
+  return SYSCALL_CANCEL (read, fd, buf, SYSCALL_ULONG (nbytes));
 }
 libc_hidden_def (__libc_read)
 
diff --git a/sysdeps/unix/sysv/linux/read_nocancel.c b/sysdeps/unix/sysv/linux/read_nocancel.c
index f9d8a3b563..4a734e9d83 100644
--- a/sysdeps/unix/sysv/linux/read_nocancel.c
+++ b/sysdeps/unix/sysv/linux/read_nocancel.c
@@ -23,6 +23,6 @@ 
 ssize_t
 __read_nocancel (int fd, void *buf, size_t nbytes)
 {
-  return INLINE_SYSCALL_CALL (read, fd, buf, nbytes);
+  return INLINE_SYSCALL_CALL (read, fd, buf, SYSCALL_ULONG (nbytes));
 }
 hidden_def (__read_nocancel)
diff --git a/sysdeps/unix/sysv/linux/readahead.c b/sysdeps/unix/sysv/linux/readahead.c
index a189c3ac79..46a98c000a 100644
--- a/sysdeps/unix/sysv/linux/readahead.c
+++ b/sysdeps/unix/sysv/linux/readahead.c
@@ -25,6 +25,6 @@  __readahead (int fd, off64_t offset, size_t count)
 {
   return INLINE_SYSCALL_CALL (readahead, fd,
 			      __ALIGNMENT_ARG SYSCALL_LL64 (offset),
-			      count);
+			      SYSCALL_ULONG (count));
 }
 weak_alias (__readahead, readahead)
diff --git a/sysdeps/unix/sysv/linux/recv.c b/sysdeps/unix/sysv/linux/recv.c
index 79fb3c32d1..9ab079cc7c 100644
--- a/sysdeps/unix/sysv/linux/recv.c
+++ b/sysdeps/unix/sysv/linux/recv.c
@@ -23,11 +23,12 @@  ssize_t
 __libc_recv (int fd, void *buf, size_t len, int flags)
 {
 #ifdef __ASSUME_RECV_SYSCALL
-  return SYSCALL_CANCEL (recv, fd, buf, len, flags);
+  return SYSCALL_CANCEL (recv, fd, buf, SYSCALL_ULONG (len), flags);
 #elif defined __ASSUME_RECVFROM_SYSCALL
-  return SYSCALL_CANCEL (recvfrom, fd, buf, len, flags, NULL, NULL);
+  return SYSCALL_CANCEL (recvfrom, fd, buf, SYSCALL_ULONG (len), flags,
+			 NULL, NULL);
 #else
-  return SOCKETCALL_CANCEL (recv, fd, buf, len, flags);
+  return SOCKETCALL_CANCEL (recv, fd, buf, SYSCALL_ULONG (len), flags);
 #endif
 }
 weak_alias (__libc_recv, recv)
diff --git a/sysdeps/unix/sysv/linux/recvfrom.c b/sysdeps/unix/sysv/linux/recvfrom.c
index 70532529c9..caf3b66738 100644
--- a/sysdeps/unix/sysv/linux/recvfrom.c
+++ b/sysdeps/unix/sysv/linux/recvfrom.c
@@ -24,11 +24,11 @@  __libc_recvfrom (int fd, void *buf, size_t len, int flags,
 		 __SOCKADDR_ARG addr, socklen_t *addrlen)
 {
 #ifdef __ASSUME_RECVFROM_SYSCALL
-  return SYSCALL_CANCEL (recvfrom, fd, buf, len, flags, addr.__sockaddr__,
-                         addrlen);
+  return SYSCALL_CANCEL (recvfrom, fd, buf, SYSCALL_ULONG (len), flags,
+			 addr.__sockaddr__, addrlen);
 #else
-  return SOCKETCALL_CANCEL (recvfrom, fd, buf, len, flags, addr.__sockaddr__,
-			    addrlen);
+  return SOCKETCALL_CANCEL (recvfrom, fd, buf, SYSCALL_ULONG (len),
+			    flags, addr.__sockaddr__, addrlen);
 #endif
 }
 weak_alias (__libc_recvfrom, recvfrom)
diff --git a/sysdeps/unix/sysv/linux/sched_setaffinity.c b/sysdeps/unix/sysv/linux/sched_setaffinity.c
index fc2c692783..aea179464c 100644
--- a/sysdeps/unix/sysv/linux/sched_setaffinity.c
+++ b/sysdeps/unix/sysv/linux/sched_setaffinity.c
@@ -30,7 +30,8 @@  libc_hidden_proto (__sched_setaffinity_new)
 int
 __sched_setaffinity_new (pid_t pid, size_t cpusetsize, const cpu_set_t *cpuset)
 {
-  int result = INLINE_SYSCALL (sched_setaffinity, 3, pid, cpusetsize, cpuset);
+  int result = INLINE_SYSCALL (sched_setaffinity, 3, pid,
+			       SYSCALL_ULONG (cpusetsize), cpuset);
 
 #ifdef RESET_VGETCPU_CACHE
   if (result != -1)
diff --git a/sysdeps/unix/sysv/linux/semtimedop.c b/sysdeps/unix/sysv/linux/semtimedop.c
index 6fdde09bad..f3b240ca9b 100644
--- a/sysdeps/unix/sysv/linux/semtimedop.c
+++ b/sysdeps/unix/sysv/linux/semtimedop.c
@@ -30,10 +30,12 @@  __semtimedop (int semid, struct sembuf *sops, size_t nsops,
   /* semtimedop wire-up syscall is not exported for 32-bit ABIs (they have
      semtimedop_time64 instead with uses a 64-bit time_t).  */
 #if defined __ASSUME_DIRECT_SYSVIPC_SYSCALLS && defined __NR_semtimedop
-  return INLINE_SYSCALL_CALL (semtimedop, semid, sops, nsops, timeout);
+  return INLINE_SYSCALL_CALL (semtimedop, semid, sops,
+			      SYSCALL_ULONG (nsops), timeout);
 #else
   return INLINE_SYSCALL_CALL (ipc, IPCOP_semtimedop, semid,
-			      SEMTIMEDOP_IPC_ARGS (nsops, sops, timeout));
+			      SEMTIMEDOP_IPC_ARGS (SYSCALL_ULONG (nsops),
+						   sops, timeout));
 #endif
 }
 weak_alias (__semtimedop, semtimedop)
diff --git a/sysdeps/unix/sysv/linux/send.c b/sysdeps/unix/sysv/linux/send.c
index aed7d06585..cd8725d05b 100644
--- a/sysdeps/unix/sysv/linux/send.c
+++ b/sysdeps/unix/sysv/linux/send.c
@@ -23,11 +23,12 @@  ssize_t
 __libc_send (int fd, const void *buf, size_t len, int flags)
 {
 #ifdef __ASSUME_SEND_SYSCALL
-  return SYSCALL_CANCEL (send, fd, buf, len, flags);
+  return SYSCALL_CANCEL (send, fd, buf, SYSCALL_ULONG (len), flags);
 #elif defined __ASSUME_SENDTO_SYSCALL
-  return SYSCALL_CANCEL (sendto, fd, buf, len, flags, NULL, 0);
+  return SYSCALL_CANCEL (sendto, fd, buf, SYSCALL_ULONG (len), flags,
+			 NULL, 0);
 #else
-  return SOCKETCALL_CANCEL (send, fd, buf, len, flags);
+  return SOCKETCALL_CANCEL (send, fd, buf, SYSCALL_ULONG (len), flags);
 #endif
 }
 weak_alias (__libc_send, send)
diff --git a/sysdeps/unix/sysv/linux/sendto.c b/sysdeps/unix/sysv/linux/sendto.c
index 670d0679ea..ceb61305af 100644
--- a/sysdeps/unix/sysv/linux/sendto.c
+++ b/sysdeps/unix/sysv/linux/sendto.c
@@ -24,11 +24,11 @@  __libc_sendto (int fd, const void *buf, size_t len, int flags,
 	       __CONST_SOCKADDR_ARG addr, socklen_t addrlen)
 {
 #ifdef __ASSUME_SENDTO_SYSCALL
-  return SYSCALL_CANCEL (sendto, fd, buf, len, flags, addr.__sockaddr__,
-                         addrlen);
+  return SYSCALL_CANCEL (sendto, fd, buf, SYSCALL_ULONG (len), flags,
+			 addr.__sockaddr__, addrlen);
 #else
-  return SOCKETCALL_CANCEL (sendto, fd, buf, len, flags, addr.__sockaddr__,
-			    addrlen);
+  return SOCKETCALL_CANCEL (sendto, fd, buf, SYSCALL_ULONG (len), flags,
+			    addr.__sockaddr__, addrlen);
 #endif
 }
 weak_alias (__libc_sendto, sendto)
diff --git a/sysdeps/unix/sysv/linux/shmget.c b/sysdeps/unix/sysv/linux/shmget.c
index 6f7ce8c057..1032142170 100644
--- a/sysdeps/unix/sysv/linux/shmget.c
+++ b/sysdeps/unix/sysv/linux/shmget.c
@@ -28,8 +28,10 @@  int
 shmget (key_t key, size_t size, int shmflg)
 {
 #ifdef __ASSUME_DIRECT_SYSVIPC_SYSCALLS
-  return INLINE_SYSCALL_CALL (shmget, key, size, shmflg, NULL);
+  return INLINE_SYSCALL_CALL (shmget, key, SYSCALL_ULONG (size),
+			      shmflg, NULL);
 #else
-  return INLINE_SYSCALL_CALL (ipc, IPCOP_shmget, key, size, shmflg, NULL);
+  return INLINE_SYSCALL_CALL (ipc, IPCOP_shmget, key,
+			      SYSCALL_ULONG (size), shmflg, NULL);
 #endif
 }
diff --git a/sysdeps/unix/sysv/linux/splice.c b/sysdeps/unix/sysv/linux/splice.c
index fe21cf1988..199608fffa 100644
--- a/sysdeps/unix/sysv/linux/splice.c
+++ b/sysdeps/unix/sysv/linux/splice.c
@@ -23,5 +23,6 @@  ssize_t
 splice (int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len,
 	unsigned int flags)
 {
-  return SYSCALL_CANCEL (splice, fd_in, off_in, fd_out, off_out, len, flags);
+  return SYSCALL_CANCEL (splice, fd_in, off_in, fd_out, off_out,
+			 SYSCALL_ULONG (len), flags);
 }
diff --git a/sysdeps/unix/sysv/linux/sysdep.h b/sysdeps/unix/sysv/linux/sysdep.h
index 5e7b6c5765..0ab65e40a5 100644
--- a/sysdeps/unix/sysv/linux/sysdep.h
+++ b/sysdeps/unix/sysv/linux/sysdep.h
@@ -94,6 +94,11 @@ 
  (long) (val), \
  (long) (((uint64_t) (val)) >> 32)
 
+/* Provide common macros to pass long/unsigned long (ssize_t/size_t)
+   values on syscalls.  */
+#define SYSCALL_LONG(val) (val)
+#define SYSCALL_ULONG(val) (val)
+
 /* Exports the __send symbol on send.c linux implementation (some ABI have
    it missing due the usage of a old generic version without it).  */
 #define HAVE_INTERNAL_SEND_SYMBOL	1
diff --git a/sysdeps/unix/sysv/linux/tee.c b/sysdeps/unix/sysv/linux/tee.c
index 0e62c226dd..f404768ef6 100644
--- a/sysdeps/unix/sysv/linux/tee.c
+++ b/sysdeps/unix/sysv/linux/tee.c
@@ -22,5 +22,5 @@ 
 ssize_t
 tee (int src, int dest, size_t len, unsigned int flags)
 {
-  return SYSCALL_CANCEL (tee, src, dest, len, flags);
+  return SYSCALL_CANCEL (tee, src, dest, SYSCALL_ULONG (len), flags);
 }
diff --git a/sysdeps/unix/sysv/linux/vmsplice.c b/sysdeps/unix/sysv/linux/vmsplice.c
index 17cc7bf8e7..e338a73944 100644
--- a/sysdeps/unix/sysv/linux/vmsplice.c
+++ b/sysdeps/unix/sysv/linux/vmsplice.c
@@ -23,5 +23,5 @@ 
 ssize_t
 vmsplice (int fd, const struct iovec *iov, size_t count, unsigned int flags)
 {
-  return SYSCALL_CANCEL (vmsplice, fd, iov, count, flags);
+  return SYSCALL_CANCEL (vmsplice, fd, iov, SYSCALL_ULONG (count), flags);
 }
diff --git a/sysdeps/unix/sysv/linux/write.c b/sysdeps/unix/sysv/linux/write.c
index 7848f7de27..2176572425 100644
--- a/sysdeps/unix/sysv/linux/write.c
+++ b/sysdeps/unix/sysv/linux/write.c
@@ -23,7 +23,7 @@ 
 ssize_t
 __libc_write (int fd, const void *buf, size_t nbytes)
 {
-  return SYSCALL_CANCEL (write, fd, buf, nbytes);
+  return SYSCALL_CANCEL (write, fd, buf, SYSCALL_ULONG (nbytes));
 }
 libc_hidden_def (__libc_write)
 
diff --git a/sysdeps/unix/sysv/linux/write_nocancel.c b/sysdeps/unix/sysv/linux/write_nocancel.c
index 36d406cf74..17aa7d4797 100644
--- a/sysdeps/unix/sysv/linux/write_nocancel.c
+++ b/sysdeps/unix/sysv/linux/write_nocancel.c
@@ -23,6 +23,6 @@ 
 ssize_t
 __write_nocancel (int fd, const void *buf, size_t nbytes)
 {
-  return INLINE_SYSCALL_CALL (write, fd, buf, nbytes);
+  return INLINE_SYSCALL_CALL (write, fd, buf, SYSCALL_ULONG (nbytes));
 }
 hidden_def (__write_nocancel)
diff --git a/sysdeps/unix/sysv/linux/x86_64/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
index 24d8b8ec20..a8a8e95fa5 100644
--- a/sysdeps/unix/sysv/linux/x86_64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
@@ -57,13 +57,27 @@ 
 #  define SYSCALL_ERROR_LABEL syscall_error
 # endif
 
+# ifndef SYSCALL_ULONG_ARG_1
+#  define SYSCALL_ULONG_ARG_1 0
+#  define SYSCALL_ULONG_ARG_2 0
+# endif
+
 # undef	PSEUDO
-# define PSEUDO(name, syscall_name, args)				      \
-  .text;								      \
-  ENTRY (name)								      \
-    DO_CALL (syscall_name, args);					      \
-    cmpq $-4095, %rax;							      \
+# if SYSCALL_ULONG_ARG_1
+#  define PSEUDO(name, syscall_name, args, long_arg_1, long_arg_2) \
+  .text;							      \
+  ENTRY (name)							      \
+    DO_CALL (syscall_name, args, long_arg_1, long_arg_2);	      \
+    cmpq $-4095, %rax;						      \
     jae SYSCALL_ERROR_LABEL
+# else
+#  define PSEUDO(name, syscall_name, args) \
+  .text;							      \
+  ENTRY (name)							      \
+    DO_CALL (syscall_name, args, 0, 0);				      \
+    cmpq $-4095, %rax;						      \
+    jae SYSCALL_ERROR_LABEL
+# endif
 
 # undef	PSEUDO_END
 # define PSEUDO_END(name)						      \
@@ -71,10 +85,17 @@ 
   END (name)
 
 # undef	PSEUDO_NOERRNO
-# define PSEUDO_NOERRNO(name, syscall_name, args) \
-  .text;								      \
-  ENTRY (name)								      \
-    DO_CALL (syscall_name, args)
+# if SYSCALL_ULONG_ARG_1
+#  define PSEUDO_NOERRNO(name, syscall_name, args, long_arg_1, long_arg_2) \
+  .text;							      \
+  ENTRY (name)							      \
+    DO_CALL (syscall_name, args, long_arg_1, long_arg_2)
+# else
+#  define PSEUDO_NOERRNO(name, syscall_name, args) \
+  .text;							      \
+  ENTRY (name)							      \
+    DO_CALL (syscall_name, args, 0, 0)
+# endif
 
 # undef	PSEUDO_END_NOERRNO
 # define PSEUDO_END_NOERRNO(name) \
@@ -83,11 +104,19 @@ 
 # define ret_NOERRNO ret
 
 # undef	PSEUDO_ERRVAL
-# define PSEUDO_ERRVAL(name, syscall_name, args) \
-  .text;								      \
-  ENTRY (name)								      \
-    DO_CALL (syscall_name, args);					      \
+# if SYSCALL_ULONG_ARG_1
+#  define PSEUDO_ERRVAL(name, syscall_name, args, long_arg_1, long_arg_2) \
+  .text;							\
+  ENTRY (name)							\
+    DO_CALL (syscall_name, args, long_arg_1, long_arg_2);	\
     negq %rax
+# else
+#  define PSEUDO_ERRVAL(name, syscall_name, args) \
+  .text;							\
+  ENTRY (name)							\
+    DO_CALL (syscall_name, args, 0, 0);				\
+    negq %rax
+# endif
 
 # undef	PSEUDO_END_ERRVAL
 # define PSEUDO_END_ERRVAL(name) \
@@ -159,7 +188,7 @@ 
     Syscalls of more than 6 arguments are not supported.  */
 
 # undef	DO_CALL
-# define DO_CALL(syscall_name, args)		\
+# define DO_CALL(syscall_name, args, long_arg_1, long_arg_2) \
     DOARGS_##args				\
     movl $SYS_ify (syscall_name), %eax;		\
     syscall;
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list b/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list
index 58ea31d1fd..dfc551d402 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list
@@ -1,4 +1,14 @@ 
 # File name	Caller	Syscall name	# args	Strong name	Weak names
 
+madvise		-	madvise		i:pUi	__madvise	madvise
+mincore		-	mincore		i:aUV	mincore
+mprotect	-	mprotect	i:aUi	__mprotect	mprotect
+mlock		-	mlock		i:bU	mlock
+mount		EXTRA	mount		i:sssUp	__mount	mount
+mremap		EXTRA	mremap		b:aUUip	__mremap	mremap
+munlock		-	munlock		i:aU	munlock
+munmap		-	munmap		i:aU	__munmap	munmap
 personality	EXTRA	personality	Ei:i	__personality	personality
 posix_fadvise64	-	fadvise64	Vi:iiii	posix_fadvise	posix_fadvise64
+remap_file_pages -	remap_file_pages i:pUiUi	__remap_file_pages remap_file_pages
+sendfile	-	sendfile	i:iipU	sendfile	sendfile64
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
index 5bf9eed80b..d6898eb080 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
@@ -26,4 +26,34 @@ 
 #undef LO_HI_LONG
 #define LO_HI_LONG(val) (val)
 
+/* How to pass  pass long/unsigned long (ssize_t/size_t) on syscalls. */
+#undef SYSCALL_LONG
+#define SYSCALL_LONG(val) ((int64_t) (val))
+#undef SYSCALL_ULONG
+#define SYSCALL_ULONG(val) ((uint64_t) (val))
+
+#ifdef __ASSEMBLER__
+# undef	DO_CALL
+# define DO_CALL(syscall_name, args, long_arg_1, long_arg_2)	\
+  DOARGS_##args							\
+  ZERO_EXTEND_##long_arg_1					\
+  ZERO_EXTEND_##long_arg_2					\
+  movl $SYS_ify (syscall_name), %eax;				\
+  syscall;
+
+# define ZERO_EXTEND_0 /* nothing */
+# define ZERO_EXTEND_1 movl %edi, %edi;
+# define ZERO_EXTEND_2 movl %esi, %esi;
+# define ZERO_EXTEND_3 movl %edx, %edx;
+# define ZERO_EXTEND_4 movl %r10d, %r10d;
+# define ZERO_EXTEND_5 movl %r8d, %r8d;
+# define ZERO_EXTEND_6 movl %r9d, %r9d;
+
+# if SYSCALL_ULONG_ARG_1 == 4 || SYSCALL_ULONG_ARG_2 == 4
+#  undef ZERO_EXTEND_4
+#  define ZERO_EXTEND_4 /* nothing */
+#  define DOARGS_4 movl %ecx, %r10d;
+# endif
+#endif	/* __ASSEMBLER__ */
+
 #endif /* linux/x86_64/x32/sysdep.h */