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

Message ID 20200422160946.GB342519@gmail.com
State Committed
Headers
Series V3 [PATCH 1/2] Add SYSCALL_ULONG_ARG_[12] to pass long to syscall [BZ #25810] |

Commit Message

H.J. Lu April 22, 2020, 4:09 p.m. UTC
  On Wed, Apr 22, 2020 at 12:42:37PM +0200, 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)

Fixed.

> 
> >  # 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”

Fixed.

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

Fixed.

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

I didn't notice any significant build timing change.

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

Fixed.

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

I updated comments of SYSCALL_ULONG_ARG_1 and SYSCALL_ULONG_ARG_2 in
syscall-template.S.

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

Fixed.

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

Fixed.

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

I updated readlink and readlinkat.  read/write are implemented as inlined
SYSCALLs.

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

This comment is C specific.  I added

/* Zero-extend 32-bit unsigned long int arguments to 64 bits.  */

to the newly added ZERO_EXTEND_X micros.

Here is the updated patch.  OK for master?

Thanks.


H.J.
---
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 int 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, which is zero-extended to
64-bit types.  SYSCALL_ULONG_ARG_1 and SYSCALL_ULONG_ARG_2 are passed
to syscall-template.S for the first and the second unsigned long int
arguments if PSEUDOS_HAVE_ULONG_INDICES 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               | 24 +++++++
 sysdeps/unix/syscall-template.S             | 49 +++++++++++++-
 sysdeps/unix/syscalls.list                  |  8 +--
 sysdeps/unix/sysv/linux/syscalls.list       | 16 ++---
 sysdeps/unix/sysv/linux/x86_64/sysdep.h     | 71 +++++++++++++++++----
 sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h | 21 +++++-
 6 files changed, 159 insertions(+), 30 deletions(-)
  

Patch

diff --git a/sysdeps/unix/make-syscalls.sh b/sysdeps/unix/make-syscalls.sh
index c07626677f..4f6c3490a2 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 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,27 @@  while read file srcfile caller syscall args strong weak; do
   ?:?????????) nargs=9;;
   esac
 
+  # Derive the unsigned long int arguments from the argument signature
+  ulong_arg_1=0
+  ulong_arg_2=0
+  ulong_count=0
+  for U in $(echo $args | sed -e "s/.*:/:/" | grep -ob U)
+  do
+    ulong_count=$(expr $ulong_count + 1)
+    ulong_arg=$(echo $U | sed -e "s/:U//")
+    case $ulong_count in
+    1)
+      ulong_arg_1=$ulong_arg
+      ;;
+    2)
+      ulong_arg_2=$ulong_arg
+      ;;
+    *)
+      echo >&2 "$0: Too many unsigned long int arguments for syscall ($strong $weak)"
+      exit 2
+    esac
+  done
+
   # Make sure only the first syscall rule is used, if multiple dirs
   # define the same syscall.
   echo ''
@@ -245,6 +267,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..f807a8603f 100644
--- a/sysdeps/unix/syscall-template.S
+++ b/sysdeps/unix/syscall-template.S
@@ -25,6 +25,12 @@ 
    defining a few macros:
 	SYSCALL_NAME		syscall name
 	SYSCALL_NARGS		number of arguments this call takes
+	SYSCALL_ULONG_ARG_1	the first unsigned long int argument this
+				call takes.  0 means that there are no
+				unsigned long int arguments.
+	SYSCALL_ULONG_ARG_2	the second unsigned long int argument this
+				call takes.  0 means that there is at most
+				one unsigned long int argument.
 	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 +50,31 @@ 
 /* 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_ULONG_INDICES is defined, PSEUDO and T_PSEUDO macros
+   have 2 extra arguments for unsigned long int arguments:
+     Extra argument 1: Position of the first unsigned long int argument.
+     Extra argument 2: Position of the second unsigned long int argument.
+ */
+#ifndef PSEUDOS_HAVE_ULONG_INDICES
+# 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 +84,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 +99,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 +113,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..0cf290076d 100644
--- a/sysdeps/unix/syscalls.list
+++ b/sysdeps/unix/syscalls.list
@@ -37,16 +37,16 @@  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
 read		-	read		Ci:ibn	__libc_read	__read read
-readlink	-	readlink	i:spi	__readlink	readlink
+readlink	-	readlink	i:spU	__readlink	readlink
 readv		-	readv		Ci:ipi	__readv		readv
 reboot		-	reboot		i:i	reboot
 recv		-	recv		Ci:ibni	__libc_recv	recv
diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list
index e40f993495..1b1010d4c8 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
@@ -71,7 +71,7 @@  chown		-	chown		i:sii	__libc_chown	__chown chown
 fchownat	-	fchownat	i:isiii	fchownat
 linkat		-	linkat		i:isisi	linkat
 mkdirat		-	mkdirat		i:isi	mkdirat
-readlinkat	-	readlinkat	i:issi	readlinkat
+readlinkat	-	readlinkat	i:issU	readlinkat
 symlinkat	-	symlinkat	i:sis	symlinkat
 unlinkat	-	unlinkat	i:isi	unlinkat
 
diff --git a/sysdeps/unix/sysv/linux/x86_64/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
index 85f8f94820..bf36875477 100644
--- a/sysdeps/unix/sysv/linux/x86_64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
@@ -57,13 +57,31 @@ 
 #  define SYSCALL_ERROR_LABEL syscall_error
 # endif
 
+/* PSEUDO and T_PSEUDO macros have 2 extra arguments for unsigned long
+   int arguments.  */
+# define PSEUDOS_HAVE_ULONG_INDICES 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 +89,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 +108,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 +192,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 +207,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..62e6f8fe11 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/sysdep.h
@@ -26,7 +26,26 @@ 
 #undef LO_HI_LONG
 #define LO_HI_LONG(val) (val)
 
-#ifndef __ASSEMBLER__
+#ifdef __ASSEMBLER__
+/* Zero-extend 32-bit unsigned long int arguments to 64 bits.  */
+# 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