diff mbox series

V2 [PATCH 1/2] Add SYSCALL_ULONG_ARG_[12] to pass long to syscall [BZ #25810]

Message ID 20200413175117.170042-2-hjl.tools@gmail.com
State New
Headers show
Series V2 [PATCH 1/2] Add SYSCALL_ULONG_ARG_[12] to pass long to syscall [BZ #25810] | expand

Commit Message

H.J. Lu April 13, 2020, 5:51 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 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 if PSEUDOS_HAVE_4_ARGS is
defined.  They are used by x32 to zero-extend 32-bit arguments to
64 bits.

Tested on i386, x86-64 and x32 as well as with build-many-glibcs.py.
---
 sysdeps/unix/make-syscalls.sh               | 88 +++++++++++++++++++++
 sysdeps/unix/syscall-template.S             | 43 +++++++++-
 sysdeps/unix/syscalls.list                  |  6 +-
 sysdeps/unix/sysv/linux/syscalls.list       | 14 ++--
 sysdeps/unix/sysv/linux/x86_64/sysdep.h     | 70 ++++++++++++----
 sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h | 20 ++++-
 6 files changed, 213 insertions(+), 28 deletions(-)

Comments

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

> diff --git a/sysdeps/unix/make-syscalls.sh b/sysdeps/unix/make-syscalls.sh
> index c07626677f..4a28badea6 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

Maybe this?

# U: unsigned long int (32-bit types are zero-extended to 64-bit types)

>  # 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 unsigned long arguments from the argument signature

“unsigned long int”

> +  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=9
> +    ;;
> +  esac
> +

I must say that I find this really, really ugly.  We should rewrite
this in Python as soon as possible (in a separate patch).

You could try this instead:

$ echo U1U | grep -ob U
0:U
2:U

And maybe guard it with a case match, so that performance does not
suffer too much.

In any case, there should be an error check that covers the more
than-two-Us case.


>    # 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'; \\

Should this be conditional on whether $ulong_arg_1 and $ulong_arg_2
are empty?  I think that might be less confusing.

Otherwise, the comment at the beginning should mention the special
value zero.

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

“unsigned long int”

>  	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,27 @@
>  /* 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 PSEUDOS_HAVE_4_ARGS is defined, PSEUDO macros have 4 arguments.  */
> +#ifndef PSEUDOS_HAVE_4_ARGS
> +# undef SYSCALL_ULONG_ARG_1
> +# define SYSCALL_ULONG_ARG_1 0
> +#endif

PSEUDOS_HAVE_4_ARGS should be PSEUDOS_HAVE_ULONG_INDICES or something
like that.  And a comment that briefly explains all the macro
arguments.  (Not sure if T_PSEUDO is documented somewhere else
already.)

> diff --git a/sysdeps/unix/syscalls.list b/sysdeps/unix/syscalls.list
> index 01c4a0e6b1..e63a8b9d23 100644
> --- a/sysdeps/unix/syscalls.list
> +++ b/sysdeps/unix/syscalls.list
> @@ -37,11 +37,11 @@ kill		-	kill		i:ii	__kill		kill
>  link		-	link		i:ss	__link		link
>  listen		-	listen		i:ii	__listen	listen
>  lseek		-	lseek		i:iii	__libc_lseek	__lseek lseek
> -madvise		-	madvise		i:pii	__madvise	madvise
> +madvise		-	madvise		i:pUi	__madvise	madvise
>  mkdir		-	mkdir		i:si	__mkdir		mkdir
>  mmap		-	mmap		b:aniiii __mmap		mmap
> -mprotect	-	mprotect	i:aii	__mprotect	mprotect
> -munmap		-	munmap		i:ai	__munmap	munmap
> +mprotect	-	mprotect	i:aUi	__mprotect	mprotect
> +munmap		-	munmap		i:aU	__munmap	munmap
>  open		-	open		Ci:siv	__libc_open __open open
>  profil		-	profil		i:piii	__profil	profil
>  ptrace		-	ptrace		i:iiii	ptrace

What about read, readlink, write, etc.?

> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
> index a37d520f86..b8a74ad2c2 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
> @@ -26,7 +26,25 @@
>  #undef LO_HI_LONG
>  #define LO_HI_LONG(val) (val)
>  
> -#ifndef __ASSEMBLER__
> +#ifdef __ASSEMBLER__
> +# undef ZERO_EXTEND_1
> +# define ZERO_EXTEND_1 movl %edi, %edi;
> +# undef ZERO_EXTEND_2
> +# define ZERO_EXTEND_2 movl %esi, %esi;
> +# undef ZERO_EXTEND_3
> +# define ZERO_EXTEND_3 movl %edx, %edx;
> +# if SYSCALL_ULONG_ARG_1 == 4 || SYSCALL_ULONG_ARG_2 == 4
> +#  undef DOARGS_4
> +#  define DOARGS_4 movl %ecx, %r10d;
> +# else
> +#  undef ZERO_EXTEND_4
> +#  define ZERO_EXTEND_4 movl %r10d, %r10d;
> +# endif
> +# undef ZERO_EXTEND_5
> +# define ZERO_EXTEND_5 movl %r8d, %r8d;
> +# undef ZERO_EXTEND_6
> +# define ZERO_EXTEND_6 movl %r9d, %r9d;
> +#else /* !__ASSEMBLER__ */
>  # undef ARGIFY
>  /* Enforce zero-extension for pointers and array system call arguments.
>     For integer types, extend to int64_t (the full register) using a

The comment should come before the newly added changes, I think.
Adhemerval Zanella April 22, 2020, 11:44 a.m. UTC | #2
On 22/04/2020 07:42, Florian Weimer wrote:
> * H. J. Lu via Libc-alpha:
> 
>> diff --git a/sysdeps/unix/make-syscalls.sh b/sysdeps/unix/make-syscalls.sh
>> index c07626677f..4a28badea6 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
> 
> Maybe this?
> 
> # U: unsigned long int (32-bit types are zero-extended to 64-bit types)
> 
>>  # 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 unsigned long arguments from the argument signature
> 
> “unsigned long int”
> 
>> +  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=9
>> +    ;;
>> +  esac
>> +
> 
> I must say that I find this really, really ugly.  We should rewrite
> this in Python as soon as possible (in a separate patch).

And I think we should make long term gold to just get rid of this
assembly macro and focus on automatic generation to a C code file
as well.

> 
> You could try this instead:
> 
> $ echo U1U | grep -ob U
> 0:U
> 2:U
> 
> And maybe guard it with a case match, so that performance does not
> suffer too much.
> 
> In any case, there should be an error check that covers the more
> than-two-Us case.
> 
> 
>>    # 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'; \\
> 
> Should this be conditional on whether $ulong_arg_1 and $ulong_arg_2
> are empty?  I think that might be less confusing.
> 
> Otherwise, the comment at the beginning should mention the special
> value zero.
> 
>>  	 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..0824a3c61e 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
> 
> “unsigned long int”
> 
>>  	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,27 @@
>>  /* 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 PSEUDOS_HAVE_4_ARGS is defined, PSEUDO macros have 4 arguments.  */
>> +#ifndef PSEUDOS_HAVE_4_ARGS
>> +# undef SYSCALL_ULONG_ARG_1
>> +# define SYSCALL_ULONG_ARG_1 0
>> +#endif
> 
> PSEUDOS_HAVE_4_ARGS should be PSEUDOS_HAVE_ULONG_INDICES or something
> like that.  And a comment that briefly explains all the macro
> arguments.  (Not sure if T_PSEUDO is documented somewhere else
> already.)
> 
>> diff --git a/sysdeps/unix/syscalls.list b/sysdeps/unix/syscalls.list
>> index 01c4a0e6b1..e63a8b9d23 100644
>> --- a/sysdeps/unix/syscalls.list
>> +++ b/sysdeps/unix/syscalls.list
>> @@ -37,11 +37,11 @@ kill		-	kill		i:ii	__kill		kill
>>  link		-	link		i:ss	__link		link
>>  listen		-	listen		i:ii	__listen	listen
>>  lseek		-	lseek		i:iii	__libc_lseek	__lseek lseek
>> -madvise		-	madvise		i:pii	__madvise	madvise
>> +madvise		-	madvise		i:pUi	__madvise	madvise
>>  mkdir		-	mkdir		i:si	__mkdir		mkdir
>>  mmap		-	mmap		b:aniiii __mmap		mmap
>> -mprotect	-	mprotect	i:aii	__mprotect	mprotect
>> -munmap		-	munmap		i:ai	__munmap	munmap
>> +mprotect	-	mprotect	i:aUi	__mprotect	mprotect
>> +munmap		-	munmap		i:aU	__munmap	munmap
>>  open		-	open		Ci:siv	__libc_open __open open
>>  profil		-	profil		i:piii	__profil	profil
>>  ptrace		-	ptrace		i:iiii	ptrace
> 
> What about read, readlink, write, etc.?
> 
>> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
>> index a37d520f86..b8a74ad2c2 100644
>> --- a/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
>> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
>> @@ -26,7 +26,25 @@
>>  #undef LO_HI_LONG
>>  #define LO_HI_LONG(val) (val)
>>  
>> -#ifndef __ASSEMBLER__
>> +#ifdef __ASSEMBLER__
>> +# undef ZERO_EXTEND_1
>> +# define ZERO_EXTEND_1 movl %edi, %edi;
>> +# undef ZERO_EXTEND_2
>> +# define ZERO_EXTEND_2 movl %esi, %esi;
>> +# undef ZERO_EXTEND_3
>> +# define ZERO_EXTEND_3 movl %edx, %edx;
>> +# if SYSCALL_ULONG_ARG_1 == 4 || SYSCALL_ULONG_ARG_2 == 4
>> +#  undef DOARGS_4
>> +#  define DOARGS_4 movl %ecx, %r10d;
>> +# else
>> +#  undef ZERO_EXTEND_4
>> +#  define ZERO_EXTEND_4 movl %r10d, %r10d;
>> +# endif
>> +# undef ZERO_EXTEND_5
>> +# define ZERO_EXTEND_5 movl %r8d, %r8d;
>> +# undef ZERO_EXTEND_6
>> +# define ZERO_EXTEND_6 movl %r9d, %r9d;
>> +#else /* !__ASSEMBLER__ */
>>  # undef ARGIFY
>>  /* Enforce zero-extension for pointers and array system call arguments.
>>     For integer types, extend to int64_t (the full register) using a
> 
> The comment should come before the newly added changes, I think.
>
Joseph Myers April 22, 2020, 10:01 p.m. UTC | #3
On Wed, 22 Apr 2020, Adhemerval Zanella via Libc-alpha wrote:

> > I must say that I find this really, really ugly.  We should rewrite
> > this in Python as soon as possible (in a separate patch).
> 
> And I think we should make long term gold to just get rid of this
> assembly macro and focus on automatic generation to a C code file
> as well.

There are a couple of possible improvements in this area that might be in 
tension here:

* Simplifying how the syscall arguments are specified.  The reason there 
are so many different letters is not because of anything relevant to 
assembly code generation now, it's because of the old support for bounded 
pointers (removed from GCC in 2002, actual substantive uses in the glibc 
syscall generation code removed in 
<https://sourceware.org/legacy-ml/libc-alpha/2013-01/msg00919.html>).

* Generating debug info for the automatically generated syscall 
implementations.  For that, the C code should have actual meaningful 
argument types, not just a sequence of integers that has the right ABI 
(but may not even have the right number of arguments, in cases where a 
64-bit argument uses two letters for syscall arguments in the 32-bit 
syscalls.list files).

What this suggests to me is that automatically-generated C code should get 
actual argument types from the header files in some way, and in the cases 
where header file information isn't sufficient (including syscalls not 
declared in header files or with different arguments to the public C 
function, etc.), using some sort of internal header to give the types 
might be better than having complicated encodings in syscalls.list.  Maybe 
syscalls.list doesn't need much more information than the conventions for 
return value / error handling and the *number* of arguments, if types can 
be extracted from C headers.
Adhemerval Zanella April 23, 2020, 9:34 p.m. UTC | #4
On 22/04/2020 19:01, Joseph Myers wrote:
> On Wed, 22 Apr 2020, Adhemerval Zanella via Libc-alpha wrote:
> 
>>> I must say that I find this really, really ugly.  We should rewrite
>>> this in Python as soon as possible (in a separate patch).
>>
>> And I think we should make long term gold to just get rid of this
>> assembly macro and focus on automatic generation to a C code file
>> as well.
> 
> There are a couple of possible improvements in this area that might be in 
> tension here:
> 
> * Simplifying how the syscall arguments are specified.  The reason there 
> are so many different letters is not because of anything relevant to 
> assembly code generation now, it's because of the old support for bounded 
> pointers (removed from GCC in 2002, actual substantive uses in the glibc 
> syscall generation code removed in 
> <https://sourceware.org/legacy-ml/libc-alpha/2013-01/msg00919.html>).
> 
> * Generating debug info for the automatically generated syscall 
> implementations.  For that, the C code should have actual meaningful 
> argument types, not just a sequence of integers that has the right ABI 
> (but may not even have the right number of arguments, in cases where a 
> 64-bit argument uses two letters for syscall arguments in the 32-bit 
> syscalls.list files).
> 
> What this suggests to me is that automatically-generated C code should get 
> actual argument types from the header files in some way, and in the cases 
> where header file information isn't sufficient (including syscalls not 
> declared in header files or with different arguments to the public C 
> function, etc.), using some sort of internal header to give the types 
> might be better than having complicated encodings in syscalls.list.  Maybe 
> syscalls.list doesn't need much more information than the conventions for 
> return value / error handling and the *number* of arguments, if types can 
> be extracted from C headers.

My initial approach would be to extend the syscall argument definition 
on syscall file description (syscalls.list) with all the required 
information to synthesize the C implementation.  It increases the 
verbose required in the argument description, but I think it would
simpler than try infer from the header itself (which would require to 
parse the it and the this information). 

Something like, using wordsize-64 fstatfs syscalls.list entry:

  fstatfs fstatfs [sys/statfs.h] [const char *, struct statfs64 *] [fstatfs64:w, __fstatfs64:w]

which would translate to:

  #define fstatfs64 __redirect_fstatfs64
  #define __fstatfs64 __redirect___fstatfs64
  #include <sys/statfs.h>
  #undef fstatfs64
  #undef __fstatfs64

  int
  __fstatfs (int arg1, struct statfs *arg2)
  { 
   return INLINE_SYSCALL_CALL (fstatfs, arg1, arg2);
  }
  weak_alias (__fstatfs, fstatfs)
  weak_alias (__fstatfs, __fstatfs64)
  weak_alias (__fstatfs, fstatfs64)

The alias would require some pre-defined logic to handle the LFS
alias for __OFF_T_MATCHES_OFF64_T (and I am not sure if this
example would be better handled in a C implementation in fact),
to handle internal hidden alias, and version.
diff mbox series

Patch

diff --git a/sysdeps/unix/make-syscalls.sh b/sysdeps/unix/make-syscalls.sh
index c07626677f..4a28badea6 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 unsigned 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..0824a3c61e 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,27 @@ 
 /* 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 PSEUDOS_HAVE_4_ARGS is defined, PSEUDO macros have 4 arguments.  */
+#ifndef PSEUDOS_HAVE_4_ARGS
+# undef SYSCALL_ULONG_ARG_1
+# define SYSCALL_ULONG_ARG_1 0
+#endif
+
+#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 +78,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 +93,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 +107,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/syscalls.list b/sysdeps/unix/syscalls.list
index 01c4a0e6b1..e63a8b9d23 100644
--- a/sysdeps/unix/syscalls.list
+++ b/sysdeps/unix/syscalls.list
@@ -37,11 +37,11 @@  kill		-	kill		i:ii	__kill		kill
 link		-	link		i:ss	__link		link
 listen		-	listen		i:ii	__listen	listen
 lseek		-	lseek		i:iii	__libc_lseek	__lseek lseek
-madvise		-	madvise		i:pii	__madvise	madvise
+madvise		-	madvise		i:pUi	__madvise	madvise
 mkdir		-	mkdir		i:si	__mkdir		mkdir
 mmap		-	mmap		b:aniiii __mmap		mmap
-mprotect	-	mprotect	i:aii	__mprotect	mprotect
-munmap		-	munmap		i:ai	__munmap	munmap
+mprotect	-	mprotect	i:aUi	__mprotect	mprotect
+munmap		-	munmap		i:aU	__munmap	munmap
 open		-	open		Ci:siv	__libc_open __open open
 profil		-	profil		i:piii	__profil	profil
 ptrace		-	ptrace		i:iiii	ptrace
diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list
index e40f993495..4d4af84f9f 100644
--- a/sysdeps/unix/sysv/linux/syscalls.list
+++ b/sysdeps/unix/sysv/linux/syscalls.list
@@ -32,12 +32,12 @@  ioperm		-	ioperm		i:iii	ioperm
 iopl		-	iopl		i:i	iopl
 klogctl		EXTRA	syslog		i:isi	klogctl
 lchown		-	lchown		i:sii	__lchown	lchown
-mincore		-	mincore		i:anV	mincore
-mlock		-	mlock		i:bn	mlock
+mincore		-	mincore		i:aUV	mincore
+mlock		-	mlock		i:bU	mlock
 mlockall	-	mlockall	i:i	mlockall
-mount		EXTRA	mount		i:sssip	__mount	mount
-mremap		EXTRA	mremap		b:ainip	__mremap	mremap
-munlock		-	munlock		i:ai	munlock
+mount		EXTRA	mount		i:sssUp	__mount	mount
+mremap		EXTRA	mremap		b:aUUip	__mremap	mremap
+munlock		-	munlock		i:aU	munlock
 munlockall	-	munlockall	i:	munlockall
 nfsservctl	EXTRA	nfsservctl	i:ipp	__compat_nfsservctl	nfsservctl@GLIBC_2.0:GLIBC_2.28
 pipe		-	pipe		i:f	__pipe		pipe
@@ -46,7 +46,7 @@  pivot_root	EXTRA	pivot_root	i:ss	pivot_root
 prctl		EXTRA	prctl		i:iiiii	__prctl		prctl
 query_module	EXTRA	query_module	i:sipip	__compat_query_module	query_module@GLIBC_2.0:GLIBC_2.23
 quotactl	EXTRA	quotactl	i:isip	quotactl
-remap_file_pages -	remap_file_pages i:piiii	__remap_file_pages remap_file_pages
+remap_file_pages -	remap_file_pages i:pUiUi	__remap_file_pages remap_file_pages
 sched_getp	-	sched_getparam	i:ip	__sched_getparam	sched_getparam
 sched_gets	-	sched_getscheduler	i:i	__sched_getscheduler	sched_getscheduler
 sched_primax	-	sched_get_priority_max	i:i	__sched_get_priority_max	sched_get_priority_max
@@ -54,7 +54,7 @@  sched_primin	-	sched_get_priority_min	i:i	__sched_get_priority_min	sched_get_pri
 sched_setp	-	sched_setparam	i:ip	__sched_setparam	sched_setparam
 sched_sets	-	sched_setscheduler	i:iip	__sched_setscheduler	sched_setscheduler
 sched_yield	-	sched_yield	i:	__sched_yield	sched_yield
-sendfile	-	sendfile	i:iipi	sendfile
+sendfile	-	sendfile	i:iipU	sendfile
 sendfile64	-	sendfile64	i:iipi	sendfile64
 setfsgid	EXTRA	setfsgid	i:i	setfsgid
 setfsuid	EXTRA	setfsuid	i:i	setfsuid
diff --git a/sysdeps/unix/sysv/linux/x86_64/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
index 85f8f94820..3596273c94 100644
--- a/sysdeps/unix/sysv/linux/x86_64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
@@ -57,13 +57,30 @@ 
 #  define SYSCALL_ERROR_LABEL syscall_error
 # endif
 
+/* PSEUDO macros have 4 arguments.  */
+# define PSEUDOS_HAVE_4_ARGS 1
+
+# 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, ulong_arg_1, ulong_arg_2) \
+  .text;							      \
+  ENTRY (name)							      \
+    DO_CALL (syscall_name, args, ulong_arg_1, ulong_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 +88,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, ulong_arg_1, ulong_arg_2) \
+  .text;							      \
+  ENTRY (name)							      \
+    DO_CALL (syscall_name, args, ulong_arg_1, ulong_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 +107,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, ulong_arg_1, ulong_arg_2) \
+  .text;							\
+  ENTRY (name)							\
+    DO_CALL (syscall_name, args, ulong_arg_1, ulong_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,8 +191,10 @@ 
     Syscalls of more than 6 arguments are not supported.  */
 
 # undef	DO_CALL
-# define DO_CALL(syscall_name, args)		\
+# define DO_CALL(syscall_name, args, ulong_arg_1, ulong_arg_2) \
     DOARGS_##args				\
+    ZERO_EXTEND_##ulong_arg_1			\
+    ZERO_EXTEND_##ulong_arg_2			\
     movl $SYS_ify (syscall_name), %eax;		\
     syscall;
 
@@ -172,6 +206,14 @@ 
 # define DOARGS_5 DOARGS_4
 # define DOARGS_6 DOARGS_5
 
+# define ZERO_EXTEND_0 /* nothing */
+# define ZERO_EXTEND_1 /* nothing */
+# define ZERO_EXTEND_2 /* nothing */
+# define ZERO_EXTEND_3 /* nothing */
+# define ZERO_EXTEND_4 /* nothing */
+# define ZERO_EXTEND_5 /* nothing */
+# define ZERO_EXTEND_6 /* nothing */
+
 #else	/* !__ASSEMBLER__ */
 
 /* Registers clobbered by syscall.  */
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
index a37d520f86..b8a74ad2c2 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
@@ -26,7 +26,25 @@ 
 #undef LO_HI_LONG
 #define LO_HI_LONG(val) (val)
 
-#ifndef __ASSEMBLER__
+#ifdef __ASSEMBLER__
+# undef ZERO_EXTEND_1
+# define ZERO_EXTEND_1 movl %edi, %edi;
+# undef ZERO_EXTEND_2
+# define ZERO_EXTEND_2 movl %esi, %esi;
+# undef ZERO_EXTEND_3
+# define ZERO_EXTEND_3 movl %edx, %edx;
+# if SYSCALL_ULONG_ARG_1 == 4 || SYSCALL_ULONG_ARG_2 == 4
+#  undef DOARGS_4
+#  define DOARGS_4 movl %ecx, %r10d;
+# else
+#  undef ZERO_EXTEND_4
+#  define ZERO_EXTEND_4 movl %r10d, %r10d;
+# endif
+# undef ZERO_EXTEND_5
+# define ZERO_EXTEND_5 movl %r8d, %r8d;
+# undef ZERO_EXTEND_6
+# define ZERO_EXTEND_6 movl %r9d, %r9d;
+#else /* !__ASSEMBLER__ */
 # undef ARGIFY
 /* Enforce zero-extension for pointers and array system call arguments.
    For integer types, extend to int64_t (the full register) using a