Bug#583911: libc6: syscall() doesn't support 6 args system calls on alpha
Package: libc6
Version: 2.11.1-1
Severity: normal
Tags: patch upstream
Some system calls, such as mmap, take 6 arguments. Unfortunatelly, the
syscall function as provided by the glibc doesn't fill the 6th argument,
and actually, the system call ends up being called with the 5th argument
copied in 6th position (technically, that's not what happens, as the args
are shifted at the end, but well).
The attached patch /should/ work. (untested).
I'm also attaching a testcase that fails on alpha because of this bug and
should work once the bug is fixed.
Cheers
Mike
-- System Information:
Debian Release: squeeze/sid
APT prefers unstable
APT policy: (500, 'unstable'), (1, 'experimental')
Architecture: amd64 (x86_64)
Kernel: Linux 2.6.31-1-amd64 (SMP w/2 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Versions of packages libc6 depends on:
ii libc-bin 2.11.1-1 Embedded GNU C Library: Binaries
ii libgcc1 1:4.5.0-4 GCC support library
libc6 recommends no packages.
Versions of packages libc6 suggests:
ii debconf [debconf-2.0] 1.5.32 Debian configuration management sy
pn glibc-doc <none> (no description available)
ii locales 2.11.1-1 Embedded GNU C Library: National L
-- debconf information excluded
--- ./ports/sysdeps/unix/sysv/linux/alpha/syscall.S 2008-11-26 09:02:02.000000000 +0100
+++ /tmp/syscall.S 2010-05-31 16:09:54.952364393 +0200
@@ -31,13 +31,13 @@
*
* Usage:
*
- * long syscall(syscall_number, arg1, arg2, arg3, arg4, arg5)
+ * long syscall(syscall_number, arg1, arg2, arg3, arg4, arg5, arg6)
*
* syscall_number = the index of the system call we're invoking
- * arg1-arg5 = up to 5 integer arguments to the system call
+ * arg1-arg6 = up to 6 integer arguments to the system call
*
* We need to do some arg shifting: the kernel expects the
- * syscall number in v0 and the first five args in a0-a4.
+ * syscall number in v0 and the first six args in a0-a5.
*
*/
@@ -60,6 +60,7 @@
mov a3, a2
mov a4, a3
mov a5, a4
+ ldq a5,0(sp) /* arg6 -> a5 */
call_pal PAL_callsys /* Invoke system call */
bne a3, $error
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <fcntl.h>
static int pagesize;
#if defined(SYS_mmap) || defined(SYS_mmap2)
static inline
void *_mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset)
{
#ifdef SYS_mmap2
return (caddr_t) syscall(SYS_mmap2, addr, length, prot, flags, fd, offset / 4096);
#warning mmap2
#else
return (caddr_t) syscall(SYS_mmap, addr, length, prot, flags, fd, offset);
#warning mmap
#endif
}
#define mmap _mmap
#endif
int main(void) {
char *buf;
int i, fd, ret = 0;
pagesize = sysconf(_SC_PAGESIZE);
fd = open("/tmp/testmmap", O_CREAT | O_RDWR, 0644);
ftruncate(fd, pagesize * 2);
buf = mmap((void *)0, pagesize, PROT_WRITE, MAP_SHARED, fd, pagesize);
if (buf == MAP_FAILED) {
perror("plop");
ret = 1;
goto end;
}
for (i = 0; i < pagesize; i++)
buf[i] = (char) i;
munmap(buf, pagesize);
close(fd);
buf = malloc(pagesize);
fd = open("/tmp/testmmap", O_RDONLY);
lseek(fd, pagesize, SEEK_SET);
read(fd, buf, pagesize);
for (i = 0; i < pagesize; i++)
if (buf[i] != (char) i) {
ret = 1;
break;
}
end:
close(fd);
unlink("/tmp/testmmap");
printf("%s\n", ret == 0 ? "ok" : "fail");
return 0;
}
Reply to: