mailing list of musl libc
 help / color / mirror / code / Atom feed
* [PATCH] remaining steps for time64 switchover
@ 2019-10-21  2:46 Rich Felker
  2019-10-21 12:43 ` Rich Felker
                   ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: Rich Felker @ 2019-10-21  2:46 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 1710 bytes --]

The attached patch series on top of present git master (commit
9b2921bea1d5017832e1b45d1fd64220047a9802) should contain all changes
needed for fully working time64 on 32-bit archs, in a form that's
plausibly ready for commit (no makeshift hacks just to get things
demonstrably working). The one omission I'm aware of is what to do
with struct utmpx, which is not actually used at present in any libc
interfaces and thus not part of the ABI surface of libc. That will be
addressed in a separate thread.

Comments and basic testing are welcome at this point. It should be
possible to build for any of the 32-bit archs, but I have only tested
build for a few and only tested execution on i386 and sh.

Some useful checks for anyone wanting to help test, especially on the
more obscure archs:

- Any new failures in libc-test?

- Any failures when subbing the new libc.so/ldso into an existing
  ecosystem of existing (time32) software?

- Anything look odd about time-related types? timeval/timespec members
  at positions that aren't naturally aligned?

- Does software built against new libc headers basically work?

- Does it work with clock set post-2038?

Being that only the final switchover patches are a big step to take,
I'll probably start pushing the earlier patches in this series pretty
soon, but want to give a little time for more eyes on them.

Note that the final switchovers are split out by arch right now,
mainly because that was the way that made sense to create them (sed to
replace arch name, apply to next arch, fix rejects manually) but also
because it helps compare/review them against each other. It would be
possible to squash them together for final merge but I probably won't.

Rich

[-- Attachment #2: 0001-add-time64-symbol-name-redirects-to-public-headers-u.patch --]
[-- Type: text/plain, Size: 12538 bytes --]

From 31283f25bcfa71d3eeaabc591d0eb3e2960980e2 Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Wed, 31 Jul 2019 15:24:58 -0400
Subject: [PATCH 01/17] add time64 symbol name redirects to public headers,
 under arch control

a _REDIR_TIME64 macro is introduced, which the arch's alltypes.h is
expected to define, to control redirection of symbol names for
interfaces that involve time_t and derived types. this ensures that
object files will only be linked to libc interfaces matching the ABI
whose headers they were compiled against.

along with time32 compat shims, which will be introduced separately,
the redirection also makes it possible for a single libc (static or
shared) to be used with object files produced with either the old
(32-bit time_t) headers or the new ones after 64-bit time_t switchover
takes place. mixing of such object files (or shared libraries) in the
same program will also be possible, but must be done with care; ABI
between libc and a consumer of the libc interfaces is guaranteed to
match by the the symbol name redirection, but pairwise ABI between
consumers of libc that define interfaces between each other in terms
of time_t is not guaranteed to match.

this change adds a dependency on an additional "GNU C" feature to the
public headers for existing 32-bit archs, which is generally
undesirable; however, the feature is one which glibc has depended on
for a long time, and thus which any viable alternative compiler is
going to need to provide. 64-bit archs are not affected, nor will
future 32-bit archs be, regardless of whether they are "new" on the
kernel side (e.g. riscv32) or just newly-added (e.g. a new sparc or
xtensa port). the same applies to newly-added ABIs for existing
machine-level archs.
---
 include/aio.h          |  4 ++++
 include/features.h     |  2 ++
 include/mqueue.h       |  5 +++++
 include/poll.h         |  6 ++++++
 include/pthread.h      | 10 ++++++++++
 include/sched.h        |  4 ++++
 include/semaphore.h    |  4 ++++
 include/signal.h       |  8 ++++++++
 include/sys/resource.h |  4 ++++
 include/sys/select.h   |  5 +++++
 include/sys/sem.h      |  6 ++++++
 include/sys/socket.h   |  6 ++++++
 include/sys/stat.h     |  9 +++++++++
 include/sys/time.h     | 14 ++++++++++++++
 include/sys/timeb.h    |  6 ++++++
 include/sys/timerfd.h  |  5 +++++
 include/sys/timex.h    |  5 +++++
 include/sys/wait.h     |  7 +++++++
 include/threads.h      |  6 ++++++
 include/time.h         | 28 ++++++++++++++++++++++++++++
 include/utime.h        |  6 ++++++
 21 files changed, 150 insertions(+)

diff --git a/include/aio.h b/include/aio.h
index 19bc28a9..453c41b7 100644
--- a/include/aio.h
+++ b/include/aio.h
@@ -62,6 +62,10 @@ int lio_listio(int, struct aiocb *__restrict const *__restrict, int, struct sige
 #define off64_t off_t
 #endif
 
+#if _REDIR_TIME64
+__REDIR(aio_suspend, __aio_suspend_time64);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/features.h b/include/features.h
index f4d651ef..85cfb72a 100644
--- a/include/features.h
+++ b/include/features.h
@@ -35,4 +35,6 @@
 #define _Noreturn
 #endif
 
+#define __REDIR(x,y) __typeof__(x) x __asm__(#y)
+
 #endif
diff --git a/include/mqueue.h b/include/mqueue.h
index f5cbe796..0c807ea0 100644
--- a/include/mqueue.h
+++ b/include/mqueue.h
@@ -30,6 +30,11 @@ ssize_t mq_timedreceive(mqd_t, char *__restrict, size_t, unsigned *__restrict, c
 int mq_timedsend(mqd_t, const char *, size_t, unsigned, const struct timespec *);
 int mq_unlink(const char *);
 
+#if _REDIR_TIME64
+__REDIR(mq_timedreceive, __mq_timedreceive_time64);
+__REDIR(mq_timedsend, __mq_timedsend_time64);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/poll.h b/include/poll.h
index daccc760..472e4b84 100644
--- a/include/poll.h
+++ b/include/poll.h
@@ -44,6 +44,12 @@ int poll (struct pollfd *, nfds_t, int);
 int ppoll(struct pollfd *, nfds_t, const struct timespec *, const sigset_t *);
 #endif
 
+#if _REDIR_TIME64
+#ifdef _GNU_SOURCE
+__REDIR(ppoll, __ppoll_time64);
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/pthread.h b/include/pthread.h
index e238321b..984db680 100644
--- a/include/pthread.h
+++ b/include/pthread.h
@@ -224,6 +224,16 @@ int pthread_tryjoin_np(pthread_t, void **);
 int pthread_timedjoin_np(pthread_t, void **, const struct timespec *);
 #endif
 
+#if _REDIR_TIME64
+__REDIR(pthread_mutex_timedlock, __pthread_mutex_timedlock_time64);
+__REDIR(pthread_cond_timedwait, __pthread_cond_timedwait_time64);
+__REDIR(pthread_rwlock_timedrdlock, __pthread_rwlock_timedrdlock_time64);
+__REDIR(pthread_rwlock_timedwrlock, __pthread_rwlock_timedwrlock_time64);
+#ifdef _GNU_SOURCE
+__REDIR(pthread_timedjoin_np, __pthread_timedjoin_np_time64);
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sched.h b/include/sched.h
index 7e470d3a..c3a8d49a 100644
--- a/include/sched.h
+++ b/include/sched.h
@@ -133,6 +133,10 @@ __CPU_op_func_S(XOR, ^)
 
 #endif
 
+#if _REDIR_TIME64
+__REDIR(sched_rr_get_interval, __sched_rr_get_interval_time64);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/semaphore.h b/include/semaphore.h
index 277c47d6..3690f496 100644
--- a/include/semaphore.h
+++ b/include/semaphore.h
@@ -29,6 +29,10 @@ int    sem_trywait(sem_t *);
 int    sem_unlink(const char *);
 int    sem_wait(sem_t *);
 
+#if _REDIR_TIME64
+__REDIR(sem_timedwait, __sem_timedwait_time64);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/signal.h b/include/signal.h
index 5c48cb83..fbdf667b 100644
--- a/include/signal.h
+++ b/include/signal.h
@@ -271,6 +271,14 @@ typedef int sig_atomic_t;
 void (*signal(int, void (*)(int)))(int);
 int raise(int);
 
+#if _REDIR_TIME64
+#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
+ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
+ || defined(_BSD_SOURCE)
+__REDIR(sigtimedwait, __sigtimedwait_time64);
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/resource.h b/include/sys/resource.h
index 70d793d5..e0c86ae3 100644
--- a/include/sys/resource.h
+++ b/include/sys/resource.h
@@ -104,6 +104,10 @@ int prlimit(pid_t, int, const struct rlimit *, struct rlimit *);
 #define rlim64_t rlim_t
 #endif
 
+#if _REDIR_TIME64
+__REDIR(getrusage, __getrusage_time64);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/select.h b/include/sys/select.h
index d34cbf10..b3bab1d5 100644
--- a/include/sys/select.h
+++ b/include/sys/select.h
@@ -35,6 +35,11 @@ int pselect (int, fd_set *__restrict, fd_set *__restrict, fd_set *__restrict, co
 #define NFDBITS (8*(int)sizeof(long))
 #endif
 
+#if _REDIR_TIME64
+__REDIR(select, __select_time64);
+__REDIR(pselect, __pselect_time64);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/sem.h b/include/sys/sem.h
index e6161e51..a747784e 100644
--- a/include/sys/sem.h
+++ b/include/sys/sem.h
@@ -60,6 +60,12 @@ int semop(int, struct sembuf *, size_t);
 int semtimedop(int, struct sembuf *, size_t, const struct timespec *);
 #endif
 
+#if _REDIR_TIME64
+#ifdef _GNU_SOURCE
+__REDIR(semtimedop, __semtimedop_time64);
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/socket.h b/include/sys/socket.h
index 8692efa7..318a98ef 100644
--- a/include/sys/socket.h
+++ b/include/sys/socket.h
@@ -350,6 +350,12 @@ int setsockopt (int, int, int, const void *, socklen_t);
 
 int sockatmark (int);
 
+#if _REDIR_TIME64
+#ifdef _GNU_SOURCE
+__REDIR(recvmmsg, __recvmmsg_time64);
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/stat.h b/include/sys/stat.h
index 9d096624..10d446c4 100644
--- a/include/sys/stat.h
+++ b/include/sys/stat.h
@@ -110,6 +110,15 @@ int lchmod(const char *, mode_t);
 #define off64_t off_t
 #endif
 
+#if _REDIR_TIME64
+__REDIR(stat, __stat_time64);
+__REDIR(fstat, __fstat_time64);
+__REDIR(lstat, __lstat_time64);
+__REDIR(fstatat, __fstatat_time64);
+__REDIR(futimens, __futimens_time64);
+__REDIR(utimensat, __utimensat_time64);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/time.h b/include/sys/time.h
index c5cab814..cdc67ef6 100644
--- a/include/sys/time.h
+++ b/include/sys/time.h
@@ -56,6 +56,20 @@ int adjtime (const struct timeval *, struct timeval *);
 	(void)0 )
 #endif
 
+#if _REDIR_TIME64
+__REDIR(gettimeofday, __gettimeofday_time64);
+__REDIR(getitimer, __getitimer_time64);
+__REDIR(setitimer, __setitimer_time64);
+__REDIR(utimes, __utimes_time64);
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+__REDIR(futimes, __futimes_time64);
+__REDIR(futimesat, __futimesat_time64);
+__REDIR(lutimes, __lutimes_time64);
+__REDIR(settimeofday, __settimeofday_time64);
+__REDIR(adjtime, __adjtime64);
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/timeb.h b/include/sys/timeb.h
index 108c1f5c..628239b7 100644
--- a/include/sys/timeb.h
+++ b/include/sys/timeb.h
@@ -4,6 +4,8 @@
 extern "C" {
 #endif
 
+#include <features.h>
+
 #define __NEED_time_t
 
 #include <bits/alltypes.h>
@@ -16,6 +18,10 @@ struct timeb {
 
 int ftime(struct timeb *);
 
+#if _REDIR_TIME64
+__REDIR(ftime, __ftime64);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/timerfd.h b/include/sys/timerfd.h
index 2794d36a..1b832cdd 100644
--- a/include/sys/timerfd.h
+++ b/include/sys/timerfd.h
@@ -20,6 +20,11 @@ int timerfd_create(int, int);
 int timerfd_settime(int, int, const struct itimerspec *, struct itimerspec *);
 int timerfd_gettime(int, struct itimerspec *);
 
+#if _REDIR_TIME64
+__REDIR(timerfd_settime, __timerfd_settime64);
+__REDIR(timerfd_gettime, __timerfd_gettime64);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/timex.h b/include/sys/timex.h
index 2e688880..8b417e1b 100644
--- a/include/sys/timex.h
+++ b/include/sys/timex.h
@@ -91,6 +91,11 @@ struct timex {
 int adjtimex(struct timex *);
 int clock_adjtime(clockid_t, struct timex *);
 
+#if _REDIR_TIME64
+__REDIR(adjtimex, __adjtimex_time64);
+__REDIR(clock_adjtime, __clock_adjtime64);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/sys/wait.h b/include/sys/wait.h
index 50c5c709..d9adbdec 100644
--- a/include/sys/wait.h
+++ b/include/sys/wait.h
@@ -53,6 +53,13 @@ pid_t wait4 (pid_t, int *, int, struct rusage *);
 #define WIFSIGNALED(s) (((s)&0xffff)-1U < 0xffu)
 #define WIFCONTINUED(s) ((s) == 0xffff)
 
+#if _REDIR_TIME64
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+__REDIR(wait3, __wait3_time64);
+__REDIR(wait4, __wait4_time64);
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/threads.h b/include/threads.h
index 8122b3b1..52ec3100 100644
--- a/include/threads.h
+++ b/include/threads.h
@@ -80,6 +80,12 @@ void tss_delete(tss_t);
 int tss_set(tss_t, void *);
 void *tss_get(tss_t);
 
+#if _REDIR_TIME64
+__REDIR(thrd_sleep, __thrd_sleep_time64);
+__REDIR(mtx_timedlock, __mtx_timedlock_time64);
+__REDIR(cnd_timedwait, __cnd_timedwait_time64);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/time.h b/include/time.h
index 672b3fc3..5494df18 100644
--- a/include/time.h
+++ b/include/time.h
@@ -130,6 +130,34 @@ int stime(const time_t *);
 time_t timegm(struct tm *);
 #endif
 
+#if _REDIR_TIME64
+__REDIR(time, __time64);
+__REDIR(difftime, __difftime64);
+__REDIR(mktime, __mktime64);
+__REDIR(gmtime, __gmtime64);
+__REDIR(localtime, __localtime64);
+__REDIR(ctime, __ctime64);
+__REDIR(timespec_get, __timespec_get_time64);
+#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
+ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
+ || defined(_BSD_SOURCE)
+__REDIR(gmtime_r, __gmtime64_r);
+__REDIR(localtime_r, __localtime64_r);
+__REDIR(ctime_r, __ctime64_r);
+__REDIR(nanosleep, __nanosleep_time64);
+__REDIR(clock_getres, __clock_getres_time64);
+__REDIR(clock_gettime, __clock_gettime64);
+__REDIR(clock_settime, __clock_settime64);
+__REDIR(clock_nanosleep, __clock_nanosleep_time64);
+__REDIR(timer_settime, __timer_settime64);
+__REDIR(timer_gettime, __timer_gettime64);
+#endif
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+__REDIR(stime, __stime64);
+__REDIR(timegm, __timegm_time64);
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/utime.h b/include/utime.h
index dd5ff927..5755bd53 100644
--- a/include/utime.h
+++ b/include/utime.h
@@ -5,6 +5,8 @@
 extern "C" {
 #endif
 
+#include <features.h>
+
 #define __NEED_time_t
 
 #include <bits/alltypes.h>
@@ -16,6 +18,10 @@ struct utimbuf {
 
 int utime (const char *, const struct utimbuf *);
 
+#if _REDIR_TIME64
+__REDIR(utime, __utime64);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.21.0


[-- Attachment #3: 0002-prepare-struct-sched_param-for-change-in-time_t-defi.patch --]
[-- Type: text/plain, Size: 1004 bytes --]

From 50e933db1e4ef0d4d6891e98a65b04f425e4a5aa Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Fri, 9 Aug 2019 22:20:55 -0400
Subject: [PATCH 02/17] prepare struct sched_param for change in time_t
 definition

the time_t members in struct sched_param are just reserved space to
preserve size and alignment. when time_t changes to 64-bit on 32-bit
archs, this structure should not change.

make definition conditional on _REDIR_TIME64 to match the size of the
old time_t, which can be assumed to be long if _REDIR_TIME64 is
defined.
---
 include/sched.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/include/sched.h b/include/sched.h
index c3a8d49a..822f464e 100644
--- a/include/sched.h
+++ b/include/sched.h
@@ -19,10 +19,14 @@ extern "C" {
 struct sched_param {
 	int sched_priority;
 	int __reserved1;
+#if _REDIR_TIME64
+	long __reserved2[4];
+#else
 	struct {
 		time_t __reserved1;
 		long __reserved2;
 	} __reserved2[2];
+#endif
 	int __reserved3;
 };
 
-- 
2.21.0


[-- Attachment #4: 0003-disable-lfs64-aliases-for-remapped-time64-functions.patch --]
[-- Type: text/plain, Size: 2765 bytes --]

From dfdb7418209a949625444322800fbc647d75f33f Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Thu, 1 Aug 2019 00:56:48 -0400
Subject: [PATCH 03/17] disable lfs64 aliases for remapped time64 functions

these functions cannot provide the glibc lfs64-ABI-compatible symbols
when time_t differs from what it was in that ABI. instead, the aliases
need to be provided by the time32 compat shims or through some other
mechanism.
---
 src/aio/aio_suspend.c | 2 ++
 src/stat/__xstat.c    | 4 ++++
 src/stat/fstat.c      | 2 ++
 src/stat/fstatat.c    | 2 ++
 src/stat/lstat.c      | 2 ++
 src/stat/stat.c       | 2 ++
 6 files changed, 14 insertions(+)

diff --git a/src/aio/aio_suspend.c b/src/aio/aio_suspend.c
index 9b24b6af..34b66f87 100644
--- a/src/aio/aio_suspend.c
+++ b/src/aio/aio_suspend.c
@@ -73,4 +73,6 @@ int aio_suspend(const struct aiocb *const cbs[], int cnt, const struct timespec
 	}
 }
 
+#if !_REDIR_TIME64
 weak_alias(aio_suspend, aio_suspend64);
+#endif
diff --git a/src/stat/__xstat.c b/src/stat/__xstat.c
index f6303430..630936a0 100644
--- a/src/stat/__xstat.c
+++ b/src/stat/__xstat.c
@@ -1,5 +1,7 @@
 #include <sys/stat.h>
 
+#if !_REDIR_TIME64
+
 int __fxstat(int ver, int fd, struct stat *buf)
 {
 	return fstat(fd, buf);
@@ -25,6 +27,8 @@ weak_alias(__fxstatat, __fxstatat64);
 weak_alias(__lxstat, __lxstat64);
 weak_alias(__xstat, __xstat64);
 
+#endif
+
 int __xmknod(int ver, const char *path, mode_t mode, dev_t *dev)
 {
 	return mknod(path, mode, *dev);
diff --git a/src/stat/fstat.c b/src/stat/fstat.c
index 07f9a5de..9bbb46de 100644
--- a/src/stat/fstat.c
+++ b/src/stat/fstat.c
@@ -10,4 +10,6 @@ int fstat(int fd, struct stat *st)
 	return fstatat(fd, "", st, AT_EMPTY_PATH);
 }
 
+#if !_REDIR_TIME64
 weak_alias(fstat, fstat64);
+#endif
diff --git a/src/stat/fstatat.c b/src/stat/fstatat.c
index d915fa10..bf0a554c 100644
--- a/src/stat/fstatat.c
+++ b/src/stat/fstatat.c
@@ -126,4 +126,6 @@ int fstatat(int fd, const char *restrict path, struct stat *restrict st, int fla
 	return __syscall_ret(ret);
 }
 
+#if !_REDIR_TIME64
 weak_alias(fstatat, fstatat64);
+#endif
diff --git a/src/stat/lstat.c b/src/stat/lstat.c
index 9f95218a..6fe004de 100644
--- a/src/stat/lstat.c
+++ b/src/stat/lstat.c
@@ -6,4 +6,6 @@ int lstat(const char *restrict path, struct stat *restrict buf)
 	return fstatat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
 }
 
+#if !_REDIR_TIME64
 weak_alias(lstat, lstat64);
+#endif
diff --git a/src/stat/stat.c b/src/stat/stat.c
index 528870d2..ea70efc4 100644
--- a/src/stat/stat.c
+++ b/src/stat/stat.c
@@ -6,4 +6,6 @@ int stat(const char *restrict path, struct stat *restrict buf)
 	return fstatat(AT_FDCWD, path, buf, 0);
 }
 
+#if !_REDIR_TIME64
 weak_alias(stat, stat64);
+#endif
-- 
2.21.0


[-- Attachment #5: 0004-make-fstatat-fill-in-old-time32-stat-fields-too.patch --]
[-- Type: text/plain, Size: 2015 bytes --]

From 7b250ae334fd8d6b15468c6ea3e068b4eb962ea1 Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Thu, 1 Aug 2019 21:33:57 -0400
Subject: [PATCH 04/17] make fstatat fill in old time32 stat fields too

here _REDIR_TIME64 is used as an indication that there's an old ABI,
and thereby the old time32 timespec fields of struct stat.

keeping struct stat compatible and providing both versions of the
timespec fields is done so that ftw/nftw does not need painful compat
shims, and (more importantly) so that similar interfaces between pairs
of libc consumers (applications/libraries) will be less likely to
break when one has been rebuilt for time64 but the other has not.
---
 src/stat/fstatat.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/src/stat/fstatat.c b/src/stat/fstatat.c
index bf0a554c..de165b5c 100644
--- a/src/stat/fstatat.c
+++ b/src/stat/fstatat.c
@@ -57,6 +57,14 @@ static int fstatat_statx(int fd, const char *restrict path, struct stat *restric
 		.st_mtim.tv_nsec = stx.stx_mtime.tv_nsec,
 		.st_ctim.tv_sec = stx.stx_ctime.tv_sec,
 		.st_ctim.tv_nsec = stx.stx_ctime.tv_nsec,
+#if _REDIR_TIME64
+		.__st_atim32.tv_sec = stx.stx_atime.tv_sec,
+		.__st_atim32.tv_nsec = stx.stx_atime.tv_nsec,
+		.__st_mtim32.tv_sec = stx.stx_mtime.tv_sec,
+		.__st_mtim32.tv_nsec = stx.stx_mtime.tv_nsec,
+		.__st_ctim32.tv_sec = stx.stx_ctime.tv_sec,
+		.__st_ctim32.tv_nsec = stx.stx_ctime.tv_nsec,
+#endif
 	};
 	return 0;
 }
@@ -110,6 +118,14 @@ static int fstatat_kstat(int fd, const char *restrict path, struct stat *restric
 		.st_mtim.tv_nsec = kst.st_mtime_nsec,
 		.st_ctim.tv_sec = kst.st_ctime_sec,
 		.st_ctim.tv_nsec = kst.st_ctime_nsec,
+#if _REDIR_TIME64
+		.__st_atim32.tv_sec = kst.st_atime_sec,
+		.__st_atim32.tv_nsec = kst.st_atime_nsec,
+		.__st_mtim32.tv_sec = kst.st_mtime_sec,
+		.__st_mtim32.tv_nsec = kst.st_mtime_nsec,
+		.__st_ctim32.tv_sec = kst.st_ctime_sec,
+		.__st_ctim32.tv_nsec = kst.st_ctime_nsec,
+#endif
 	};
 
 	return 0;
-- 
2.21.0


[-- Attachment #6: 0005-add-time32-ABI-compat-shims-compat-source-tree.patch --]
[-- Type: text/plain, Size: 50333 bytes --]

From 2807a6f11b4c999dee9c02283bba77bfb2b6cd5f Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Fri, 2 Aug 2019 15:52:42 -0400
Subject: [PATCH 05/17] add time32 ABI compat shims, compat source tree

these files provide the symbols for the traditional 32-bit time_t ABI
on existing 32-bit archs by wrapping the real, internal versions of
the corresponding functions, which always work with 64-bit time_t.
they are written to be as agnostic as possible to the implementation
details of the real functions, so that they can be written once and
mostly forgotten, but they are aware of details of the old (and
sometimes new) ABI, which is okay since ABI is fixed and cannot
change.

a new compat tree is added, separate from src, which the Makefile does
not see or use now, but which archs will be able to add to the build
process. we could also consider moving other things that are compat
shims here, like functions which are purely for glibc-ABI-compat, with
the goal of making it optional or just cleaning up the main src tree
to make the distinction between actual implementation/API files and
ABI-compat shims clear.
---
 compat/time32/__xstat.c                       | 22 +++++
 compat/time32/adjtime32.c                     | 21 +++++
 compat/time32/adjtimex_time32.c               | 37 ++++++++
 compat/time32/aio_suspend_time32.c            | 11 +++
 compat/time32/clock_adjtime32.c               | 70 ++++++++++++++
 compat/time32/clock_getres_time32.c           | 13 +++
 compat/time32/clock_gettime32.c               | 18 ++++
 compat/time32/clock_nanosleep_time32.c        | 15 +++
 compat/time32/clock_settime32.c               |  9 ++
 compat/time32/cnd_timedwait_time32.c          |  9 ++
 compat/time32/ctime32.c                       |  7 ++
 compat/time32/ctime32_r.c                     |  7 ++
 compat/time32/difftime32.c                    |  7 ++
 compat/time32/fstat_time32.c                  | 17 ++++
 compat/time32/fstatat_time32.c                | 17 ++++
 compat/time32/ftime32.c                       | 25 +++++
 compat/time32/futimens_time32.c               | 10 ++
 compat/time32/futimes_time32.c                | 12 +++
 compat/time32/futimesat_time32.c              | 12 +++
 compat/time32/getitimer_time32.c              | 15 +++
 compat/time32/getrusage_time32.c              | 39 ++++++++
 compat/time32/gettimeofday_time32.c           | 19 ++++
 compat/time32/gmtime32.c                      |  7 ++
 compat/time32/gmtime32_r.c                    |  7 ++
 compat/time32/localtime32.c                   |  7 ++
 compat/time32/localtime32_r.c                 |  7 ++
 compat/time32/lstat_time32.c                  | 17 ++++
 compat/time32/lutimes_time32.c                | 12 +++
 compat/time32/mktime32.c                      | 16 ++++
 compat/time32/mq_timedreceive_time32.c        |  9 ++
 compat/time32/mq_timedsend_time32.c           |  9 ++
 compat/time32/mtx_timedlock_time32.c          |  9 ++
 compat/time32/nanosleep_time32.c              | 15 +++
 compat/time32/ppoll_time32.c                  | 10 ++
 compat/time32/pselect_time32.c                |  9 ++
 compat/time32/pthread_cond_timedwait_time32.c |  9 ++
 .../time32/pthread_mutex_timedlock_time32.c   |  9 ++
 .../pthread_rwlock_timedrdlock_time32.c       |  9 ++
 .../pthread_rwlock_timedwrlock_time32.c       |  9 ++
 compat/time32/pthread_timedjoin_np_time32.c   | 10 ++
 compat/time32/recvmmsg_time32.c               | 10 ++
 compat/time32/sched_rr_get_interval_time32.c  | 13 +++
 compat/time32/select_time32.c                 | 10 ++
 compat/time32/sem_timedwait_time32.c          |  9 ++
 compat/time32/semtimedop_time32.c             | 10 ++
 compat/time32/setitimer_time32.c              | 23 +++++
 compat/time32/settimeofday_time32.c           | 10 ++
 compat/time32/sigtimedwait_time32.c           |  9 ++
 compat/time32/stat_time32.c                   | 17 ++++
 compat/time32/stime32.c                       |  8 ++
 compat/time32/thrd_sleep_time32.c             | 16 ++++
 compat/time32/time32.c                        | 15 +++
 compat/time32/time32.h                        | 91 +++++++++++++++++++
 compat/time32/time32gm.c                      | 15 +++
 compat/time32/timer_gettime32.c               | 15 +++
 compat/time32/timer_settime32.c               | 25 +++++
 compat/time32/timerfd_gettime32.c             | 16 ++++
 compat/time32/timerfd_settime32.c             | 26 ++++++
 compat/time32/timespec_get_time32.c           | 18 ++++
 compat/time32/utime_time32.c                  | 14 +++
 compat/time32/utimensat_time32.c              | 11 +++
 compat/time32/utimes_time32.c                 | 11 +++
 compat/time32/wait3_time32.c                  | 40 ++++++++
 compat/time32/wait4_time32.c                  | 40 ++++++++
 64 files changed, 1064 insertions(+)
 create mode 100644 compat/time32/__xstat.c
 create mode 100644 compat/time32/adjtime32.c
 create mode 100644 compat/time32/adjtimex_time32.c
 create mode 100644 compat/time32/aio_suspend_time32.c
 create mode 100644 compat/time32/clock_adjtime32.c
 create mode 100644 compat/time32/clock_getres_time32.c
 create mode 100644 compat/time32/clock_gettime32.c
 create mode 100644 compat/time32/clock_nanosleep_time32.c
 create mode 100644 compat/time32/clock_settime32.c
 create mode 100644 compat/time32/cnd_timedwait_time32.c
 create mode 100644 compat/time32/ctime32.c
 create mode 100644 compat/time32/ctime32_r.c
 create mode 100644 compat/time32/difftime32.c
 create mode 100644 compat/time32/fstat_time32.c
 create mode 100644 compat/time32/fstatat_time32.c
 create mode 100644 compat/time32/ftime32.c
 create mode 100644 compat/time32/futimens_time32.c
 create mode 100644 compat/time32/futimes_time32.c
 create mode 100644 compat/time32/futimesat_time32.c
 create mode 100644 compat/time32/getitimer_time32.c
 create mode 100644 compat/time32/getrusage_time32.c
 create mode 100644 compat/time32/gettimeofday_time32.c
 create mode 100644 compat/time32/gmtime32.c
 create mode 100644 compat/time32/gmtime32_r.c
 create mode 100644 compat/time32/localtime32.c
 create mode 100644 compat/time32/localtime32_r.c
 create mode 100644 compat/time32/lstat_time32.c
 create mode 100644 compat/time32/lutimes_time32.c
 create mode 100644 compat/time32/mktime32.c
 create mode 100644 compat/time32/mq_timedreceive_time32.c
 create mode 100644 compat/time32/mq_timedsend_time32.c
 create mode 100644 compat/time32/mtx_timedlock_time32.c
 create mode 100644 compat/time32/nanosleep_time32.c
 create mode 100644 compat/time32/ppoll_time32.c
 create mode 100644 compat/time32/pselect_time32.c
 create mode 100644 compat/time32/pthread_cond_timedwait_time32.c
 create mode 100644 compat/time32/pthread_mutex_timedlock_time32.c
 create mode 100644 compat/time32/pthread_rwlock_timedrdlock_time32.c
 create mode 100644 compat/time32/pthread_rwlock_timedwrlock_time32.c
 create mode 100644 compat/time32/pthread_timedjoin_np_time32.c
 create mode 100644 compat/time32/recvmmsg_time32.c
 create mode 100644 compat/time32/sched_rr_get_interval_time32.c
 create mode 100644 compat/time32/select_time32.c
 create mode 100644 compat/time32/sem_timedwait_time32.c
 create mode 100644 compat/time32/semtimedop_time32.c
 create mode 100644 compat/time32/setitimer_time32.c
 create mode 100644 compat/time32/settimeofday_time32.c
 create mode 100644 compat/time32/sigtimedwait_time32.c
 create mode 100644 compat/time32/stat_time32.c
 create mode 100644 compat/time32/stime32.c
 create mode 100644 compat/time32/thrd_sleep_time32.c
 create mode 100644 compat/time32/time32.c
 create mode 100644 compat/time32/time32.h
 create mode 100644 compat/time32/time32gm.c
 create mode 100644 compat/time32/timer_gettime32.c
 create mode 100644 compat/time32/timer_settime32.c
 create mode 100644 compat/time32/timerfd_gettime32.c
 create mode 100644 compat/time32/timerfd_settime32.c
 create mode 100644 compat/time32/timespec_get_time32.c
 create mode 100644 compat/time32/utime_time32.c
 create mode 100644 compat/time32/utimensat_time32.c
 create mode 100644 compat/time32/utimes_time32.c
 create mode 100644 compat/time32/wait3_time32.c
 create mode 100644 compat/time32/wait4_time32.c

diff --git a/compat/time32/__xstat.c b/compat/time32/__xstat.c
new file mode 100644
index 00000000..d8cd5ef2
--- /dev/null
+++ b/compat/time32/__xstat.c
@@ -0,0 +1,22 @@
+#include "time32.h"
+#include <sys/stat.h>
+
+int __fxstat64(int ver, int fd, struct stat *buf)
+{
+	return __fstat_time32(fd, buf);
+}
+
+int __fxstatat64(int ver, int fd, const char *path, struct stat *buf, int flag)
+{
+	return __fstatat_time32(fd, path, buf, flag);
+}
+
+int __lxstat64(int ver, const char *path, struct stat *buf)
+{
+	return __lstat_time32(path, buf);
+}
+
+int __xstat64(int ver, const char *path, struct stat *buf)
+{
+	return __stat_time32(path, buf);
+}
diff --git a/compat/time32/adjtime32.c b/compat/time32/adjtime32.c
new file mode 100644
index 00000000..b0042c63
--- /dev/null
+++ b/compat/time32/adjtime32.c
@@ -0,0 +1,21 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+
+int __adjtime32(const struct timeval32 *in32, struct timeval32 *out32)
+{
+	struct timeval out;
+	int r = adjtime((&(struct timeval){
+		.tv_sec = in32->tv_sec,
+		.tv_usec = in32->tv_usec}), &out);
+	if (r) return r;
+	/* We can't range-check the result because success was already
+	 * committed by the above call. */
+	if (out32) {
+		out32->tv_sec = out.tv_sec;
+		out32->tv_usec = out.tv_usec;
+	}
+	return r;
+}
diff --git a/compat/time32/adjtimex_time32.c b/compat/time32/adjtimex_time32.c
new file mode 100644
index 00000000..d7541da8
--- /dev/null
+++ b/compat/time32/adjtimex_time32.c
@@ -0,0 +1,37 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+#include <string.h>
+#include <stddef.h>
+
+struct oldtimex {
+	unsigned modes;
+	long offset, freq, maxerror, esterror;
+	int status;
+	long constant, precision, tolerance;
+	long time_sec, time_usec;
+	long tick, ppsfreq, jitter;
+	int shift;
+	long stabil, jitcnt, calcnt, errcnt, stbcnt;
+	int tai;
+	int __padding[11];
+};
+
+int __adjtimex_time32(struct timex *tx32)
+{
+	struct timex utx;
+	memcpy(&utx, tx32, sizeof(struct oldtimex));
+	utx.time.tv_sec =
+		*(long *)((char *)tx32 + offsetof(struct oldtimex,time_sec));
+	utx.time.tv_usec =
+		*(long *)((char *)tx32 + offsetof(struct oldtimex,time_usec));
+	int r = adjtimex(&utx);
+	if (r<0) return r;
+	memcpy(tx32, &utx, sizeof(struct oldtimex));
+	*(long *)((char *)tx32 + offsetof(struct oldtimex,time_sec)) =
+		utx.time.tv_sec;
+	*(long *)((char *)tx32 + offsetof(struct oldtimex,time_usec)) =
+		utx.time.tv_usec;
+	return r;
+}
diff --git a/compat/time32/aio_suspend_time32.c b/compat/time32/aio_suspend_time32.c
new file mode 100644
index 00000000..ed5119bd
--- /dev/null
+++ b/compat/time32/aio_suspend_time32.c
@@ -0,0 +1,11 @@
+#include "time32.h"
+#include <time.h>
+#include <aio.h>
+
+int __aio_suspend_time32(const struct aiocb *const cbs[], int cnt, const struct timespec32 *ts32)
+{
+	return aio_suspend(cbs, cnt, ts32 ? (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
+}
+
+weak_alias(aio_suspend, aio_suspend64);
diff --git a/compat/time32/clock_adjtime32.c b/compat/time32/clock_adjtime32.c
new file mode 100644
index 00000000..5a25b8ac
--- /dev/null
+++ b/compat/time32/clock_adjtime32.c
@@ -0,0 +1,70 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+#include <string.h>
+#include <stddef.h>
+
+struct timex32 {
+	unsigned modes;
+	long offset, freq, maxerror, esterror;
+	int status;
+	long constant, precision, tolerance;
+	struct timeval32 time;
+	long tick, ppsfreq, jitter;
+	int shift;
+	long stabil, jitcnt, calcnt, errcnt, stbcnt;
+	int tai;
+	int __padding[11];
+};
+
+int __clock_adjtime32(clockid_t clock_id, struct timex32 *tx32)
+{
+	struct timex utx = {
+		.modes = tx32->modes,
+		.offset = tx32->offset,
+		.freq = tx32->freq,
+		.maxerror = tx32->maxerror,
+		.esterror = tx32->esterror,
+		.status = tx32->status,
+		.constant = tx32->constant,
+		.precision = tx32->precision,
+		.tolerance = tx32->tolerance,
+		.time.tv_sec = tx32->time.tv_sec,
+		.time.tv_usec = tx32->time.tv_usec,
+		.tick = tx32->tick,
+		.ppsfreq = tx32->ppsfreq,
+		.jitter = tx32->jitter,
+		.shift = tx32->shift,
+		.stabil = tx32->stabil,
+		.jitcnt = tx32->jitcnt,
+		.calcnt = tx32->calcnt,
+		.errcnt = tx32->errcnt,
+		.stbcnt = tx32->stbcnt,
+		.tai = tx32->tai,
+	};
+	int r = clock_adjtime(clock_id, &utx);
+	if (r<0) return r;
+	tx32->modes = utx.modes;
+	tx32->offset = utx.offset;
+	tx32->freq = utx.freq;
+	tx32->maxerror = utx.maxerror;
+	tx32->esterror = utx.esterror;
+	tx32->status = utx.status;
+	tx32->constant = utx.constant;
+	tx32->precision = utx.precision;
+	tx32->tolerance = utx.tolerance;
+	tx32->time.tv_sec = utx.time.tv_sec;
+	tx32->time.tv_usec = utx.time.tv_usec;
+	tx32->tick = utx.tick;
+	tx32->ppsfreq = utx.ppsfreq;
+	tx32->jitter = utx.jitter;
+	tx32->shift = utx.shift;
+	tx32->stabil = utx.stabil;
+	tx32->jitcnt = utx.jitcnt;
+	tx32->calcnt = utx.calcnt;
+	tx32->errcnt = utx.errcnt;
+	tx32->stbcnt = utx.stbcnt;
+	tx32->tai = utx.tai;
+	return r;
+}
diff --git a/compat/time32/clock_getres_time32.c b/compat/time32/clock_getres_time32.c
new file mode 100644
index 00000000..47a24c13
--- /dev/null
+++ b/compat/time32/clock_getres_time32.c
@@ -0,0 +1,13 @@
+#include "time32.h"
+#include <time.h>
+
+int __clock_getres_time32(clockid_t clk, struct timespec32 *ts32)
+{
+	struct timespec ts;
+	int r = clock_getres(clk, &ts);
+	if (!r && ts32) {
+		ts32->tv_sec = ts.tv_sec;
+		ts32->tv_nsec = ts.tv_nsec;
+	}
+	return r;
+}
diff --git a/compat/time32/clock_gettime32.c b/compat/time32/clock_gettime32.c
new file mode 100644
index 00000000..0cac7bbd
--- /dev/null
+++ b/compat/time32/clock_gettime32.c
@@ -0,0 +1,18 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+
+int __clock_gettime32(clockid_t clk, struct timespec32 *ts32)
+{
+	struct timespec ts;
+	int r = clock_gettime(clk, &ts);
+	if (r) return r;
+	if (ts.tv_sec < INT32_MIN || ts.tv_sec > INT32_MAX) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+	ts32->tv_sec = ts.tv_sec;
+	ts32->tv_nsec = ts.tv_nsec;
+	return 0;
+}
diff --git a/compat/time32/clock_nanosleep_time32.c b/compat/time32/clock_nanosleep_time32.c
new file mode 100644
index 00000000..91ef067d
--- /dev/null
+++ b/compat/time32/clock_nanosleep_time32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+
+int __clock_nanosleep_time32(clockid_t clk, int flags, const struct timespec32 *req32, struct timespec32 *rem32)
+{
+	struct timespec rem;
+	int ret = clock_nanosleep(clk, flags, (&(struct timespec){
+		.tv_sec = req32->tv_sec, .tv_nsec = req32->tv_nsec}), &rem);
+	if (ret==EINTR && rem32 && !(flags & TIMER_ABSTIME)) {
+		rem32->tv_sec = rem.tv_sec;
+		rem32->tv_nsec = rem.tv_nsec;
+	}
+	return ret;
+}
diff --git a/compat/time32/clock_settime32.c b/compat/time32/clock_settime32.c
new file mode 100644
index 00000000..7ca4f0e9
--- /dev/null
+++ b/compat/time32/clock_settime32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+
+int __clock_settime32(clockid_t clk, const struct timespec32 *ts32)
+{
+	return clock_settime(clk, (&(struct timespec){
+		.tv_sec = ts32->tv_sec,
+		.tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/cnd_timedwait_time32.c b/compat/time32/cnd_timedwait_time32.c
new file mode 100644
index 00000000..314251d1
--- /dev/null
+++ b/compat/time32/cnd_timedwait_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <threads.h>
+
+int __cnd_timedwait_time32(cnd_t *restrict c, mtx_t *restrict m, const struct timespec32 *restrict ts32)
+{
+	return cnd_timedwait(c, m, ts32 ? (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
+}
diff --git a/compat/time32/ctime32.c b/compat/time32/ctime32.c
new file mode 100644
index 00000000..a057274e
--- /dev/null
+++ b/compat/time32/ctime32.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+char *__ctime32(time32_t *t)
+{
+	return ctime(&(time_t){*t});
+}
diff --git a/compat/time32/ctime32_r.c b/compat/time32/ctime32_r.c
new file mode 100644
index 00000000..e1ad2e28
--- /dev/null
+++ b/compat/time32/ctime32_r.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+char *__ctime32_r(time32_t *t, char *buf)
+{
+	return ctime_r(&(time_t){*t}, buf);
+}
diff --git a/compat/time32/difftime32.c b/compat/time32/difftime32.c
new file mode 100644
index 00000000..15c65709
--- /dev/null
+++ b/compat/time32/difftime32.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+double __difftime32(time32_t t1, time_t t2)
+{
+	return difftime(t1, t2);
+}
diff --git a/compat/time32/fstat_time32.c b/compat/time32/fstat_time32.c
new file mode 100644
index 00000000..3e084398
--- /dev/null
+++ b/compat/time32/fstat_time32.c
@@ -0,0 +1,17 @@
+#include "time32.h"
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+struct stat32;
+
+int __fstat_time32(int fd, struct stat32 *restrict st32)
+{
+	struct stat st;
+	int r = fstat(fd, &st);
+	if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
+	return r;
+}
+
+weak_alias(fstat, fstat64);
diff --git a/compat/time32/fstatat_time32.c b/compat/time32/fstatat_time32.c
new file mode 100644
index 00000000..85dcb008
--- /dev/null
+++ b/compat/time32/fstatat_time32.c
@@ -0,0 +1,17 @@
+#include "time32.h"
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+struct stat32;
+
+int __fstatat_time32(int fd, const char *restrict path, struct stat32 *restrict st32, int flag)
+{
+	struct stat st;
+	int r = fstatat(fd, path, &st, flag);
+	if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
+	return r;
+}
+
+weak_alias(fstatat, fstatat64);
diff --git a/compat/time32/ftime32.c b/compat/time32/ftime32.c
new file mode 100644
index 00000000..166a6dae
--- /dev/null
+++ b/compat/time32/ftime32.c
@@ -0,0 +1,25 @@
+#include "time32.h"
+#include <sys/timeb.h>
+#include <errno.h>
+#include <stdint.h>
+
+struct timeb32 {
+	int32_t time;
+	unsigned short millitm;
+	short timezone, dstflag;
+};
+
+int __ftime32(struct timeb32 *tp)
+{
+	struct timeb tb;
+	if (ftime(&tb) < 0) return -1;
+	if (tb.time < INT32_MIN || tb.time > INT32_MAX) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+	tp->time = tb.time;
+	tp->millitm = tb.millitm;
+	tp->timezone = tb.timezone;
+	tp->dstflag = tb.dstflag;
+	return 0;
+}
diff --git a/compat/time32/futimens_time32.c b/compat/time32/futimens_time32.c
new file mode 100644
index 00000000..7856f176
--- /dev/null
+++ b/compat/time32/futimens_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/stat.h>
+
+int __futimens_time32(int fd, const struct timespec32 *times32)
+{
+	return futimens(fd, !times32 ? 0 : ((struct timespec[2]){
+		{.tv_sec = times32[0].tv_sec,.tv_nsec = times32[0].tv_nsec},
+		{.tv_sec = times32[1].tv_sec,.tv_nsec = times32[1].tv_nsec}}));
+}
diff --git a/compat/time32/futimes_time32.c b/compat/time32/futimes_time32.c
new file mode 100644
index 00000000..f29533f1
--- /dev/null
+++ b/compat/time32/futimes_time32.c
@@ -0,0 +1,12 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+int __futimes_time32(int fd, const struct timeval32 times32[2])
+{
+	return futimes(fd, !times32 ? 0 : ((struct timeval[2]){
+		{.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
+		{.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
+}
diff --git a/compat/time32/futimesat_time32.c b/compat/time32/futimesat_time32.c
new file mode 100644
index 00000000..5a1295bd
--- /dev/null
+++ b/compat/time32/futimesat_time32.c
@@ -0,0 +1,12 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+int __futimesat_time32(int dirfd, const char *pathname, const struct timeval32 times32[2])
+{
+	return futimesat(dirfd, pathname, !times32 ? 0 : ((struct timeval[2]){
+		{.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
+		{.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
+}
diff --git a/compat/time32/getitimer_time32.c b/compat/time32/getitimer_time32.c
new file mode 100644
index 00000000..4bac4bf5
--- /dev/null
+++ b/compat/time32/getitimer_time32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+
+int __getitimer_time32(int which, struct itimerval32 *old32)
+{
+	struct itimerval old;
+	int r = getitimer(which, &old);
+	if (r) return r;
+	old32->it_interval.tv_sec = old.it_interval.tv_sec;
+	old32->it_interval.tv_usec = old.it_interval.tv_usec;
+	old32->it_value.tv_sec = old.it_value.tv_sec;
+	old32->it_value.tv_usec = old.it_value.tv_usec;
+	return 0;
+}
diff --git a/compat/time32/getrusage_time32.c b/compat/time32/getrusage_time32.c
new file mode 100644
index 00000000..d7487dee
--- /dev/null
+++ b/compat/time32/getrusage_time32.c
@@ -0,0 +1,39 @@
+#include "time32.h"
+#include <string.h>
+#include <stddef.h>
+#include <sys/resource.h>
+
+struct compat_rusage {
+	struct timeval32 ru_utime;
+	struct timeval32 ru_stime;
+	long	ru_maxrss;
+	long	ru_ixrss;
+	long	ru_idrss;
+	long	ru_isrss;
+	long	ru_minflt;
+	long	ru_majflt;
+	long	ru_nswap;
+	long	ru_inblock;
+	long	ru_oublock;
+	long	ru_msgsnd;
+	long	ru_msgrcv;
+	long	ru_nsignals;
+	long	ru_nvcsw;
+	long	ru_nivcsw;
+};
+
+int __getrusage_time32(int who, struct compat_rusage *usage)
+{
+	struct rusage ru;
+	int r = getrusage(who, &ru);
+	if (!r) {
+		usage->ru_utime.tv_sec = ru.ru_utime.tv_sec;
+		usage->ru_utime.tv_usec = ru.ru_utime.tv_usec;
+		usage->ru_stime.tv_sec = ru.ru_stime.tv_sec;
+		usage->ru_stime.tv_usec = ru.ru_stime.tv_usec;
+		memcpy(&usage->ru_maxrss, &ru.ru_maxrss,
+			sizeof(struct compat_rusage) -
+			offsetof(struct compat_rusage, ru_maxrss));
+	}
+	return r;
+}
diff --git a/compat/time32/gettimeofday_time32.c b/compat/time32/gettimeofday_time32.c
new file mode 100644
index 00000000..1f3ce68e
--- /dev/null
+++ b/compat/time32/gettimeofday_time32.c
@@ -0,0 +1,19 @@
+#include "time32.h"
+#include <sys/time.h>
+#include <errno.h>
+#include <stdint.h>
+
+int __gettimeofday_time32(struct timeval32 *tv32, void *tz)
+{
+	struct timeval tv;
+	if (!tv32) return 0;
+	int r = gettimeofday(&tv, 0);
+	if (r) return r;
+	if (tv.tv_sec < INT32_MIN || tv.tv_sec > INT32_MAX) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+	tv32->tv_sec = tv.tv_sec;
+	tv32->tv_usec = tv.tv_usec;
+	return 0;
+}
diff --git a/compat/time32/gmtime32.c b/compat/time32/gmtime32.c
new file mode 100644
index 00000000..963f0e05
--- /dev/null
+++ b/compat/time32/gmtime32.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+struct tm *__gmtime32(time32_t *t)
+{
+	return gmtime(&(time_t){*t});
+}
diff --git a/compat/time32/gmtime32_r.c b/compat/time32/gmtime32_r.c
new file mode 100644
index 00000000..7d72bfb3
--- /dev/null
+++ b/compat/time32/gmtime32_r.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+struct tm *__gmtime32_r(time32_t *t, struct tm *tm)
+{
+	return gmtime_r(&(time_t){*t}, tm);
+}
diff --git a/compat/time32/localtime32.c b/compat/time32/localtime32.c
new file mode 100644
index 00000000..96bc3034
--- /dev/null
+++ b/compat/time32/localtime32.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+struct tm *__localtime32(time32_t *t)
+{
+	return localtime(&(time_t){*t});
+}
diff --git a/compat/time32/localtime32_r.c b/compat/time32/localtime32_r.c
new file mode 100644
index 00000000..633ec829
--- /dev/null
+++ b/compat/time32/localtime32_r.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include <time.h>
+
+struct tm *__localtime32_r(time32_t *t, struct tm *tm)
+{
+	return localtime_r(&(time_t){*t}, tm);
+}
diff --git a/compat/time32/lstat_time32.c b/compat/time32/lstat_time32.c
new file mode 100644
index 00000000..c1257a14
--- /dev/null
+++ b/compat/time32/lstat_time32.c
@@ -0,0 +1,17 @@
+#include "time32.h"
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+struct stat32;
+
+int __lstat_time32(const char *restrict path, struct stat32 *restrict st32)
+{
+	struct stat st;
+	int r = lstat(path, &st);
+	if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
+	return r;
+}
+
+weak_alias(lstat, lstat64);
diff --git a/compat/time32/lutimes_time32.c b/compat/time32/lutimes_time32.c
new file mode 100644
index 00000000..7f75cd4a
--- /dev/null
+++ b/compat/time32/lutimes_time32.c
@@ -0,0 +1,12 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+int __lutimes_time32(const char *path, const struct timeval32 times32[2])
+{
+	return lutimes(path, !times32 ? 0 : ((struct timeval[2]){
+		{.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
+		{.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
+}
diff --git a/compat/time32/mktime32.c b/compat/time32/mktime32.c
new file mode 100644
index 00000000..e6f15d51
--- /dev/null
+++ b/compat/time32/mktime32.c
@@ -0,0 +1,16 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+
+time32_t __mktime32(struct tm *tm)
+{
+	struct tm tmp = *tm;
+	time_t t = mktime(&tmp);
+	if (t < INT32_MIN || t > INT32_MAX) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+	*tm = tmp;
+	return t;
+}
diff --git a/compat/time32/mq_timedreceive_time32.c b/compat/time32/mq_timedreceive_time32.c
new file mode 100644
index 00000000..211cea4b
--- /dev/null
+++ b/compat/time32/mq_timedreceive_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <mqueue.h>
+#include <time.h>
+
+ssize_t __mq_timedreceive_time32(mqd_t mqd, char *restrict msg, size_t len, unsigned *restrict prio, const struct timespec32 *restrict ts32)
+{
+	return mq_timedreceive(mqd, msg, len, prio, ts32 ? (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
+}
diff --git a/compat/time32/mq_timedsend_time32.c b/compat/time32/mq_timedsend_time32.c
new file mode 100644
index 00000000..93b697a7
--- /dev/null
+++ b/compat/time32/mq_timedsend_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <mqueue.h>
+#include <time.h>
+
+int __mq_timedsend_time32(mqd_t mqd, const char *msg, size_t len, unsigned prio, const struct timespec32 *ts32)
+{
+	return mq_timedsend(mqd, msg, len, prio, ts32 ? (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
+}
diff --git a/compat/time32/mtx_timedlock_time32.c b/compat/time32/mtx_timedlock_time32.c
new file mode 100644
index 00000000..a01f09b8
--- /dev/null
+++ b/compat/time32/mtx_timedlock_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <threads.h>
+
+int __mtx_timedlock_time32(mtx_t *restrict m, const struct timespec32 *restrict ts32)
+{
+	return mtx_timedlock(m, !ts32 ? 0 : (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/nanosleep_time32.c b/compat/time32/nanosleep_time32.c
new file mode 100644
index 00000000..ea6bdd81
--- /dev/null
+++ b/compat/time32/nanosleep_time32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+
+int __nanosleep_time32(const struct timespec32 *req32, struct timespec32 *rem32)
+{
+	struct timespec rem;
+	int ret = nanosleep((&(struct timespec){
+		.tv_sec = req32->tv_sec, .tv_nsec = req32->tv_nsec}), &rem);
+	if (ret<0 && errno==EINTR && rem32) {
+		rem32->tv_sec = rem.tv_sec;
+		rem32->tv_nsec = rem.tv_nsec;
+	}
+	return ret;
+}
diff --git a/compat/time32/ppoll_time32.c b/compat/time32/ppoll_time32.c
new file mode 100644
index 00000000..43b4b0df
--- /dev/null
+++ b/compat/time32/ppoll_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#define _GNU_SOURCE
+#include <time.h>
+#include <poll.h>
+
+int __ppoll_time32(struct pollfd *fds, nfds_t n, const struct timespec32 *ts32, const sigset_t *mask)
+{
+	return ppoll(fds, n, !ts32 ? 0 : (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}), mask);
+}
diff --git a/compat/time32/pselect_time32.c b/compat/time32/pselect_time32.c
new file mode 100644
index 00000000..ecaa8f86
--- /dev/null
+++ b/compat/time32/pselect_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/select.h>
+
+int __pselect_time32(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, const struct timespec32 *restrict ts32, const sigset_t *restrict mask)
+{
+	return pselect(n, rfds, wfds, efds, !ts32 ? 0 : (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}), mask);
+}
diff --git a/compat/time32/pthread_cond_timedwait_time32.c b/compat/time32/pthread_cond_timedwait_time32.c
new file mode 100644
index 00000000..fba1f2a9
--- /dev/null
+++ b/compat/time32/pthread_cond_timedwait_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <pthread.h>
+
+int __pthread_cond_timedwait_time32(pthread_cond_t *restrict c, pthread_mutex_t *restrict m, const struct timespec32 *restrict ts32)
+{
+	return pthread_cond_timedwait(c, m, !ts32 ? 0 : (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/pthread_mutex_timedlock_time32.c b/compat/time32/pthread_mutex_timedlock_time32.c
new file mode 100644
index 00000000..2d29602c
--- /dev/null
+++ b/compat/time32/pthread_mutex_timedlock_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <pthread.h>
+
+int __pthread_mutex_timedlock_time32(pthread_mutex_t *restrict m, const struct timespec32 *restrict ts32)
+{
+	return pthread_mutex_timedlock(m, !ts32 ? 0 : (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/pthread_rwlock_timedrdlock_time32.c b/compat/time32/pthread_rwlock_timedrdlock_time32.c
new file mode 100644
index 00000000..33df27a4
--- /dev/null
+++ b/compat/time32/pthread_rwlock_timedrdlock_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <pthread.h>
+
+int __pthread_rwlock_timedrdlock_time32(pthread_rwlock_t *restrict rw, const struct timespec32 *restrict ts32)
+{
+	return pthread_rwlock_timedrdlock(rw, !ts32 ? 0 : (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/pthread_rwlock_timedwrlock_time32.c b/compat/time32/pthread_rwlock_timedwrlock_time32.c
new file mode 100644
index 00000000..99f24f73
--- /dev/null
+++ b/compat/time32/pthread_rwlock_timedwrlock_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <pthread.h>
+
+int __pthread_rwlock_timedwrlock_time32(pthread_rwlock_t *restrict rw, const struct timespec32 *restrict ts32)
+{
+	return pthread_rwlock_timedwrlock(rw, !ts32 ? 0 : (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/pthread_timedjoin_np_time32.c b/compat/time32/pthread_timedjoin_np_time32.c
new file mode 100644
index 00000000..99a26bc6
--- /dev/null
+++ b/compat/time32/pthread_timedjoin_np_time32.c
@@ -0,0 +1,10 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <pthread.h>
+
+int __pthread_timedjoin_np_time32(pthread_t t, void **res, const struct timespec *at32)
+{
+	return pthread_timedjoin_np(t, res, !at32 ? 0 : (&(struct timespec){
+		.tv_sec = at32->tv_sec, .tv_nsec = at32->tv_nsec}));
+}
diff --git a/compat/time32/recvmmsg_time32.c b/compat/time32/recvmmsg_time32.c
new file mode 100644
index 00000000..acf1cfb8
--- /dev/null
+++ b/compat/time32/recvmmsg_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#define _GNU_SOURCE
+#include <time.h>
+#include <sys/socket.h>
+
+int __recvmmsg_time32(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags, struct timespec32 *ts32)
+{
+	return recvmmsg(fd, msgvec, vlen, flags, ts32 ? (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
+}
diff --git a/compat/time32/sched_rr_get_interval_time32.c b/compat/time32/sched_rr_get_interval_time32.c
new file mode 100644
index 00000000..36cbbaca
--- /dev/null
+++ b/compat/time32/sched_rr_get_interval_time32.c
@@ -0,0 +1,13 @@
+#include "time32.h"
+#include <time.h>
+#include <sched.h>
+
+int __sched_rr_get_interval_time32(pid_t pid, struct timespec32 *ts32)
+{
+	struct timespec ts;
+	int r = sched_rr_get_interval(pid, &ts);
+	if (r) return r;
+	ts32->tv_sec = ts.tv_sec;
+	ts32->tv_nsec = ts.tv_nsec;
+	return r;
+}
diff --git a/compat/time32/select_time32.c b/compat/time32/select_time32.c
new file mode 100644
index 00000000..2d8df9ac
--- /dev/null
+++ b/compat/time32/select_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/select.h>
+
+int __select_time32(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, struct timeval32 *restrict tv32)
+{
+	return select(n, rfds, wfds, efds, !tv32 ? 0 : (&(struct timeval){
+		.tv_sec = tv32->tv_sec, .tv_usec = tv32->tv_usec}));
+}
diff --git a/compat/time32/sem_timedwait_time32.c b/compat/time32/sem_timedwait_time32.c
new file mode 100644
index 00000000..c3469f9b
--- /dev/null
+++ b/compat/time32/sem_timedwait_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <semaphore.h>
+
+int __sem_timedwait_time32(sem_t *sem, const struct timespec32 *restrict ts32)
+{
+	return sem_timedwait(sem, !ts32 ? 0 : (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/semtimedop_time32.c b/compat/time32/semtimedop_time32.c
new file mode 100644
index 00000000..34ec5281
--- /dev/null
+++ b/compat/time32/semtimedop_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#define _GNU_SOURCE
+#include <sys/sem.h>
+#include <time.h>
+
+int __semtimedop_time32(int id, struct sembuf *buf, size_t n, const struct timespec32 *ts32)
+{
+	return semtimedop(id, buf, n, !ts32 ? 0 : (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/setitimer_time32.c b/compat/time32/setitimer_time32.c
new file mode 100644
index 00000000..4651dacb
--- /dev/null
+++ b/compat/time32/setitimer_time32.c
@@ -0,0 +1,23 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+
+int __setitimer_time32(int which, const struct itimerval32 *restrict new32, struct itimerval32 *restrict old32)
+{
+	struct itimerval old;
+	int r = setitimer(which, (&(struct itimerval){
+		.it_interval.tv_sec = new32->it_interval.tv_sec,
+		.it_interval.tv_usec = new32->it_interval.tv_usec,
+		.it_value.tv_sec = new32->it_value.tv_sec,
+		.it_value.tv_usec = new32->it_value.tv_usec}), &old);
+	if (r) return r;
+	/* The above call has already committed to success by changing the
+	 * timer setting, so we can't fail on out-of-range old value.
+	 * Since these are relative times, values large enough to overflow
+	 * don't make sense anyway. */
+	old32->it_interval.tv_sec = old.it_interval.tv_sec;
+	old32->it_interval.tv_usec = old.it_interval.tv_usec;
+	old32->it_value.tv_sec = old.it_value.tv_sec;
+	old32->it_value.tv_usec = old.it_value.tv_usec;
+	return 0;
+}
diff --git a/compat/time32/settimeofday_time32.c b/compat/time32/settimeofday_time32.c
new file mode 100644
index 00000000..09e625cb
--- /dev/null
+++ b/compat/time32/settimeofday_time32.c
@@ -0,0 +1,10 @@
+#define _BSD_SOURCE
+#include "time32.h"
+#include <sys/time.h>
+
+int __settimeofday_time32(const struct timeval32 *tv32, const void *tz)
+{
+	return settimeofday(!tv32 ? 0 : (&(struct timeval){
+		.tv_sec = tv32->tv_sec,
+		.tv_usec = tv32->tv_usec}), 0);
+}
diff --git a/compat/time32/sigtimedwait_time32.c b/compat/time32/sigtimedwait_time32.c
new file mode 100644
index 00000000..6b3aa39c
--- /dev/null
+++ b/compat/time32/sigtimedwait_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include <time.h>
+#include <signal.h>
+
+int __sigtimedwait_time32(const sigset_t *restrict set, siginfo_t *restrict si, const struct timespec32 *restrict ts32)
+{
+	return sigtimedwait(set, si, !ts32 ? 0 : (&(struct timespec){
+		.tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/compat/time32/stat_time32.c b/compat/time32/stat_time32.c
new file mode 100644
index 00000000..8c6121da
--- /dev/null
+++ b/compat/time32/stat_time32.c
@@ -0,0 +1,17 @@
+#include "time32.h"
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+struct stat32;
+
+int __stat_time32(const char *restrict path, struct stat32 *restrict st32)
+{
+	struct stat st;
+	int r = stat(path, &st);
+	if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
+	return r;
+}
+
+weak_alias(stat, stat64);
diff --git a/compat/time32/stime32.c b/compat/time32/stime32.c
new file mode 100644
index 00000000..cc76364d
--- /dev/null
+++ b/compat/time32/stime32.c
@@ -0,0 +1,8 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+
+int __stime32(const time32_t *t)
+{
+	return stime(&(time_t){*t});
+}
diff --git a/compat/time32/thrd_sleep_time32.c b/compat/time32/thrd_sleep_time32.c
new file mode 100644
index 00000000..59088001
--- /dev/null
+++ b/compat/time32/thrd_sleep_time32.c
@@ -0,0 +1,16 @@
+#include "time32.h"
+#include <time.h>
+#include <threads.h>
+#include <errno.h>
+
+int __thrd_sleep_time32(const struct timespec32 *req32, struct timespec32 *rem32)
+{
+	struct timespec rem;
+	int ret = thrd_sleep((&(struct timespec){
+		.tv_sec = req32->tv_sec, .tv_nsec = req32->tv_nsec}), &rem);
+	if (ret<0 && errno==EINTR && rem32) {
+		rem32->tv_sec = rem.tv_sec;
+		rem32->tv_nsec = rem.tv_nsec;
+	}
+	return ret;
+}
diff --git a/compat/time32/time32.c b/compat/time32/time32.c
new file mode 100644
index 00000000..4b8fac1c
--- /dev/null
+++ b/compat/time32/time32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+
+time32_t __time32(time32_t *p)
+{
+	time_t t = time(0);
+	if (t < INT32_MIN || t > INT32_MAX) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+	if (p) *p = t;
+	return t;
+}
diff --git a/compat/time32/time32.h b/compat/time32/time32.h
new file mode 100644
index 00000000..fdec17c3
--- /dev/null
+++ b/compat/time32/time32.h
@@ -0,0 +1,91 @@
+#ifndef TIME32_H
+#define TIME32_H
+
+#include <sys/types.h>
+
+typedef long time32_t;
+
+struct timeval32 {
+	long tv_sec;
+	long tv_usec;
+};
+
+struct itimerval32 {
+	struct timeval32 it_interval;
+	struct timeval32 it_value;
+};
+
+struct timespec32 {
+	long tv_sec;
+	long tv_nsec;
+};
+
+struct itimerspec32 {
+	struct timespec32 it_interval;
+	struct timespec32 it_value;
+};
+
+int __adjtime32() __asm__("adjtime");
+int __adjtimex_time32() __asm__("adjtimex");
+int __aio_suspend_time32() __asm__("aio_suspend");
+int __clock_adjtime32() __asm__("clock_adjtime");
+int __clock_getres_time32() __asm__("clock_getres");
+int __clock_gettime32() __asm__("clock_gettime");
+int __clock_nanosleep_time32() __asm__("clock_nanosleep");
+int __clock_settime32() __asm__("clock_settime");
+int __cnd_timedwait_time32() __asm__("cnd_timedwait");
+char *__ctime32() __asm__("ctime");
+char *__ctime32_r() __asm__("ctime_r");
+double __difftime32() __asm__("difftime");
+int __fstat_time32() __asm__("fstat");
+int __fstatat_time32() __asm__("fstatat");
+int __ftime32() __asm__("ftime");
+int __futimens_time32() __asm__("futimens");
+int __futimes_time32() __asm__("futimes");
+int __futimesat_time32() __asm__("futimesat");
+int __getitimer_time32() __asm__("getitimer");
+int __getrusage_time32() __asm__("getrusage");
+int __gettimeofday_time32() __asm__("gettimeofday");
+struct tm *__gmtime32() __asm__("gmtime");
+struct tm *__gmtime32_r() __asm__("gmtime_r");
+struct tm *__localtime32() __asm__("localtime");
+struct tm *__localtime32_r() __asm__("localtime_r");
+int __lstat_time32() __asm__("lstat");
+int __lutimes_time32() __asm__("lutimes");
+time32_t __mktime32() __asm__("mktime");
+ssize_t __mq_timedreceive_time32() __asm__("mq_timedreceive");
+int __mq_timedsend_time32() __asm__("mq_timedsend");
+int __mtx_timedlock_time32() __asm__("mtx_timedlock");
+int __nanosleep_time32() __asm__("nanosleep");
+int __ppoll_time32() __asm__("ppoll");
+int __pselect_time32() __asm__("pselect");
+int __pthread_cond_timedwait_time32() __asm__("pthread_cond_timedwait");
+int __pthread_mutex_timedlock_time32() __asm__("pthread_mutex_timedlock");
+int __pthread_rwlock_timedrdlock_time32() __asm__("pthread_rwlock_timedrdlock");
+int __pthread_rwlock_timedwrlock_time32() __asm__("pthread_rwlock_timedwrlock");
+int __pthread_timedjoin_np_time32() __asm__("pthread_timedjoin_np");
+int __recvmmsg_time32() __asm__("recvmmsg");
+int __sched_rr_get_interval_time32() __asm__("sched_rr_get_interval");
+int __select_time32() __asm__("select");
+int __sem_timedwait_time32() __asm__("sem_timedwait");
+int __semtimedop_time32() __asm__("semtimedop");
+int __setitimer_time32() __asm__("setitimer");
+int __settimeofday_time32() __asm__("settimeofday");
+int __sigtimedwait_time32() __asm__("sigtimedwait");
+int __stat_time32() __asm__("stat");
+int __stime32() __asm__("stime");
+int __thrd_sleep_time32() __asm__("thrd_sleep");
+time32_t __time32() __asm__("time");
+time32_t __time32gm() __asm__("timegm");
+int __timer_gettime32() __asm__("timer_gettime");
+int __timer_settime32() __asm__("timer_settime");
+int __timerfd_gettime32() __asm__("timerfd_gettime");
+int __timerfd_settime32() __asm__("timerfd_settime");
+int __timespec_get_time32() __asm__("timespec_get");
+int __utime_time32() __asm__("utime");
+int __utimensat_time32() __asm__("utimensat");
+int __utimes_time32() __asm__("utimes");
+pid_t __wait3_time32() __asm__("wait3");
+pid_t __wait4_time32() __asm__("wait4");
+
+#endif
diff --git a/compat/time32/time32gm.c b/compat/time32/time32gm.c
new file mode 100644
index 00000000..60d68fbf
--- /dev/null
+++ b/compat/time32/time32gm.c
@@ -0,0 +1,15 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+
+time32_t __time32gm(struct tm *tm)
+{
+	time_t t = timegm(tm);
+	if (t < INT32_MIN || t > INT32_MAX) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+	return t;
+}
diff --git a/compat/time32/timer_gettime32.c b/compat/time32/timer_gettime32.c
new file mode 100644
index 00000000..b4184cc2
--- /dev/null
+++ b/compat/time32/timer_gettime32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include <time.h>
+
+int __timer_gettime32(timer_t t, struct itimerspec32 *val32)
+{
+	struct itimerspec old;
+	int r = timer_gettime(t, &old);
+	if (r) return r;
+	/* No range checking for consistency with settime */
+	val32->it_interval.tv_sec = old.it_interval.tv_sec;
+	val32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+	val32->it_value.tv_sec = old.it_value.tv_sec;
+	val32->it_value.tv_nsec = old.it_value.tv_nsec;
+	return 0;
+}
diff --git a/compat/time32/timer_settime32.c b/compat/time32/timer_settime32.c
new file mode 100644
index 00000000..a447e7d4
--- /dev/null
+++ b/compat/time32/timer_settime32.c
@@ -0,0 +1,25 @@
+#include "time32.h"
+#include <time.h>
+
+int __timer_settime32(timer_t t, int flags, const struct itimerspec32 *restrict val32, struct itimerspec32 *restrict old32)
+{
+	struct itimerspec old;
+	int r = timer_settime(t, flags, (&(struct itimerspec){
+		.it_interval.tv_sec = val32->it_interval.tv_sec,
+		.it_interval.tv_nsec = val32->it_interval.tv_nsec,
+		.it_value.tv_sec = val32->it_value.tv_sec,
+		.it_value.tv_nsec = val32->it_value.tv_nsec}),
+		old32 ? &old : 0);
+	if (r) return r;
+	/* The above call has already committed to success by changing the
+	 * timer setting, so we can't fail on out-of-range old value.
+	 * Since these are relative times, values large enough to overflow
+	 * don't make sense anyway. */
+	if (old32) {
+		old32->it_interval.tv_sec = old.it_interval.tv_sec;
+		old32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+		old32->it_value.tv_sec = old.it_value.tv_sec;
+		old32->it_value.tv_nsec = old.it_value.tv_nsec;
+	}
+	return 0;
+}
diff --git a/compat/time32/timerfd_gettime32.c b/compat/time32/timerfd_gettime32.c
new file mode 100644
index 00000000..75e5435f
--- /dev/null
+++ b/compat/time32/timerfd_gettime32.c
@@ -0,0 +1,16 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/timerfd.h>
+
+int __timerfd_gettime32(int t, struct itimerspec32 *val32)
+{
+	struct itimerspec old;
+	int r = timerfd_gettime(t, &old);
+	if (r) return r;
+	/* No range checking for consistency with settime */
+	val32->it_interval.tv_sec = old.it_interval.tv_sec;
+	val32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+	val32->it_value.tv_sec = old.it_value.tv_sec;
+	val32->it_value.tv_nsec = old.it_value.tv_nsec;
+	return 0;
+}
diff --git a/compat/time32/timerfd_settime32.c b/compat/time32/timerfd_settime32.c
new file mode 100644
index 00000000..67830d34
--- /dev/null
+++ b/compat/time32/timerfd_settime32.c
@@ -0,0 +1,26 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/timerfd.h>
+
+int __timerfd_settime32(int t, int flags, const struct itimerspec32 *restrict val32, struct itimerspec32 *restrict old32)
+{
+	struct itimerspec old;
+	int r = timerfd_settime(t, flags, (&(struct itimerspec){
+		.it_interval.tv_sec = val32->it_interval.tv_sec,
+		.it_interval.tv_nsec = val32->it_interval.tv_nsec,
+		.it_value.tv_sec = val32->it_value.tv_sec,
+		.it_value.tv_nsec = val32->it_value.tv_nsec}),
+		old32 ? &old : 0);
+	if (r) return r;
+	/* The above call has already committed to success by changing the
+	 * timer setting, so we can't fail on out-of-range old value.
+	 * Since these are relative times, values large enough to overflow
+	 * don't make sense anyway. */
+	if (old32) {
+		old32->it_interval.tv_sec = old.it_interval.tv_sec;
+		old32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+		old32->it_value.tv_sec = old.it_value.tv_sec;
+		old32->it_value.tv_nsec = old.it_value.tv_nsec;
+	}
+	return 0;
+}
diff --git a/compat/time32/timespec_get_time32.c b/compat/time32/timespec_get_time32.c
new file mode 100644
index 00000000..e9ca94cb
--- /dev/null
+++ b/compat/time32/timespec_get_time32.c
@@ -0,0 +1,18 @@
+#include "time32.h"
+#include <time.h>
+#include <errno.h>
+#include <stdint.h>
+
+int __timespec_get_time32(struct timespec32 *ts32, int base)
+{
+	struct timespec ts;
+	int r = timespec_get(&ts, base);
+	if (!r) return r;
+	if (ts.tv_sec < INT32_MIN || ts.tv_sec > INT32_MAX) {
+		errno = EOVERFLOW;
+		return 0;
+	}
+	ts32->tv_sec = ts.tv_sec;
+	ts32->tv_nsec = ts.tv_nsec;
+	return r;
+}
diff --git a/compat/time32/utime_time32.c b/compat/time32/utime_time32.c
new file mode 100644
index 00000000..65f11d46
--- /dev/null
+++ b/compat/time32/utime_time32.c
@@ -0,0 +1,14 @@
+#include "time32.h"
+#include <time.h>
+#include <utime.h>
+
+struct utimbuf32 {
+	time32_t actime;
+	time32_t modtime;
+};
+
+int __utime_time32(const char *path, const struct utimbuf32 *times32)
+{
+	return utime(path, !times32 ? 0 : (&(struct utimbuf){
+		.actime = times32->actime, .modtime = times32->modtime}));
+}
diff --git a/compat/time32/utimensat_time32.c b/compat/time32/utimensat_time32.c
new file mode 100644
index 00000000..c687b8d1
--- /dev/null
+++ b/compat/time32/utimensat_time32.c
@@ -0,0 +1,11 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/stat.h>
+
+int __utimensat_time32(int fd, const char *path, const struct timespec32 times32[2], int flags)
+{
+	return utimensat(fd, path, !times32 ? 0 : ((struct timespec[2]){
+		{.tv_sec = times32[0].tv_sec,.tv_nsec = times32[0].tv_nsec},
+		{.tv_sec = times32[1].tv_sec,.tv_nsec = times32[1].tv_nsec}}),
+		flags);
+}
diff --git a/compat/time32/utimes_time32.c b/compat/time32/utimes_time32.c
new file mode 100644
index 00000000..59248f62
--- /dev/null
+++ b/compat/time32/utimes_time32.c
@@ -0,0 +1,11 @@
+#include "time32.h"
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+int __utimes_time32(const char *path, const struct timeval32 times32[2])
+{
+	return utimes(path, !times32 ? 0 : ((struct timeval[2]){
+		{.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
+		{.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
+}
diff --git a/compat/time32/wait3_time32.c b/compat/time32/wait3_time32.c
new file mode 100644
index 00000000..8fe128ed
--- /dev/null
+++ b/compat/time32/wait3_time32.c
@@ -0,0 +1,40 @@
+#define _BSD_SOURCE
+#include "time32.h"
+#include <string.h>
+#include <stddef.h>
+#include <sys/wait.h>
+
+struct compat_rusage {
+	struct timeval32 ru_utime;
+	struct timeval32 ru_stime;
+	long	ru_maxrss;
+	long	ru_ixrss;
+	long	ru_idrss;
+	long	ru_isrss;
+	long	ru_minflt;
+	long	ru_majflt;
+	long	ru_nswap;
+	long	ru_inblock;
+	long	ru_oublock;
+	long	ru_msgsnd;
+	long	ru_msgrcv;
+	long	ru_nsignals;
+	long	ru_nvcsw;
+	long	ru_nivcsw;
+};
+
+pid_t __wait3_time32(int *status, int options, struct compat_rusage *usage)
+{
+	struct rusage ru;
+	int r = wait3(status, options, usage ? &ru : 0);
+	if (!r && usage) {
+		usage->ru_utime.tv_sec = ru.ru_utime.tv_sec;
+		usage->ru_utime.tv_usec = ru.ru_utime.tv_usec;
+		usage->ru_stime.tv_sec = ru.ru_stime.tv_sec;
+		usage->ru_stime.tv_usec = ru.ru_stime.tv_usec;
+		memcpy(&usage->ru_maxrss, &ru.ru_maxrss,
+			sizeof(struct compat_rusage) -
+			offsetof(struct compat_rusage, ru_maxrss));
+	}
+	return r;
+}
diff --git a/compat/time32/wait4_time32.c b/compat/time32/wait4_time32.c
new file mode 100644
index 00000000..918548e7
--- /dev/null
+++ b/compat/time32/wait4_time32.c
@@ -0,0 +1,40 @@
+#define _BSD_SOURCE
+#include "time32.h"
+#include <string.h>
+#include <stddef.h>
+#include <sys/wait.h>
+
+struct compat_rusage {
+	struct timeval32 ru_utime;
+	struct timeval32 ru_stime;
+	long	ru_maxrss;
+	long	ru_ixrss;
+	long	ru_idrss;
+	long	ru_isrss;
+	long	ru_minflt;
+	long	ru_majflt;
+	long	ru_nswap;
+	long	ru_inblock;
+	long	ru_oublock;
+	long	ru_msgsnd;
+	long	ru_msgrcv;
+	long	ru_nsignals;
+	long	ru_nvcsw;
+	long	ru_nivcsw;
+};
+
+pid_t __wait4_time32(pid_t pid, int *status, int options, struct compat_rusage *usage)
+{
+	struct rusage ru;
+	int r = wait4(pid, status, options, usage ? &ru : 0);
+	if (!r && usage) {
+		usage->ru_utime.tv_sec = ru.ru_utime.tv_sec;
+		usage->ru_utime.tv_usec = ru.ru_utime.tv_usec;
+		usage->ru_stime.tv_sec = ru.ru_stime.tv_sec;
+		usage->ru_stime.tv_usec = ru.ru_stime.tv_usec;
+		memcpy(&usage->ru_maxrss, &ru.ru_maxrss,
+			sizeof(struct compat_rusage) -
+			offsetof(struct compat_rusage, ru_maxrss));
+	}
+	return r;
+}
-- 
2.21.0


[-- Attachment #7: 0006-add-time64-redirect-for-and-redirecting-implementati.patch --]
[-- Type: text/plain, Size: 2360 bytes --]

From 6d86a424aa7fea178440e465f3e2fe9bc2d40cb1 Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Fri, 9 Aug 2019 15:26:23 -0400
Subject: [PATCH 06/17] add time64 redirect for, and redirecting implementation
 of, dlsym

if symbols are being redirected to provide the new time64 ABI, dlsym
must perform matching redirections; otherwise, it would poke a hole in
the magic and return pointers to functions that are not safe to call
from a caller using time64 types.

rather than duplicating a table of redirections, use the time64
symbols present in libc's symbol table to derive the decision for
whether a particular symbol needs to be redirected.
---
 include/dlfcn.h |  4 ++++
 ldso/dynlink.c  | 27 +++++++++++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/include/dlfcn.h b/include/dlfcn.h
index 78fb0733..13ab71dd 100644
--- a/include/dlfcn.h
+++ b/include/dlfcn.h
@@ -35,6 +35,10 @@ int dladdr(const void *, Dl_info *);
 int dlinfo(void *, int, void *);
 #endif
 
+#if _REDIR_TIME64
+__REDIR(dlsym, __dlsym_time64);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index 7ac0bf75..7810356b 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -2237,6 +2237,33 @@ hidden void *__dlsym(void *restrict p, const char *restrict s, void *restrict ra
 	return res;
 }
 
+hidden void *__dlsym_redir_time64(void *restrict p, const char *restrict s, void *restrict ra)
+{
+#if _REDIR_TIME64
+	const char *suffix, *suffix2 = "";
+	char redir[36];
+
+	/* Map the symbol name to a time64 version of itself according to the
+	 * pattern used for naming the redirected time64 symbols. */
+	size_t l = strnlen(s, sizeof redir);
+	if (l<4 || l==sizeof redir) goto no_redir;
+	if (s[l-2]=='_' && s[l-1]=='r') {
+		l -= 2;
+		suffix2 = s+l;
+	}
+	if (l<4) goto no_redir;
+	if (!strcmp(s+l-4, "time")) suffix = "64";
+	else suffix = "_time64";
+
+	/* Use the presence of the remapped symbol name in libc to determine
+	 * whether it's one that requires time64 redirection; replace if so. */
+	snprintf(redir, sizeof redir, "__%.*s%s%s", (int)l, s, suffix, suffix2);
+	if (find_sym(&ldso, redir, 1).sym) s = redir;
+no_redir:
+#endif
+	return __dlsym(p, s, ra);
+}
+
 int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void *data), void *data)
 {
 	struct dso *current;
-- 
2.21.0


[-- Attachment #8: 0007-add-__dlsym_time64-asm-entry-point-for-all-legacy-32.patch --]
[-- Type: text/plain, Size: 5142 bytes --]

From c2fd025acba7fc191dff2b3f343912c2a9d06e20 Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Sun, 20 Oct 2019 14:32:20 -0400
Subject: [PATCH 07/17] add __dlsym_time64 asm entry point for all
 legacy-32bit-time_t archs

these were produced programmatically via trivial sed on the
corresponding dlsym.s files.
---
 src/ldso/arm/dlsym_time64.s        |  8 ++++++++
 src/ldso/i386/dlsym_time64.s       | 11 +++++++++++
 src/ldso/m68k/dlsym_time64.s       | 12 ++++++++++++
 src/ldso/microblaze/dlsym_time64.s |  6 ++++++
 src/ldso/mips/dlsym_time64.s       | 17 +++++++++++++++++
 src/ldso/mipsn32/dlsym_time64.s    | 17 +++++++++++++++++
 src/ldso/or1k/dlsym_time64.s       |  6 ++++++
 src/ldso/powerpc/dlsym_time64.s    |  8 ++++++++
 src/ldso/sh/dlsym_time64.s         | 11 +++++++++++
 9 files changed, 96 insertions(+)
 create mode 100644 src/ldso/arm/dlsym_time64.s
 create mode 100644 src/ldso/i386/dlsym_time64.s
 create mode 100644 src/ldso/m68k/dlsym_time64.s
 create mode 100644 src/ldso/microblaze/dlsym_time64.s
 create mode 100644 src/ldso/mips/dlsym_time64.s
 create mode 100644 src/ldso/mipsn32/dlsym_time64.s
 create mode 100644 src/ldso/or1k/dlsym_time64.s
 create mode 100644 src/ldso/powerpc/dlsym_time64.s
 create mode 100644 src/ldso/sh/dlsym_time64.s

diff --git a/src/ldso/arm/dlsym_time64.s b/src/ldso/arm/dlsym_time64.s
new file mode 100644
index 00000000..8edd7e5b
--- /dev/null
+++ b/src/ldso/arm/dlsym_time64.s
@@ -0,0 +1,8 @@
+.syntax unified
+.text
+.global __dlsym_time64
+.hidden __dlsym_redir_time64
+.type __dlsym_time64,%function
+__dlsym_time64:
+	mov r2,lr
+	b __dlsym_redir_time64
diff --git a/src/ldso/i386/dlsym_time64.s b/src/ldso/i386/dlsym_time64.s
new file mode 100644
index 00000000..6a004434
--- /dev/null
+++ b/src/ldso/i386/dlsym_time64.s
@@ -0,0 +1,11 @@
+.text
+.global __dlsym_time64
+.hidden __dlsym_redir_time64
+.type __dlsym_time64,@function
+__dlsym_time64:
+	push (%esp)
+	push 12(%esp)
+	push 12(%esp)
+	call __dlsym_redir_time64
+	add $12,%esp
+	ret
diff --git a/src/ldso/m68k/dlsym_time64.s b/src/ldso/m68k/dlsym_time64.s
new file mode 100644
index 00000000..8540e113
--- /dev/null
+++ b/src/ldso/m68k/dlsym_time64.s
@@ -0,0 +1,12 @@
+.text
+.global __dlsym_time64
+.hidden __dlsym_redir_time64
+.type __dlsym_time64,@function
+__dlsym_time64:
+	move.l (%sp),-(%sp)
+	move.l 12(%sp),-(%sp)
+	move.l 12(%sp),-(%sp)
+	lea __dlsym_redir_time64-.-8,%a1
+	jsr (%pc,%a1)
+	add.l #12,%sp
+	rts
diff --git a/src/ldso/microblaze/dlsym_time64.s b/src/ldso/microblaze/dlsym_time64.s
new file mode 100644
index 00000000..83e68e30
--- /dev/null
+++ b/src/ldso/microblaze/dlsym_time64.s
@@ -0,0 +1,6 @@
+.global __dlsym_time64
+.hidden __dlsym_redir_time64
+.type   __dlsym_time64,@function
+__dlsym_time64:
+	brid    __dlsym_redir_time64
+	add     r7, r15, r0
diff --git a/src/ldso/mips/dlsym_time64.s b/src/ldso/mips/dlsym_time64.s
new file mode 100644
index 00000000..20ba674a
--- /dev/null
+++ b/src/ldso/mips/dlsym_time64.s
@@ -0,0 +1,17 @@
+.set noreorder
+.global __dlsym_time64
+.hidden __dlsym_redir_time64
+.type __dlsym_time64,@function
+__dlsym_time64:
+	lui $gp, %hi(_gp_disp)
+	addiu $gp, %lo(_gp_disp)
+	addu $gp, $gp, $25
+	move $6, $ra
+	lw $25, %call16(__dlsym_redir_time64)($gp)
+	addiu $sp, $sp, -16
+	sw $ra, 12($sp)
+	jalr $25
+	nop
+	lw $ra, 12($sp)
+	jr $ra
+	addiu $sp, $sp, 16
diff --git a/src/ldso/mipsn32/dlsym_time64.s b/src/ldso/mipsn32/dlsym_time64.s
new file mode 100644
index 00000000..3dc9c18c
--- /dev/null
+++ b/src/ldso/mipsn32/dlsym_time64.s
@@ -0,0 +1,17 @@
+.set	noreorder
+.global	__dlsym_time64
+.hidden	__dlsym_redir_time64
+.type	__dlsym_time64,@function
+__dlsym_time64:
+	lui	$3, %hi(%neg(%gp_rel(__dlsym_time64)))
+	addiu	$3, $3, %lo(%neg(%gp_rel(__dlsym_time64)))
+	addu	$3, $3, $25
+	move	$6, $ra
+	lw	$25, %got_disp(__dlsym_redir_time64)($3)
+	addiu	$sp, $sp, -32
+	sd	$ra, 16($sp)
+	jalr	$25
+	nop
+	ld	$ra, 16($sp)
+	jr	$ra
+	addiu	$sp, $sp, 32
diff --git a/src/ldso/or1k/dlsym_time64.s b/src/ldso/or1k/dlsym_time64.s
new file mode 100644
index 00000000..ea168378
--- /dev/null
+++ b/src/ldso/or1k/dlsym_time64.s
@@ -0,0 +1,6 @@
+.global __dlsym_time64
+.hidden __dlsym_redir_time64
+.type   __dlsym_time64,@function
+__dlsym_time64:
+	l.j	__dlsym_redir_time64
+	 l.ori	r5, r9, 0
diff --git a/src/ldso/powerpc/dlsym_time64.s b/src/ldso/powerpc/dlsym_time64.s
new file mode 100644
index 00000000..ddc30985
--- /dev/null
+++ b/src/ldso/powerpc/dlsym_time64.s
@@ -0,0 +1,8 @@
+	.text
+	.global __dlsym_time64
+	.hidden __dlsym_redir_time64
+	.type   __dlsym_time64,@function
+__dlsym_time64:
+	mflr    5                      # The return address is arg3.
+	b       __dlsym_redir_time64
+	.size   __dlsym_time64, .-dlsym
diff --git a/src/ldso/sh/dlsym_time64.s b/src/ldso/sh/dlsym_time64.s
new file mode 100644
index 00000000..785e23ed
--- /dev/null
+++ b/src/ldso/sh/dlsym_time64.s
@@ -0,0 +1,11 @@
+.text
+.global __dlsym_time64
+.hidden __dlsym_redir_time64
+.type   __dlsym_time64, @function
+__dlsym_time64:
+	mov.l L1, r0
+1:	braf  r0
+	 mov.l @r15, r6
+
+.align 2
+L1:	.long __dlsym_redir_time64@PLT-(1b+4-.)
-- 
2.21.0


[-- Attachment #9: 0008-add-framework-for-arch-provided-makefile-fragments-c.patch --]
[-- Type: text/plain, Size: 1705 bytes --]

From 57e02067ac4a7afad29384c344fca94d019f5436 Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Sun, 20 Oct 2019 20:03:20 -0400
Subject: [PATCH 08/17] add framework for arch-provided makefile fragments,
 compat source dirs

the immediate usage case for this is to let 32-bit archs moving to
64-bit time_t via symbol redirection pull in wrapper shims that
provide the old symbol names. in the future it may be used for other
types of compatibility-only source files that are not relevant to all
archs.
---
 Makefile | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index b46f8ca4..d636f5a9 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ includedir = $(prefix)/include
 libdir = $(prefix)/lib
 syslibdir = /lib
 
-SRC_DIRS = $(addprefix $(srcdir)/,src/* crt ldso)
+SRC_DIRS = $(addprefix $(srcdir)/,src/* crt ldso $(COMPAT_SRC_DIRS))
 BASE_GLOBS = $(addsuffix /*.c,$(SRC_DIRS))
 ARCH_GLOBS = $(addsuffix /$(ARCH)/*.[csS],$(SRC_DIRS))
 BASE_SRCS = $(sort $(wildcard $(BASE_GLOBS)))
@@ -27,7 +27,7 @@ ARCH_OBJS = $(patsubst $(srcdir)/%,%.o,$(basename $(ARCH_SRCS)))
 REPLACED_OBJS = $(sort $(subst /$(ARCH)/,/,$(ARCH_OBJS)))
 ALL_OBJS = $(addprefix obj/, $(filter-out $(REPLACED_OBJS), $(sort $(BASE_OBJS) $(ARCH_OBJS))))
 
-LIBC_OBJS = $(filter obj/src/%,$(ALL_OBJS))
+LIBC_OBJS = $(filter obj/src/%,$(ALL_OBJS)) $(filter obj/compat/%,$(ALL_OBJS))
 LDSO_OBJS = $(filter obj/ldso/%,$(ALL_OBJS:%.o=%.lo))
 CRT_OBJS = $(filter obj/crt/%,$(ALL_OBJS))
 
@@ -75,6 +75,7 @@ WRAPCC_CLANG = clang
 LDSO_PATHNAME = $(syslibdir)/ld-musl-$(ARCH)$(SUBARCH).so.1
 
 -include config.mak
+-include arch/$(ARCH)/arch.mak
 
 ifeq ($(ARCH),)
 
-- 
2.21.0


[-- Attachment #10: 0009-switch-i386-to-64-bit-time_t.patch --]
[-- Type: text/plain, Size: 4640 bytes --]

From 486ef0a0985abd9545fe4f25cf8471cf93be474f Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Fri, 2 Aug 2019 15:41:27 -0400
Subject: [PATCH 09/17] switch i386 to 64-bit time_t

---
 arch/i386/arch.mak           |  1 +
 arch/i386/bits/alltypes.h.in |  5 +++--
 arch/i386/bits/ipcstat.h     |  2 +-
 arch/i386/bits/msg.h         | 15 +++++++++------
 arch/i386/bits/sem.h         | 10 ++++++----
 arch/i386/bits/shm.h         | 16 ++++++++++------
 arch/i386/bits/stat.h        |  6 +++++-
 arch/i386/syscall_arch.h     |  4 +++-
 8 files changed, 38 insertions(+), 21 deletions(-)
 create mode 100644 arch/i386/arch.mak

diff --git a/arch/i386/arch.mak b/arch/i386/arch.mak
new file mode 100644
index 00000000..aa4d05ce
--- /dev/null
+++ b/arch/i386/arch.mak
@@ -0,0 +1 @@
+COMPAT_SRC_DIRS = compat/time32
diff --git a/arch/i386/bits/alltypes.h.in b/arch/i386/bits/alltypes.h.in
index f033f376..74e599a2 100644
--- a/arch/i386/bits/alltypes.h.in
+++ b/arch/i386/bits/alltypes.h.in
@@ -1,3 +1,4 @@
+#define _REDIR_TIME64 1
 #define _Addr int
 #define _Int64 long long
 #define _Reg int
@@ -29,5 +30,5 @@ TYPEDEF struct { __attribute__((__aligned__(8))) long long __ll; long double __l
 TYPEDEF struct { alignas(8) long long __ll; long double __ld; } max_align_t;
 #endif
 
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
+TYPEDEF long long time_t;
+TYPEDEF long long suseconds_t;
diff --git a/arch/i386/bits/ipcstat.h b/arch/i386/bits/ipcstat.h
index 0018ad1e..4f4fcb0c 100644
--- a/arch/i386/bits/ipcstat.h
+++ b/arch/i386/bits/ipcstat.h
@@ -1 +1 @@
-#define IPC_STAT 2
+#define IPC_STAT 0x102
diff --git a/arch/i386/bits/msg.h b/arch/i386/bits/msg.h
index bc8436c4..7bbbb2bf 100644
--- a/arch/i386/bits/msg.h
+++ b/arch/i386/bits/msg.h
@@ -1,15 +1,18 @@
 struct msqid_ds {
 	struct ipc_perm msg_perm;
-	time_t msg_stime;
-	int __unused1;
-	time_t msg_rtime;
-	int __unused2;
-	time_t msg_ctime;
-	int __unused3;
+	unsigned long __msg_stime_lo;
+	unsigned long __msg_stime_hi;
+	unsigned long __msg_rtime_lo;
+	unsigned long __msg_rtime_hi;
+	unsigned long __msg_ctime_lo;
+	unsigned long __msg_ctime_hi;
 	unsigned long msg_cbytes;
 	msgqnum_t msg_qnum;
 	msglen_t msg_qbytes;
 	pid_t msg_lspid;
 	pid_t msg_lrpid;
 	unsigned long __unused[2];
+	time_t msg_stime;
+	time_t msg_rtime;
+	time_t msg_ctime;
 };
diff --git a/arch/i386/bits/sem.h b/arch/i386/bits/sem.h
index e61571c1..65661542 100644
--- a/arch/i386/bits/sem.h
+++ b/arch/i386/bits/sem.h
@@ -1,11 +1,13 @@
 struct semid_ds {
 	struct ipc_perm sem_perm;
-	time_t sem_otime;
-	long __unused1;
-	time_t sem_ctime;
-	long __unused2;
+	unsigned long __sem_otime_lo;
+	unsigned long __sem_otime_hi;
+	unsigned long __sem_ctime_lo;
+	unsigned long __sem_ctime_hi;
 	unsigned short sem_nsems;
 	char __sem_nsems_pad[sizeof(long)-sizeof(short)];
 	long __unused3;
 	long __unused4;
+	time_t sem_otime;
+	time_t sem_ctime;
 };
diff --git a/arch/i386/bits/shm.h b/arch/i386/bits/shm.h
index 81b2a29a..725fb469 100644
--- a/arch/i386/bits/shm.h
+++ b/arch/i386/bits/shm.h
@@ -3,17 +3,21 @@
 struct shmid_ds {
 	struct ipc_perm shm_perm;
 	size_t shm_segsz;
-	time_t shm_atime;
-	int __unused1;
-	time_t shm_dtime;
-	int __unused2;
-	time_t shm_ctime;
-	int __unused3;
+	unsigned long __shm_atime_lo;
+	unsigned long __shm_atime_hi;
+	unsigned long __shm_dtime_lo;
+	unsigned long __shm_dtime_hi;
+	unsigned long __shm_ctime_lo;
+	unsigned long __shm_ctime_hi;
 	pid_t shm_cpid;
 	pid_t shm_lpid;
 	unsigned long shm_nattch;
 	unsigned long __pad1;
 	unsigned long __pad2;
+	unsigned long __pad3;
+	time_t shm_atime;
+	time_t shm_dtime;
+	time_t shm_ctime;
 };
 
 struct shminfo {
diff --git a/arch/i386/bits/stat.h b/arch/i386/bits/stat.h
index 22b19bbf..5d7828cf 100644
--- a/arch/i386/bits/stat.h
+++ b/arch/i386/bits/stat.h
@@ -14,8 +14,12 @@ struct stat {
 	off_t st_size;
 	blksize_t st_blksize;
 	blkcnt_t st_blocks;
+	struct {
+		long tv_sec;
+		long tv_nsec;
+	} __st_atim32, __st_mtim32, __st_ctim32;
+	ino_t st_ino;
 	struct timespec st_atim;
 	struct timespec st_mtim;
 	struct timespec st_ctim;
-	ino_t st_ino;
 };
diff --git a/arch/i386/syscall_arch.h b/arch/i386/syscall_arch.h
index 22b0b28b..69642e57 100644
--- a/arch/i386/syscall_arch.h
+++ b/arch/i386/syscall_arch.h
@@ -83,7 +83,9 @@ static inline long __syscall6(long n, long a1, long a2, long a3, long a4, long a
 }
 
 #define VDSO_USEFUL
-#define VDSO_CGT_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_VER "LINUX_2.6"
+#define VDSO_CGT_SYM "__vdso_clock_gettime64"
 #define VDSO_CGT_VER "LINUX_2.6"
 
 #define SYSCALL_USE_SOCKETCALL
-- 
2.21.0


[-- Attachment #11: 0010-switch-sh-to-64-bit-time_t.patch --]
[-- Type: text/plain, Size: 4008 bytes --]

From e40867626101f96d80ece84d5ed77782c3b7bd27 Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Sun, 20 Oct 2019 14:49:31 -0400
Subject: [PATCH 10/17] switch sh to 64-bit time_t

---
 arch/sh/arch.mak           |  1 +
 arch/sh/bits/alltypes.h.in |  5 +++--
 arch/sh/bits/ipcstat.h     |  2 +-
 arch/sh/bits/msg.h         | 15 +++++++++------
 arch/sh/bits/sem.h         | 10 ++++++----
 arch/sh/bits/shm.h         | 16 ++++++++++------
 arch/sh/bits/stat.h        |  6 +++++-
 7 files changed, 35 insertions(+), 20 deletions(-)
 create mode 100644 arch/sh/arch.mak

diff --git a/arch/sh/arch.mak b/arch/sh/arch.mak
new file mode 100644
index 00000000..aa4d05ce
--- /dev/null
+++ b/arch/sh/arch.mak
@@ -0,0 +1 @@
+COMPAT_SRC_DIRS = compat/time32
diff --git a/arch/sh/bits/alltypes.h.in b/arch/sh/bits/alltypes.h.in
index b32f913c..04e0fcca 100644
--- a/arch/sh/bits/alltypes.h.in
+++ b/arch/sh/bits/alltypes.h.in
@@ -1,3 +1,4 @@
+#define _REDIR_TIME64 1
 #define _Addr int
 #define _Int64 long long
 #define _Reg int
@@ -23,5 +24,5 @@ TYPEDEF double double_t;
 
 TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
 
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
+TYPEDEF long long time_t;
+TYPEDEF long long suseconds_t;
diff --git a/arch/sh/bits/ipcstat.h b/arch/sh/bits/ipcstat.h
index 0018ad1e..4f4fcb0c 100644
--- a/arch/sh/bits/ipcstat.h
+++ b/arch/sh/bits/ipcstat.h
@@ -1 +1 @@
-#define IPC_STAT 2
+#define IPC_STAT 0x102
diff --git a/arch/sh/bits/msg.h b/arch/sh/bits/msg.h
index bc8436c4..7bbbb2bf 100644
--- a/arch/sh/bits/msg.h
+++ b/arch/sh/bits/msg.h
@@ -1,15 +1,18 @@
 struct msqid_ds {
 	struct ipc_perm msg_perm;
-	time_t msg_stime;
-	int __unused1;
-	time_t msg_rtime;
-	int __unused2;
-	time_t msg_ctime;
-	int __unused3;
+	unsigned long __msg_stime_lo;
+	unsigned long __msg_stime_hi;
+	unsigned long __msg_rtime_lo;
+	unsigned long __msg_rtime_hi;
+	unsigned long __msg_ctime_lo;
+	unsigned long __msg_ctime_hi;
 	unsigned long msg_cbytes;
 	msgqnum_t msg_qnum;
 	msglen_t msg_qbytes;
 	pid_t msg_lspid;
 	pid_t msg_lrpid;
 	unsigned long __unused[2];
+	time_t msg_stime;
+	time_t msg_rtime;
+	time_t msg_ctime;
 };
diff --git a/arch/sh/bits/sem.h b/arch/sh/bits/sem.h
index d383d4ea..544e3d2a 100644
--- a/arch/sh/bits/sem.h
+++ b/arch/sh/bits/sem.h
@@ -1,9 +1,9 @@
 struct semid_ds {
 	struct ipc_perm sem_perm;
-	time_t sem_otime;
-	long __unused1;
-	time_t sem_ctime;
-	long __unused2;
+	unsigned long __sem_otime_lo;
+	unsigned long __sem_otime_hi;
+	unsigned long __sem_ctime_lo;
+	unsigned long __sem_ctime_hi;
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 	unsigned short sem_nsems;
 	char __sem_nsems_pad[sizeof(long)-sizeof(short)];
@@ -13,4 +13,6 @@ struct semid_ds {
 #endif
 	long __unused3;
 	long __unused4;
+	time_t sem_otime;
+	time_t sem_ctime;
 };
diff --git a/arch/sh/bits/shm.h b/arch/sh/bits/shm.h
index 6cdac131..adc01e34 100644
--- a/arch/sh/bits/shm.h
+++ b/arch/sh/bits/shm.h
@@ -3,17 +3,21 @@
 struct shmid_ds {
 	struct ipc_perm shm_perm;
 	size_t shm_segsz;
-	time_t shm_atime;
-	int __unused1;
-	time_t shm_dtime;
-	int __unused2;
-	time_t shm_ctime;
-	int __unused3;
+	unsigned long __shm_atime_lo;
+	unsigned long __shm_atime_hi;
+	unsigned long __shm_dtime_lo;
+	unsigned long __shm_dtime_hi;
+	unsigned long __shm_ctime_lo;
+	unsigned long __shm_ctime_hi;
 	pid_t shm_cpid;
 	pid_t shm_lpid;
 	unsigned long shm_nattch;
 	unsigned long __pad1;
 	unsigned long __pad2;
+	unsigned long __pad3;
+	time_t shm_atime;
+	time_t shm_dtime;
+	time_t shm_ctime;
 };
 
 struct shminfo {
diff --git a/arch/sh/bits/stat.h b/arch/sh/bits/stat.h
index 22b19bbf..5d7828cf 100644
--- a/arch/sh/bits/stat.h
+++ b/arch/sh/bits/stat.h
@@ -14,8 +14,12 @@ struct stat {
 	off_t st_size;
 	blksize_t st_blksize;
 	blkcnt_t st_blocks;
+	struct {
+		long tv_sec;
+		long tv_nsec;
+	} __st_atim32, __st_mtim32, __st_ctim32;
+	ino_t st_ino;
 	struct timespec st_atim;
 	struct timespec st_mtim;
 	struct timespec st_ctim;
-	ino_t st_ino;
 };
-- 
2.21.0


[-- Attachment #12: 0011-switch-arm-to-64-bit-time_t.patch --]
[-- Type: text/plain, Size: 4605 bytes --]

From 78348d402216a05e2d664e51e41b32b40de4ca83 Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Sun, 20 Oct 2019 18:55:29 -0400
Subject: [PATCH 11/17] switch arm to 64-bit time_t

---
 arch/arm/arch.mak           |  1 +
 arch/arm/bits/alltypes.h.in |  5 +++--
 arch/arm/bits/ipcstat.h     |  2 +-
 arch/arm/bits/msg.h         | 15 +++++++++------
 arch/arm/bits/sem.h         | 10 ++++++----
 arch/arm/bits/shm.h         | 16 ++++++++++------
 arch/arm/bits/stat.h        |  6 +++++-
 arch/arm/syscall_arch.h     |  4 +++-
 8 files changed, 38 insertions(+), 21 deletions(-)
 create mode 100644 arch/arm/arch.mak

diff --git a/arch/arm/arch.mak b/arch/arm/arch.mak
new file mode 100644
index 00000000..aa4d05ce
--- /dev/null
+++ b/arch/arm/arch.mak
@@ -0,0 +1 @@
+COMPAT_SRC_DIRS = compat/time32
diff --git a/arch/arm/bits/alltypes.h.in b/arch/arm/bits/alltypes.h.in
index d2700bd9..40bd30ea 100644
--- a/arch/arm/bits/alltypes.h.in
+++ b/arch/arm/bits/alltypes.h.in
@@ -1,3 +1,4 @@
+#define _REDIR_TIME64 1
 #define _Addr int
 #define _Int64 long long
 #define _Reg int
@@ -19,5 +20,5 @@ TYPEDEF double double_t;
 
 TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
 
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
+TYPEDEF long long time_t;
+TYPEDEF long long suseconds_t;
diff --git a/arch/arm/bits/ipcstat.h b/arch/arm/bits/ipcstat.h
index 0018ad1e..4f4fcb0c 100644
--- a/arch/arm/bits/ipcstat.h
+++ b/arch/arm/bits/ipcstat.h
@@ -1 +1 @@
-#define IPC_STAT 2
+#define IPC_STAT 0x102
diff --git a/arch/arm/bits/msg.h b/arch/arm/bits/msg.h
index bc8436c4..7bbbb2bf 100644
--- a/arch/arm/bits/msg.h
+++ b/arch/arm/bits/msg.h
@@ -1,15 +1,18 @@
 struct msqid_ds {
 	struct ipc_perm msg_perm;
-	time_t msg_stime;
-	int __unused1;
-	time_t msg_rtime;
-	int __unused2;
-	time_t msg_ctime;
-	int __unused3;
+	unsigned long __msg_stime_lo;
+	unsigned long __msg_stime_hi;
+	unsigned long __msg_rtime_lo;
+	unsigned long __msg_rtime_hi;
+	unsigned long __msg_ctime_lo;
+	unsigned long __msg_ctime_hi;
 	unsigned long msg_cbytes;
 	msgqnum_t msg_qnum;
 	msglen_t msg_qbytes;
 	pid_t msg_lspid;
 	pid_t msg_lrpid;
 	unsigned long __unused[2];
+	time_t msg_stime;
+	time_t msg_rtime;
+	time_t msg_ctime;
 };
diff --git a/arch/arm/bits/sem.h b/arch/arm/bits/sem.h
index d383d4ea..544e3d2a 100644
--- a/arch/arm/bits/sem.h
+++ b/arch/arm/bits/sem.h
@@ -1,9 +1,9 @@
 struct semid_ds {
 	struct ipc_perm sem_perm;
-	time_t sem_otime;
-	long __unused1;
-	time_t sem_ctime;
-	long __unused2;
+	unsigned long __sem_otime_lo;
+	unsigned long __sem_otime_hi;
+	unsigned long __sem_ctime_lo;
+	unsigned long __sem_ctime_hi;
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 	unsigned short sem_nsems;
 	char __sem_nsems_pad[sizeof(long)-sizeof(short)];
@@ -13,4 +13,6 @@ struct semid_ds {
 #endif
 	long __unused3;
 	long __unused4;
+	time_t sem_otime;
+	time_t sem_ctime;
 };
diff --git a/arch/arm/bits/shm.h b/arch/arm/bits/shm.h
index 81b2a29a..725fb469 100644
--- a/arch/arm/bits/shm.h
+++ b/arch/arm/bits/shm.h
@@ -3,17 +3,21 @@
 struct shmid_ds {
 	struct ipc_perm shm_perm;
 	size_t shm_segsz;
-	time_t shm_atime;
-	int __unused1;
-	time_t shm_dtime;
-	int __unused2;
-	time_t shm_ctime;
-	int __unused3;
+	unsigned long __shm_atime_lo;
+	unsigned long __shm_atime_hi;
+	unsigned long __shm_dtime_lo;
+	unsigned long __shm_dtime_hi;
+	unsigned long __shm_ctime_lo;
+	unsigned long __shm_ctime_hi;
 	pid_t shm_cpid;
 	pid_t shm_lpid;
 	unsigned long shm_nattch;
 	unsigned long __pad1;
 	unsigned long __pad2;
+	unsigned long __pad3;
+	time_t shm_atime;
+	time_t shm_dtime;
+	time_t shm_ctime;
 };
 
 struct shminfo {
diff --git a/arch/arm/bits/stat.h b/arch/arm/bits/stat.h
index 22b19bbf..5d7828cf 100644
--- a/arch/arm/bits/stat.h
+++ b/arch/arm/bits/stat.h
@@ -14,8 +14,12 @@ struct stat {
 	off_t st_size;
 	blksize_t st_blksize;
 	blkcnt_t st_blocks;
+	struct {
+		long tv_sec;
+		long tv_nsec;
+	} __st_atim32, __st_mtim32, __st_ctim32;
+	ino_t st_ino;
 	struct timespec st_atim;
 	struct timespec st_mtim;
 	struct timespec st_ctim;
-	ino_t st_ino;
 };
diff --git a/arch/arm/syscall_arch.h b/arch/arm/syscall_arch.h
index 53fb155c..4b08762d 100644
--- a/arch/arm/syscall_arch.h
+++ b/arch/arm/syscall_arch.h
@@ -99,7 +99,9 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo
 }
 
 #define VDSO_USEFUL
-#define VDSO_CGT_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_VER "LINUX_2.6"
+#define VDSO_CGT_SYM "__vdso_clock_gettime64"
 #define VDSO_CGT_VER "LINUX_2.6"
 
 #define SYSCALL_FADVISE_6_ARG
-- 
2.21.0


[-- Attachment #13: 0012-switch-m68k-to-64-bit-time_t.patch --]
[-- Type: text/plain, Size: 4006 bytes --]

From 58a8d251770e4f25b42923a69218dfcb685e2992 Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Sun, 20 Oct 2019 19:00:01 -0400
Subject: [PATCH 12/17] switch m68k to 64-bit time_t

---
 arch/m68k/arch.mak           |  1 +
 arch/m68k/bits/alltypes.h.in |  5 +++--
 arch/m68k/bits/ipcstat.h     |  2 +-
 arch/m68k/bits/msg.h         | 15 +++++++++------
 arch/m68k/bits/sem.h         | 10 ++++++----
 arch/m68k/bits/shm.h         | 16 ++++++++++------
 arch/m68k/bits/stat.h        |  6 +++++-
 7 files changed, 35 insertions(+), 20 deletions(-)
 create mode 100644 arch/m68k/arch.mak

diff --git a/arch/m68k/arch.mak b/arch/m68k/arch.mak
new file mode 100644
index 00000000..aa4d05ce
--- /dev/null
+++ b/arch/m68k/arch.mak
@@ -0,0 +1 @@
+COMPAT_SRC_DIRS = compat/time32
diff --git a/arch/m68k/bits/alltypes.h.in b/arch/m68k/bits/alltypes.h.in
index 922c2ce5..a92d1f07 100644
--- a/arch/m68k/bits/alltypes.h.in
+++ b/arch/m68k/bits/alltypes.h.in
@@ -1,3 +1,4 @@
+#define _REDIR_TIME64 1
 #define _Addr int
 #define _Int64 long long
 #define _Reg int
@@ -23,5 +24,5 @@ TYPEDEF long double double_t;
 
 TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
 
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
+TYPEDEF long long time_t;
+TYPEDEF long long suseconds_t;
diff --git a/arch/m68k/bits/ipcstat.h b/arch/m68k/bits/ipcstat.h
index 0018ad1e..4f4fcb0c 100644
--- a/arch/m68k/bits/ipcstat.h
+++ b/arch/m68k/bits/ipcstat.h
@@ -1 +1 @@
-#define IPC_STAT 2
+#define IPC_STAT 0x102
diff --git a/arch/m68k/bits/msg.h b/arch/m68k/bits/msg.h
index bc8436c4..7bbbb2bf 100644
--- a/arch/m68k/bits/msg.h
+++ b/arch/m68k/bits/msg.h
@@ -1,15 +1,18 @@
 struct msqid_ds {
 	struct ipc_perm msg_perm;
-	time_t msg_stime;
-	int __unused1;
-	time_t msg_rtime;
-	int __unused2;
-	time_t msg_ctime;
-	int __unused3;
+	unsigned long __msg_stime_lo;
+	unsigned long __msg_stime_hi;
+	unsigned long __msg_rtime_lo;
+	unsigned long __msg_rtime_hi;
+	unsigned long __msg_ctime_lo;
+	unsigned long __msg_ctime_hi;
 	unsigned long msg_cbytes;
 	msgqnum_t msg_qnum;
 	msglen_t msg_qbytes;
 	pid_t msg_lspid;
 	pid_t msg_lrpid;
 	unsigned long __unused[2];
+	time_t msg_stime;
+	time_t msg_rtime;
+	time_t msg_ctime;
 };
diff --git a/arch/m68k/bits/sem.h b/arch/m68k/bits/sem.h
index 08faafea..d88338e6 100644
--- a/arch/m68k/bits/sem.h
+++ b/arch/m68k/bits/sem.h
@@ -1,11 +1,13 @@
 struct semid_ds {
 	struct ipc_perm sem_perm;
-	time_t sem_otime;
-	long __unused1;
-	time_t sem_ctime;
-	long __unused2;
+	unsigned long __sem_otime_lo;
+	unsigned long __sem_otime_hi;
+	unsigned long __sem_ctime_lo;
+	unsigned long __sem_ctime_hi;
 	char __sem_nsems_pad[sizeof(long)-sizeof(short)];
 	unsigned short sem_nsems;
 	long __unused3;
 	long __unused4;
+	time_t sem_otime;
+	time_t sem_ctime;
 };
diff --git a/arch/m68k/bits/shm.h b/arch/m68k/bits/shm.h
index 81b2a29a..725fb469 100644
--- a/arch/m68k/bits/shm.h
+++ b/arch/m68k/bits/shm.h
@@ -3,17 +3,21 @@
 struct shmid_ds {
 	struct ipc_perm shm_perm;
 	size_t shm_segsz;
-	time_t shm_atime;
-	int __unused1;
-	time_t shm_dtime;
-	int __unused2;
-	time_t shm_ctime;
-	int __unused3;
+	unsigned long __shm_atime_lo;
+	unsigned long __shm_atime_hi;
+	unsigned long __shm_dtime_lo;
+	unsigned long __shm_dtime_hi;
+	unsigned long __shm_ctime_lo;
+	unsigned long __shm_ctime_hi;
 	pid_t shm_cpid;
 	pid_t shm_lpid;
 	unsigned long shm_nattch;
 	unsigned long __pad1;
 	unsigned long __pad2;
+	unsigned long __pad3;
+	time_t shm_atime;
+	time_t shm_dtime;
+	time_t shm_ctime;
 };
 
 struct shminfo {
diff --git a/arch/m68k/bits/stat.h b/arch/m68k/bits/stat.h
index 0f7b66a1..f8768147 100644
--- a/arch/m68k/bits/stat.h
+++ b/arch/m68k/bits/stat.h
@@ -14,8 +14,12 @@ struct stat {
 	off_t st_size;
 	blksize_t st_blksize;
 	blkcnt_t st_blocks;
+	struct {
+		long tv_sec;
+		long tv_nsec;
+	} __st_atim32, __st_mtim32, __st_ctim32;
+	ino_t st_ino;
 	struct timespec st_atim;
 	struct timespec st_mtim;
 	struct timespec st_ctim;
-	ino_t st_ino;
 };
-- 
2.21.0


[-- Attachment #14: 0013-switch-microblaze-to-64-bit-time_t.patch --]
[-- Type: text/plain, Size: 4323 bytes --]

From dc87454d5c13ef3f91338e0d9c9ff96071ee42bf Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Sun, 20 Oct 2019 19:03:36 -0400
Subject: [PATCH 13/17] switch microblaze to 64-bit time_t

---
 arch/microblaze/arch.mak           |  1 +
 arch/microblaze/bits/alltypes.h.in |  5 +++--
 arch/microblaze/bits/ipcstat.h     |  2 +-
 arch/microblaze/bits/msg.h         | 15 +++++++++------
 arch/microblaze/bits/sem.h         | 10 ++++++----
 arch/microblaze/bits/shm.h         | 16 ++++++++++------
 arch/microblaze/bits/stat.h        |  6 +++++-
 7 files changed, 35 insertions(+), 20 deletions(-)
 create mode 100644 arch/microblaze/arch.mak

diff --git a/arch/microblaze/arch.mak b/arch/microblaze/arch.mak
new file mode 100644
index 00000000..aa4d05ce
--- /dev/null
+++ b/arch/microblaze/arch.mak
@@ -0,0 +1 @@
+COMPAT_SRC_DIRS = compat/time32
diff --git a/arch/microblaze/bits/alltypes.h.in b/arch/microblaze/bits/alltypes.h.in
index b958604e..6f69b4f9 100644
--- a/arch/microblaze/bits/alltypes.h.in
+++ b/arch/microblaze/bits/alltypes.h.in
@@ -1,3 +1,4 @@
+#define _REDIR_TIME64 1
 #define _Addr int
 #define _Int64 long long
 #define _Reg int
@@ -19,5 +20,5 @@ TYPEDEF double double_t;
 
 TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
 
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
+TYPEDEF long long time_t;
+TYPEDEF long long suseconds_t;
diff --git a/arch/microblaze/bits/ipcstat.h b/arch/microblaze/bits/ipcstat.h
index 0018ad1e..4f4fcb0c 100644
--- a/arch/microblaze/bits/ipcstat.h
+++ b/arch/microblaze/bits/ipcstat.h
@@ -1 +1 @@
-#define IPC_STAT 2
+#define IPC_STAT 0x102
diff --git a/arch/microblaze/bits/msg.h b/arch/microblaze/bits/msg.h
index bc8436c4..7bbbb2bf 100644
--- a/arch/microblaze/bits/msg.h
+++ b/arch/microblaze/bits/msg.h
@@ -1,15 +1,18 @@
 struct msqid_ds {
 	struct ipc_perm msg_perm;
-	time_t msg_stime;
-	int __unused1;
-	time_t msg_rtime;
-	int __unused2;
-	time_t msg_ctime;
-	int __unused3;
+	unsigned long __msg_stime_lo;
+	unsigned long __msg_stime_hi;
+	unsigned long __msg_rtime_lo;
+	unsigned long __msg_rtime_hi;
+	unsigned long __msg_ctime_lo;
+	unsigned long __msg_ctime_hi;
 	unsigned long msg_cbytes;
 	msgqnum_t msg_qnum;
 	msglen_t msg_qbytes;
 	pid_t msg_lspid;
 	pid_t msg_lrpid;
 	unsigned long __unused[2];
+	time_t msg_stime;
+	time_t msg_rtime;
+	time_t msg_ctime;
 };
diff --git a/arch/microblaze/bits/sem.h b/arch/microblaze/bits/sem.h
index d383d4ea..544e3d2a 100644
--- a/arch/microblaze/bits/sem.h
+++ b/arch/microblaze/bits/sem.h
@@ -1,9 +1,9 @@
 struct semid_ds {
 	struct ipc_perm sem_perm;
-	time_t sem_otime;
-	long __unused1;
-	time_t sem_ctime;
-	long __unused2;
+	unsigned long __sem_otime_lo;
+	unsigned long __sem_otime_hi;
+	unsigned long __sem_ctime_lo;
+	unsigned long __sem_ctime_hi;
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 	unsigned short sem_nsems;
 	char __sem_nsems_pad[sizeof(long)-sizeof(short)];
@@ -13,4 +13,6 @@ struct semid_ds {
 #endif
 	long __unused3;
 	long __unused4;
+	time_t sem_otime;
+	time_t sem_ctime;
 };
diff --git a/arch/microblaze/bits/shm.h b/arch/microblaze/bits/shm.h
index 81b2a29a..725fb469 100644
--- a/arch/microblaze/bits/shm.h
+++ b/arch/microblaze/bits/shm.h
@@ -3,17 +3,21 @@
 struct shmid_ds {
 	struct ipc_perm shm_perm;
 	size_t shm_segsz;
-	time_t shm_atime;
-	int __unused1;
-	time_t shm_dtime;
-	int __unused2;
-	time_t shm_ctime;
-	int __unused3;
+	unsigned long __shm_atime_lo;
+	unsigned long __shm_atime_hi;
+	unsigned long __shm_dtime_lo;
+	unsigned long __shm_dtime_hi;
+	unsigned long __shm_ctime_lo;
+	unsigned long __shm_ctime_hi;
 	pid_t shm_cpid;
 	pid_t shm_lpid;
 	unsigned long shm_nattch;
 	unsigned long __pad1;
 	unsigned long __pad2;
+	unsigned long __pad3;
+	time_t shm_atime;
+	time_t shm_dtime;
+	time_t shm_ctime;
 };
 
 struct shminfo {
diff --git a/arch/microblaze/bits/stat.h b/arch/microblaze/bits/stat.h
index ce6a6bd0..8a4d509a 100644
--- a/arch/microblaze/bits/stat.h
+++ b/arch/microblaze/bits/stat.h
@@ -14,8 +14,12 @@ struct stat {
 	blksize_t st_blksize;
 	int __st_blksize_padding;
 	blkcnt_t st_blocks;
+	struct {
+		long tv_sec;
+		long tv_nsec;
+	} __st_atim32, __st_mtim32, __st_ctim32;
+	unsigned __unused[2];
 	struct timespec st_atim;
 	struct timespec st_mtim;
 	struct timespec st_ctim;
-	unsigned __unused[2];
 };
-- 
2.21.0


[-- Attachment #15: 0014-switch-mips-to-64-bit-time_t.patch --]
[-- Type: text/plain, Size: 5203 bytes --]

From cb385cabc7259fa85d8b63a6f170309d3650e7fd Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Sun, 20 Oct 2019 19:12:23 -0400
Subject: [PATCH 14/17] switch mips to 64-bit time_t

---
 arch/mips/arch.mak           |  1 +
 arch/mips/bits/alltypes.h.in |  5 +++--
 arch/mips/bits/ipcstat.h     |  2 +-
 arch/mips/bits/msg.h         | 27 +++++++++++++++------------
 arch/mips/bits/sem.h         | 10 ++++++----
 arch/mips/bits/shm.h         | 15 ++++++++++-----
 arch/mips/bits/stat.h        | 12 ++++++++----
 arch/mips/syscall_arch.h     |  4 +++-
 8 files changed, 47 insertions(+), 29 deletions(-)
 create mode 100644 arch/mips/arch.mak

diff --git a/arch/mips/arch.mak b/arch/mips/arch.mak
new file mode 100644
index 00000000..aa4d05ce
--- /dev/null
+++ b/arch/mips/arch.mak
@@ -0,0 +1 @@
+COMPAT_SRC_DIRS = compat/time32
diff --git a/arch/mips/bits/alltypes.h.in b/arch/mips/bits/alltypes.h.in
index 9544b496..32544cfe 100644
--- a/arch/mips/bits/alltypes.h.in
+++ b/arch/mips/bits/alltypes.h.in
@@ -1,3 +1,4 @@
+#define _REDIR_TIME64 1
 #define _Addr int
 #define _Int64 long long
 #define _Reg int
@@ -19,5 +20,5 @@ TYPEDEF double double_t;
 
 TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
 
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
+TYPEDEF long long time_t;
+TYPEDEF long long suseconds_t;
diff --git a/arch/mips/bits/ipcstat.h b/arch/mips/bits/ipcstat.h
index 0018ad1e..4f4fcb0c 100644
--- a/arch/mips/bits/ipcstat.h
+++ b/arch/mips/bits/ipcstat.h
@@ -1 +1 @@
-#define IPC_STAT 2
+#define IPC_STAT 0x102
diff --git a/arch/mips/bits/msg.h b/arch/mips/bits/msg.h
index f28aece8..c734dbb5 100644
--- a/arch/mips/bits/msg.h
+++ b/arch/mips/bits/msg.h
@@ -1,19 +1,19 @@
 struct msqid_ds {
 	struct ipc_perm msg_perm;
 #if _MIPSEL || __MIPSEL || __MIPSEL__
-	time_t msg_stime;
-	int __unused1;
-	time_t msg_rtime;
-	int __unused2;
-	time_t msg_ctime;
-	int __unused3;
+	unsigned long __msg_stime_lo;
+	unsigned long __msg_stime_hi;
+	unsigned long __msg_rtime_lo;
+	unsigned long __msg_rtime_hi;
+	unsigned long __msg_ctime_lo;
+	unsigned long __msg_ctime_hi;
 #else
-	int __unused1;
-	time_t msg_stime;
-	int __unused2;
-	time_t msg_rtime;
-	int __unused3;
-	time_t msg_ctime;
+	unsigned long __msg_stime_hi;
+	unsigned long __msg_stime_lo;
+	unsigned long __msg_rtime_hi;
+	unsigned long __msg_rtime_lo;
+	unsigned long __msg_ctime_hi;
+	unsigned long __msg_ctime_lo;
 #endif
 	unsigned long msg_cbytes;
 	msgqnum_t msg_qnum;
@@ -21,4 +21,7 @@ struct msqid_ds {
 	pid_t msg_lspid;
 	pid_t msg_lrpid;
 	unsigned long __unused[2];
+	time_t msg_stime;
+	time_t msg_rtime;
+	time_t msg_ctime;
 };
diff --git a/arch/mips/bits/sem.h b/arch/mips/bits/sem.h
index 5184eb59..fe6f0948 100644
--- a/arch/mips/bits/sem.h
+++ b/arch/mips/bits/sem.h
@@ -1,7 +1,7 @@
 struct semid_ds {
 	struct ipc_perm sem_perm;
-	time_t sem_otime;
-	time_t sem_ctime;
+	unsigned long __sem_otime_lo;
+	unsigned long __sem_ctime_lo;
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 	unsigned short sem_nsems;
 	char __sem_nsems_pad[sizeof(long)-sizeof(short)];
@@ -9,6 +9,8 @@ struct semid_ds {
 	char __sem_nsems_pad[sizeof(long)-sizeof(short)];
 	unsigned short sem_nsems;
 #endif
-	long __unused3;
-	long __unused4;
+	unsigned long __sem_otime_hi;
+	unsigned long __sem_ctime_hi;
+	time_t sem_otime;
+	time_t sem_ctime;
 };
diff --git a/arch/mips/bits/shm.h b/arch/mips/bits/shm.h
index 8d193781..ab8c642d 100644
--- a/arch/mips/bits/shm.h
+++ b/arch/mips/bits/shm.h
@@ -3,14 +3,19 @@
 struct shmid_ds {
 	struct ipc_perm shm_perm;
 	size_t shm_segsz;
-	time_t shm_atime;
-	time_t shm_dtime;
-	time_t shm_ctime;
+	unsigned long __shm_atime_lo;
+	unsigned long __shm_dtime_lo;
+	unsigned long __shm_ctime_lo;
 	pid_t shm_cpid;
 	pid_t shm_lpid;
 	unsigned long shm_nattch;
-	unsigned long __pad1;
-	unsigned long __pad2;
+	unsigned short __shm_atime_hi;
+	unsigned short __shm_dtime_hi;
+	unsigned short __shm_ctime_hi;
+	unsigned short __pad1;
+	time_t shm_atime;
+	time_t shm_dtime;
+	time_t shm_ctime;
 };
 
 struct shminfo {
diff --git a/arch/mips/bits/stat.h b/arch/mips/bits/stat.h
index 3291a636..48d4ac80 100644
--- a/arch/mips/bits/stat.h
+++ b/arch/mips/bits/stat.h
@@ -12,11 +12,15 @@ struct stat {
 	dev_t st_rdev;
 	long __st_padding2[2];
 	off_t st_size;
-	struct timespec st_atim;
-	struct timespec st_mtim;
-	struct timespec st_ctim;
+	struct {
+		long tv_sec;
+		long tv_nsec;
+	} __st_atim32, __st_mtim32, __st_ctim32;
 	blksize_t st_blksize;
 	long __st_padding3;
 	blkcnt_t st_blocks;
-        long __st_padding4[14];
+	struct timespec st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+	long __st_padding4[2];
 };
diff --git a/arch/mips/syscall_arch.h b/arch/mips/syscall_arch.h
index 6ea73437..f821e73f 100644
--- a/arch/mips/syscall_arch.h
+++ b/arch/mips/syscall_arch.h
@@ -142,7 +142,9 @@ static inline long __syscall7(long n, long a, long b, long c, long d, long e, lo
 }
 
 #define VDSO_USEFUL
-#define VDSO_CGT_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_VER "LINUX_2.6"
+#define VDSO_CGT_SYM "__vdso_clock_gettime64"
 #define VDSO_CGT_VER "LINUX_2.6"
 
 #define SO_SNDTIMEO_OLD 0x1005
-- 
2.21.0


[-- Attachment #16: 0015-switch-mipsn32-to-64-bit-time_t.patch --]
[-- Type: text/plain, Size: 5289 bytes --]

From 7f7c13e06019cc1aa94a4b334b5138b47f9ff42a Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Sun, 20 Oct 2019 19:15:15 -0400
Subject: [PATCH 15/17] switch mipsn32 to 64-bit time_t

---
 arch/mipsn32/arch.mak           |  1 +
 arch/mipsn32/bits/alltypes.h.in |  5 +++--
 arch/mipsn32/bits/ipcstat.h     |  2 +-
 arch/mipsn32/bits/msg.h         | 27 +++++++++++++++------------
 arch/mipsn32/bits/sem.h         | 10 ++++++----
 arch/mipsn32/bits/shm.h         | 15 ++++++++++-----
 arch/mipsn32/bits/stat.h        | 12 ++++++++----
 arch/mipsn32/syscall_arch.h     |  4 +++-
 8 files changed, 47 insertions(+), 29 deletions(-)
 create mode 100644 arch/mipsn32/arch.mak

diff --git a/arch/mipsn32/arch.mak b/arch/mipsn32/arch.mak
new file mode 100644
index 00000000..aa4d05ce
--- /dev/null
+++ b/arch/mipsn32/arch.mak
@@ -0,0 +1 @@
+COMPAT_SRC_DIRS = compat/time32
diff --git a/arch/mipsn32/bits/alltypes.h.in b/arch/mipsn32/bits/alltypes.h.in
index 9544b496..32544cfe 100644
--- a/arch/mipsn32/bits/alltypes.h.in
+++ b/arch/mipsn32/bits/alltypes.h.in
@@ -1,3 +1,4 @@
+#define _REDIR_TIME64 1
 #define _Addr int
 #define _Int64 long long
 #define _Reg int
@@ -19,5 +20,5 @@ TYPEDEF double double_t;
 
 TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
 
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
+TYPEDEF long long time_t;
+TYPEDEF long long suseconds_t;
diff --git a/arch/mipsn32/bits/ipcstat.h b/arch/mipsn32/bits/ipcstat.h
index 0018ad1e..4f4fcb0c 100644
--- a/arch/mipsn32/bits/ipcstat.h
+++ b/arch/mipsn32/bits/ipcstat.h
@@ -1 +1 @@
-#define IPC_STAT 2
+#define IPC_STAT 0x102
diff --git a/arch/mipsn32/bits/msg.h b/arch/mipsn32/bits/msg.h
index f28aece8..c734dbb5 100644
--- a/arch/mipsn32/bits/msg.h
+++ b/arch/mipsn32/bits/msg.h
@@ -1,19 +1,19 @@
 struct msqid_ds {
 	struct ipc_perm msg_perm;
 #if _MIPSEL || __MIPSEL || __MIPSEL__
-	time_t msg_stime;
-	int __unused1;
-	time_t msg_rtime;
-	int __unused2;
-	time_t msg_ctime;
-	int __unused3;
+	unsigned long __msg_stime_lo;
+	unsigned long __msg_stime_hi;
+	unsigned long __msg_rtime_lo;
+	unsigned long __msg_rtime_hi;
+	unsigned long __msg_ctime_lo;
+	unsigned long __msg_ctime_hi;
 #else
-	int __unused1;
-	time_t msg_stime;
-	int __unused2;
-	time_t msg_rtime;
-	int __unused3;
-	time_t msg_ctime;
+	unsigned long __msg_stime_hi;
+	unsigned long __msg_stime_lo;
+	unsigned long __msg_rtime_hi;
+	unsigned long __msg_rtime_lo;
+	unsigned long __msg_ctime_hi;
+	unsigned long __msg_ctime_lo;
 #endif
 	unsigned long msg_cbytes;
 	msgqnum_t msg_qnum;
@@ -21,4 +21,7 @@ struct msqid_ds {
 	pid_t msg_lspid;
 	pid_t msg_lrpid;
 	unsigned long __unused[2];
+	time_t msg_stime;
+	time_t msg_rtime;
+	time_t msg_ctime;
 };
diff --git a/arch/mipsn32/bits/sem.h b/arch/mipsn32/bits/sem.h
index 5184eb59..fe6f0948 100644
--- a/arch/mipsn32/bits/sem.h
+++ b/arch/mipsn32/bits/sem.h
@@ -1,7 +1,7 @@
 struct semid_ds {
 	struct ipc_perm sem_perm;
-	time_t sem_otime;
-	time_t sem_ctime;
+	unsigned long __sem_otime_lo;
+	unsigned long __sem_ctime_lo;
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 	unsigned short sem_nsems;
 	char __sem_nsems_pad[sizeof(long)-sizeof(short)];
@@ -9,6 +9,8 @@ struct semid_ds {
 	char __sem_nsems_pad[sizeof(long)-sizeof(short)];
 	unsigned short sem_nsems;
 #endif
-	long __unused3;
-	long __unused4;
+	unsigned long __sem_otime_hi;
+	unsigned long __sem_ctime_hi;
+	time_t sem_otime;
+	time_t sem_ctime;
 };
diff --git a/arch/mipsn32/bits/shm.h b/arch/mipsn32/bits/shm.h
index 8d193781..ab8c642d 100644
--- a/arch/mipsn32/bits/shm.h
+++ b/arch/mipsn32/bits/shm.h
@@ -3,14 +3,19 @@
 struct shmid_ds {
 	struct ipc_perm shm_perm;
 	size_t shm_segsz;
-	time_t shm_atime;
-	time_t shm_dtime;
-	time_t shm_ctime;
+	unsigned long __shm_atime_lo;
+	unsigned long __shm_dtime_lo;
+	unsigned long __shm_ctime_lo;
 	pid_t shm_cpid;
 	pid_t shm_lpid;
 	unsigned long shm_nattch;
-	unsigned long __pad1;
-	unsigned long __pad2;
+	unsigned short __shm_atime_hi;
+	unsigned short __shm_dtime_hi;
+	unsigned short __shm_ctime_hi;
+	unsigned short __pad1;
+	time_t shm_atime;
+	time_t shm_dtime;
+	time_t shm_ctime;
 };
 
 struct shminfo {
diff --git a/arch/mipsn32/bits/stat.h b/arch/mipsn32/bits/stat.h
index 27d36b51..6e2f2808 100644
--- a/arch/mipsn32/bits/stat.h
+++ b/arch/mipsn32/bits/stat.h
@@ -9,11 +9,15 @@ struct stat {
 	dev_t st_rdev;
 	long __pad2[2];
 	off_t st_size;
-	struct timespec st_atim;
-	struct timespec st_mtim;
-	struct timespec st_ctim;
+	struct {
+		long tv_sec;
+		long tv_nsec;
+	} __st_atim32, __st_mtim32, __st_ctim32;
 	blksize_t st_blksize;
 	long __pad3;
 	blkcnt_t st_blocks;
-	long __pad4[14];
+	struct timespec st_atim;
+	struct timespec st_mtim;
+	struct timespec st_ctim;
+	long __pad4[2];
 };
diff --git a/arch/mipsn32/syscall_arch.h b/arch/mipsn32/syscall_arch.h
index 5ff43bba..c1a4b7da 100644
--- a/arch/mipsn32/syscall_arch.h
+++ b/arch/mipsn32/syscall_arch.h
@@ -116,7 +116,9 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo
 }
 
 #define VDSO_USEFUL
-#define VDSO_CGT_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_VER "LINUX_2.6"
+#define VDSO_CGT_SYM "__vdso_clock_gettime64"
 #define VDSO_CGT_VER "LINUX_2.6"
 
 #define SO_SNDTIMEO_OLD 0x1005
-- 
2.21.0


[-- Attachment #17: 0016-switch-or1k-to-64-bit-time_t.patch --]
[-- Type: text/plain, Size: 4092 bytes --]

From 97dd89e7a4058dea3a2f3bc9eaa5e64753a441cb Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Sun, 20 Oct 2019 19:18:37 -0400
Subject: [PATCH 16/17] switch or1k to 64-bit time_t

---
 arch/or1k/arch.mak           |  1 +
 arch/or1k/bits/alltypes.h.in |  5 +++--
 arch/or1k/bits/ipcstat.h     |  2 +-
 arch/or1k/bits/msg.h         | 15 +++++++++------
 arch/or1k/bits/sem.h         | 10 ++++++----
 arch/or1k/bits/shm.h         | 16 ++++++++++------
 arch/or1k/bits/stat.h        | 10 +++++++---
 7 files changed, 37 insertions(+), 22 deletions(-)
 create mode 100644 arch/or1k/arch.mak

diff --git a/arch/or1k/arch.mak b/arch/or1k/arch.mak
new file mode 100644
index 00000000..aa4d05ce
--- /dev/null
+++ b/arch/or1k/arch.mak
@@ -0,0 +1 @@
+COMPAT_SRC_DIRS = compat/time32
diff --git a/arch/or1k/bits/alltypes.h.in b/arch/or1k/bits/alltypes.h.in
index 5faa1578..aeb73ab5 100644
--- a/arch/or1k/bits/alltypes.h.in
+++ b/arch/or1k/bits/alltypes.h.in
@@ -1,3 +1,4 @@
+#define _REDIR_TIME64 1
 #define _Addr int
 #define _Int64 long long
 #define _Reg int
@@ -14,5 +15,5 @@ TYPEDEF double double_t;
 
 TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
 
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
+TYPEDEF long long time_t;
+TYPEDEF long long suseconds_t;
diff --git a/arch/or1k/bits/ipcstat.h b/arch/or1k/bits/ipcstat.h
index 0018ad1e..4f4fcb0c 100644
--- a/arch/or1k/bits/ipcstat.h
+++ b/arch/or1k/bits/ipcstat.h
@@ -1 +1 @@
-#define IPC_STAT 2
+#define IPC_STAT 0x102
diff --git a/arch/or1k/bits/msg.h b/arch/or1k/bits/msg.h
index bc8436c4..7bbbb2bf 100644
--- a/arch/or1k/bits/msg.h
+++ b/arch/or1k/bits/msg.h
@@ -1,15 +1,18 @@
 struct msqid_ds {
 	struct ipc_perm msg_perm;
-	time_t msg_stime;
-	int __unused1;
-	time_t msg_rtime;
-	int __unused2;
-	time_t msg_ctime;
-	int __unused3;
+	unsigned long __msg_stime_lo;
+	unsigned long __msg_stime_hi;
+	unsigned long __msg_rtime_lo;
+	unsigned long __msg_rtime_hi;
+	unsigned long __msg_ctime_lo;
+	unsigned long __msg_ctime_hi;
 	unsigned long msg_cbytes;
 	msgqnum_t msg_qnum;
 	msglen_t msg_qbytes;
 	pid_t msg_lspid;
 	pid_t msg_lrpid;
 	unsigned long __unused[2];
+	time_t msg_stime;
+	time_t msg_rtime;
+	time_t msg_ctime;
 };
diff --git a/arch/or1k/bits/sem.h b/arch/or1k/bits/sem.h
index 08faafea..d88338e6 100644
--- a/arch/or1k/bits/sem.h
+++ b/arch/or1k/bits/sem.h
@@ -1,11 +1,13 @@
 struct semid_ds {
 	struct ipc_perm sem_perm;
-	time_t sem_otime;
-	long __unused1;
-	time_t sem_ctime;
-	long __unused2;
+	unsigned long __sem_otime_lo;
+	unsigned long __sem_otime_hi;
+	unsigned long __sem_ctime_lo;
+	unsigned long __sem_ctime_hi;
 	char __sem_nsems_pad[sizeof(long)-sizeof(short)];
 	unsigned short sem_nsems;
 	long __unused3;
 	long __unused4;
+	time_t sem_otime;
+	time_t sem_ctime;
 };
diff --git a/arch/or1k/bits/shm.h b/arch/or1k/bits/shm.h
index 81b2a29a..725fb469 100644
--- a/arch/or1k/bits/shm.h
+++ b/arch/or1k/bits/shm.h
@@ -3,17 +3,21 @@
 struct shmid_ds {
 	struct ipc_perm shm_perm;
 	size_t shm_segsz;
-	time_t shm_atime;
-	int __unused1;
-	time_t shm_dtime;
-	int __unused2;
-	time_t shm_ctime;
-	int __unused3;
+	unsigned long __shm_atime_lo;
+	unsigned long __shm_atime_hi;
+	unsigned long __shm_dtime_lo;
+	unsigned long __shm_dtime_hi;
+	unsigned long __shm_ctime_lo;
+	unsigned long __shm_ctime_hi;
 	pid_t shm_cpid;
 	pid_t shm_lpid;
 	unsigned long shm_nattch;
 	unsigned long __pad1;
 	unsigned long __pad2;
+	unsigned long __pad3;
+	time_t shm_atime;
+	time_t shm_dtime;
+	time_t shm_ctime;
 };
 
 struct shminfo {
diff --git a/arch/or1k/bits/stat.h b/arch/or1k/bits/stat.h
index ce6a6bd0..cde3fd02 100644
--- a/arch/or1k/bits/stat.h
+++ b/arch/or1k/bits/stat.h
@@ -14,8 +14,12 @@ struct stat {
 	blksize_t st_blksize;
 	int __st_blksize_padding;
 	blkcnt_t st_blocks;
-	struct timespec st_atim;
-	struct timespec st_mtim;
-	struct timespec st_ctim;
+	struct {
+		long tv_sec;
+		long tv_nsec;
+	} __st_atim32, __st_mtim32, __st_ctim32;
 	unsigned __unused[2];
+ 	struct timespec st_atim;
+ 	struct timespec st_mtim;
+ 	struct timespec st_ctim;
 };
-- 
2.21.0


[-- Attachment #18: 0017-switch-powerpc-to-64-bit-time_t.patch --]
[-- Type: text/plain, Size: 4084 bytes --]

From 31aae539d35550a3db0641f25d16968ed6a0702c Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Sun, 20 Oct 2019 19:24:53 -0400
Subject: [PATCH 17/17] switch powerpc to 64-bit time_t

---
 arch/powerpc/arch.mak           |  1 +
 arch/powerpc/bits/alltypes.h.in |  5 +++--
 arch/powerpc/bits/ipcstat.h     |  2 +-
 arch/powerpc/bits/msg.h         | 15 +++++++++------
 arch/powerpc/bits/sem.h         | 10 ++++++----
 arch/powerpc/bits/shm.h         | 16 +++++++++-------
 arch/powerpc/bits/stat.h        |  6 +++++-
 7 files changed, 34 insertions(+), 21 deletions(-)
 create mode 100644 arch/powerpc/arch.mak

diff --git a/arch/powerpc/arch.mak b/arch/powerpc/arch.mak
new file mode 100644
index 00000000..aa4d05ce
--- /dev/null
+++ b/arch/powerpc/arch.mak
@@ -0,0 +1 @@
+COMPAT_SRC_DIRS = compat/time32
diff --git a/arch/powerpc/bits/alltypes.h.in b/arch/powerpc/bits/alltypes.h.in
index fd0c816c..8e003545 100644
--- a/arch/powerpc/bits/alltypes.h.in
+++ b/arch/powerpc/bits/alltypes.h.in
@@ -1,3 +1,4 @@
+#define _REDIR_TIME64 1
 #define _Addr int
 #define _Int64 long long
 #define _Reg int
@@ -18,5 +19,5 @@ TYPEDEF double double_t;
 
 TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
 
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
+TYPEDEF long long time_t;
+TYPEDEF long long suseconds_t;
diff --git a/arch/powerpc/bits/ipcstat.h b/arch/powerpc/bits/ipcstat.h
index 0018ad1e..4f4fcb0c 100644
--- a/arch/powerpc/bits/ipcstat.h
+++ b/arch/powerpc/bits/ipcstat.h
@@ -1 +1 @@
-#define IPC_STAT 2
+#define IPC_STAT 0x102
diff --git a/arch/powerpc/bits/msg.h b/arch/powerpc/bits/msg.h
index 171c11a3..9fb15dcc 100644
--- a/arch/powerpc/bits/msg.h
+++ b/arch/powerpc/bits/msg.h
@@ -1,15 +1,18 @@
 struct msqid_ds {
 	struct ipc_perm msg_perm;
-	int __unused1;
-	time_t msg_stime;
-	int __unused2;
-	time_t msg_rtime;
-	int __unused3;
-	time_t msg_ctime;
+	unsigned long __msg_stime_hi;
+	unsigned long __msg_stime_lo;
+	unsigned long __msg_rtime_hi;
+	unsigned long __msg_rtime_lo;
+	unsigned long __msg_ctime_hi;
+	unsigned long __msg_ctime_lo;
 	unsigned long msg_cbytes;
 	msgqnum_t msg_qnum;
 	msglen_t msg_qbytes;
 	pid_t msg_lspid;
 	pid_t msg_lrpid;
 	unsigned long __unused[2];
+	time_t msg_stime;
+	time_t msg_rtime;
+	time_t msg_ctime;
 };
diff --git a/arch/powerpc/bits/sem.h b/arch/powerpc/bits/sem.h
index bc2d6d1f..28be4845 100644
--- a/arch/powerpc/bits/sem.h
+++ b/arch/powerpc/bits/sem.h
@@ -1,10 +1,12 @@
 struct semid_ds {
 	struct ipc_perm sem_perm;
-	int __unused1;
-	time_t sem_otime;
-	int  __unused2;
-	time_t sem_ctime;
+	unsigned long __sem_otime_hi;
+	unsigned long __sem_otime_lo;
+	unsigned long __sem_ctime_hi;
+	unsigned long __sem_ctime_lo;
 	unsigned short __sem_nsems_pad, sem_nsems;
 	long __unused3;
 	long __unused4;
+	time_t sem_otime;
+	time_t sem_ctime;
 };
diff --git a/arch/powerpc/bits/shm.h b/arch/powerpc/bits/shm.h
index b19801d5..fb1d4020 100644
--- a/arch/powerpc/bits/shm.h
+++ b/arch/powerpc/bits/shm.h
@@ -2,19 +2,21 @@
 
 struct shmid_ds {
 	struct ipc_perm shm_perm;
-	int __unused1;
-	time_t shm_atime;
-	int __unused2;
-	time_t shm_dtime;
-	int __unused3;
-	time_t shm_ctime;
-	int __unused4;
+	unsigned long __shm_atime_hi;
+	unsigned long __shm_atime_lo;
+	unsigned long __shm_dtime_hi;
+	unsigned long __shm_dtime_lo;
+	unsigned long __shm_ctime_hi;
+	unsigned long __shm_ctime_lo;
 	size_t shm_segsz;
 	pid_t shm_cpid;
 	pid_t shm_lpid;
 	unsigned long shm_nattch;
 	unsigned long __pad1;
 	unsigned long __pad2;
+	time_t shm_atime;
+	time_t shm_dtime;
+	time_t shm_ctime;
 };
 
 struct shminfo {
diff --git a/arch/powerpc/bits/stat.h b/arch/powerpc/bits/stat.h
index dcb896fd..585d98e9 100644
--- a/arch/powerpc/bits/stat.h
+++ b/arch/powerpc/bits/stat.h
@@ -13,8 +13,12 @@ struct stat {
 	off_t st_size;
 	blksize_t st_blksize;
 	blkcnt_t st_blocks;
+	struct {
+		long tv_sec;
+		long tv_nsec;
+	} __st_atim32, __st_mtim32, __st_ctim32;
+	unsigned __unused[2];
 	struct timespec st_atim;
 	struct timespec st_mtim;
 	struct timespec st_ctim;
-	unsigned __unused[2];
 };
-- 
2.21.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] remaining steps for time64 switchover
  2019-10-21  2:46 [PATCH] remaining steps for time64 switchover Rich Felker
@ 2019-10-21 12:43 ` Rich Felker
  2019-10-27  4:15   ` Rich Felker
  2019-10-27  4:26 ` Rich Felker
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 15+ messages in thread
From: Rich Felker @ 2019-10-21 12:43 UTC (permalink / raw)
  To: musl

On Sun, Oct 20, 2019 at 10:46:43PM -0400, Rich Felker wrote:
> >From 31aae539d35550a3db0641f25d16968ed6a0702c Mon Sep 17 00:00:00 2001
> From: Rich Felker <dalias@aerifal.cx>
> Date: Sun, 20 Oct 2019 19:24:53 -0400
> Subject: [PATCH 17/17] switch powerpc to 64-bit time_t
> 
> ---
>  arch/powerpc/arch.mak           |  1 +
>  arch/powerpc/bits/alltypes.h.in |  5 +++--
>  arch/powerpc/bits/ipcstat.h     |  2 +-
>  arch/powerpc/bits/msg.h         | 15 +++++++++------
>  arch/powerpc/bits/sem.h         | 10 ++++++----
>  arch/powerpc/bits/shm.h         | 16 +++++++++-------
>  arch/powerpc/bits/stat.h        |  6 +++++-
>  7 files changed, 34 insertions(+), 21 deletions(-)
>  create mode 100644 arch/powerpc/arch.mak
> 
> diff --git a/arch/powerpc/arch.mak b/arch/powerpc/arch.mak
> new file mode 100644
> index 00000000..aa4d05ce
> --- /dev/null
> +++ b/arch/powerpc/arch.mak
> @@ -0,0 +1 @@
> +COMPAT_SRC_DIRS = compat/time32
> diff --git a/arch/powerpc/bits/alltypes.h.in b/arch/powerpc/bits/alltypes.h.in
> index fd0c816c..8e003545 100644
> --- a/arch/powerpc/bits/alltypes.h.in
> +++ b/arch/powerpc/bits/alltypes.h.in
> @@ -1,3 +1,4 @@
> +#define _REDIR_TIME64 1
>  #define _Addr int
>  #define _Int64 long long
>  #define _Reg int
> @@ -18,5 +19,5 @@ TYPEDEF double double_t;
>  
>  TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
>  
> -TYPEDEF long time_t;
> -TYPEDEF long suseconds_t;
> +TYPEDEF long long time_t;
> +TYPEDEF long long suseconds_t;
> diff --git a/arch/powerpc/bits/ipcstat.h b/arch/powerpc/bits/ipcstat.h
> index 0018ad1e..4f4fcb0c 100644
> --- a/arch/powerpc/bits/ipcstat.h
> +++ b/arch/powerpc/bits/ipcstat.h
> @@ -1 +1 @@
> -#define IPC_STAT 2
> +#define IPC_STAT 0x102

This could actually be dropped for powerpc...

> diff --git a/arch/powerpc/bits/msg.h b/arch/powerpc/bits/msg.h
> index 171c11a3..9fb15dcc 100644
> --- a/arch/powerpc/bits/msg.h
> +++ b/arch/powerpc/bits/msg.h
> @@ -1,15 +1,18 @@
>  struct msqid_ds {
>  	struct ipc_perm msg_perm;
> -	int __unused1;
> -	time_t msg_stime;
> -	int __unused2;
> -	time_t msg_rtime;
> -	int __unused3;
> -	time_t msg_ctime;
> +	unsigned long __msg_stime_hi;
> +	unsigned long __msg_stime_lo;
> +	unsigned long __msg_rtime_hi;
> +	unsigned long __msg_rtime_lo;
> +	unsigned long __msg_ctime_hi;
> +	unsigned long __msg_ctime_lo;

by making this just:

> +	time_t msg_stime;
> +	time_t msg_rtime;
> +	time_t msg_ctime;

since the alignments and endianness are correct (I'm pretty sure
they're correct for all 3 structs). Any ppc folks want to confirm
that?

It's not a big deal either way but would be slightly "nicer".

Rich


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] remaining steps for time64 switchover
  2019-10-21 12:43 ` Rich Felker
@ 2019-10-27  4:15   ` Rich Felker
  0 siblings, 0 replies; 15+ messages in thread
From: Rich Felker @ 2019-10-27  4:15 UTC (permalink / raw)
  To: musl

On Mon, Oct 21, 2019 at 08:43:35AM -0400, Rich Felker wrote:
> On Sun, Oct 20, 2019 at 10:46:43PM -0400, Rich Felker wrote:
> > >From 31aae539d35550a3db0641f25d16968ed6a0702c Mon Sep 17 00:00:00 2001
> > From: Rich Felker <dalias@aerifal.cx>
> > Date: Sun, 20 Oct 2019 19:24:53 -0400
> > Subject: [PATCH 17/17] switch powerpc to 64-bit time_t
> > 
> > ---
> >  arch/powerpc/arch.mak           |  1 +
> >  arch/powerpc/bits/alltypes.h.in |  5 +++--
> >  arch/powerpc/bits/ipcstat.h     |  2 +-
> >  arch/powerpc/bits/msg.h         | 15 +++++++++------
> >  arch/powerpc/bits/sem.h         | 10 ++++++----
> >  arch/powerpc/bits/shm.h         | 16 +++++++++-------
> >  arch/powerpc/bits/stat.h        |  6 +++++-
> >  7 files changed, 34 insertions(+), 21 deletions(-)
> >  create mode 100644 arch/powerpc/arch.mak
> > 
> > diff --git a/arch/powerpc/arch.mak b/arch/powerpc/arch.mak
> > new file mode 100644
> > index 00000000..aa4d05ce
> > --- /dev/null
> > +++ b/arch/powerpc/arch.mak
> > @@ -0,0 +1 @@
> > +COMPAT_SRC_DIRS = compat/time32
> > diff --git a/arch/powerpc/bits/alltypes.h.in b/arch/powerpc/bits/alltypes.h.in
> > index fd0c816c..8e003545 100644
> > --- a/arch/powerpc/bits/alltypes.h.in
> > +++ b/arch/powerpc/bits/alltypes.h.in
> > @@ -1,3 +1,4 @@
> > +#define _REDIR_TIME64 1
> >  #define _Addr int
> >  #define _Int64 long long
> >  #define _Reg int
> > @@ -18,5 +19,5 @@ TYPEDEF double double_t;
> >  
> >  TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
> >  
> > -TYPEDEF long time_t;
> > -TYPEDEF long suseconds_t;
> > +TYPEDEF long long time_t;
> > +TYPEDEF long long suseconds_t;
> > diff --git a/arch/powerpc/bits/ipcstat.h b/arch/powerpc/bits/ipcstat.h
> > index 0018ad1e..4f4fcb0c 100644
> > --- a/arch/powerpc/bits/ipcstat.h
> > +++ b/arch/powerpc/bits/ipcstat.h
> > @@ -1 +1 @@
> > -#define IPC_STAT 2
> > +#define IPC_STAT 0x102
> 
> This could actually be dropped for powerpc...
> 
> > diff --git a/arch/powerpc/bits/msg.h b/arch/powerpc/bits/msg.h
> > index 171c11a3..9fb15dcc 100644
> > --- a/arch/powerpc/bits/msg.h
> > +++ b/arch/powerpc/bits/msg.h
> > @@ -1,15 +1,18 @@
> >  struct msqid_ds {
> >  	struct ipc_perm msg_perm;
> > -	int __unused1;
> > -	time_t msg_stime;
> > -	int __unused2;
> > -	time_t msg_rtime;
> > -	int __unused3;
> > -	time_t msg_ctime;
> > +	unsigned long __msg_stime_hi;
> > +	unsigned long __msg_stime_lo;
> > +	unsigned long __msg_rtime_hi;
> > +	unsigned long __msg_rtime_lo;
> > +	unsigned long __msg_ctime_hi;
> > +	unsigned long __msg_ctime_lo;
> 
> by making this just:
> 
> > +	time_t msg_stime;
> > +	time_t msg_rtime;
> > +	time_t msg_ctime;
> 
> since the alignments and endianness are correct (I'm pretty sure
> they're correct for all 3 structs). Any ppc folks want to confirm
> that?
> 
> It's not a big deal either way but would be slightly "nicer".

If there's any possibility of having a little-endian 32-bit powerpc
target, then I think it's probably best not to do this -- it would
have to be backed out conditional on endianness.

Rich


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] remaining steps for time64 switchover
  2019-10-21  2:46 [PATCH] remaining steps for time64 switchover Rich Felker
  2019-10-21 12:43 ` Rich Felker
@ 2019-10-27  4:26 ` Rich Felker
  2019-10-27  8:32   ` Laurent Bercot
  2019-10-28 22:22   ` Rich Felker
  2019-10-29 19:52 ` Rich Felker
  2019-10-29 23:08 ` Rich Felker
  3 siblings, 2 replies; 15+ messages in thread
From: Rich Felker @ 2019-10-27  4:26 UTC (permalink / raw)
  To: musl

On Sun, Oct 20, 2019 at 10:46:43PM -0400, Rich Felker wrote:
> demonstrably working). The one omission I'm aware of is what to do
> with struct utmpx, which is not actually used at present in any libc
> interfaces and thus not part of the ABI surface of libc. That will be
> addressed in a separate thread.

Or here. So, the story on utmpx: we can either

1. match the current size on 32-bit archs, but move the timeval to
   unused space at the end where a time64 version fits, or

2. match the current size and layout of the 64-bit struct, making it
   possible to share records between 32- and 64-bit processes on the
   same machine.

Keep in mind that this struct is not used anywhere in libc presently,
but normally it's used as a format for on-disk records.

I'm kinda leaning towards option 2, but being that I don't use (and
hate) utmp, I'd rather hear opinions from people who do use it. Either
way time fields in existing data will break, so it's a question of
whether that one-time breakage is already sufficient to go a bit
further and get 32/64 compat afterwards.

Rich


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] remaining steps for time64 switchover
  2019-10-27  4:26 ` Rich Felker
@ 2019-10-27  8:32   ` Laurent Bercot
  2019-10-27 14:53     ` Rich Felker
  2019-10-27 20:12     ` Matias Fonzo
  2019-10-28 22:22   ` Rich Felker
  1 sibling, 2 replies; 15+ messages in thread
From: Laurent Bercot @ 2019-10-27  8:32 UTC (permalink / raw)
  To: musl

>Or here. So, the story on utmpx: we can either
>
>1. match the current size on 32-bit archs, but move the timeval to
>    unused space at the end where a time64 version fits, or
>
>2. match the current size and layout of the 64-bit struct, making it
>    possible to share records between 32- and 64-bit processes on the
>    same machine.
>
>Keep in mind that this struct is not used anywhere in libc presently,
>but normally it's used as a format for on-disk records.
>
>I'm kinda leaning towards option 2, but being that I don't use (and
>hate) utmp, I'd rather hear opinions from people who do use it. Either
>way time fields in existing data will break, so it's a question of
>whether that one-time breakage is already sufficient to go a bit
>further and get 32/64 compat afterwards.

I don't use the libc's utmpx, but I maintain utmps, which is a secure 
implementation of utmp, including the definition of struct utmpx.
I haven't been following the time64 thing closely. The current struct
utmpx definition includes a struct timeval. Will it need to change,
or will musl's struct timeval change be enough and naturally propagate
so the struct utmpx will become time64-compatible?

On-disk data is not a problem. On the distro that I know uses utmps
(Adélie), the utmp/wtmp records, by design, do not survive a reboot,
so a reboot will fix everything - and will be mandatory anyway on
arches where the musl ABI changes.

I'm not aware of any distribution that uses musl, doesn't use utmps,
and still keeps on-disk utmpx records.

--
Laurent



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] remaining steps for time64 switchover
  2019-10-27  8:32   ` Laurent Bercot
@ 2019-10-27 14:53     ` Rich Felker
  2019-10-27 20:12     ` Matias Fonzo
  1 sibling, 0 replies; 15+ messages in thread
From: Rich Felker @ 2019-10-27 14:53 UTC (permalink / raw)
  To: musl

On Sun, Oct 27, 2019 at 08:32:57AM +0000, Laurent Bercot wrote:
> >Or here. So, the story on utmpx: we can either
> >
> >1. match the current size on 32-bit archs, but move the timeval to
> >   unused space at the end where a time64 version fits, or
> >
> >2. match the current size and layout of the 64-bit struct, making it
> >   possible to share records between 32- and 64-bit processes on the
> >   same machine.
> >
> >Keep in mind that this struct is not used anywhere in libc presently,
> >but normally it's used as a format for on-disk records.
> >
> >I'm kinda leaning towards option 2, but being that I don't use (and
> >hate) utmp, I'd rather hear opinions from people who do use it. Either
> >way time fields in existing data will break, so it's a question of
> >whether that one-time breakage is already sufficient to go a bit
> >further and get 32/64 compat afterwards.
> 
> I don't use the libc's utmpx, but I maintain utmps, which is a
> secure implementation of utmp, including the definition of struct
> utmpx.
> I haven't been following the time64 thing closely. The current struct
> utmpx definition includes a struct timeval. Will it need to change,
> or will musl's struct timeval change be enough and naturally propagate
> so the struct utmpx will become time64-compatible?

It will naturally propagate even if nothing is done, but then you have
the worst of both worlds of 1 and 2. You neither maintain the size and
layout of other members (which would be useful if you have old data or
a mix of old and new binaries using it) nor gain any useful
compatibility (between 32- and 64-bit on same system). You just get a
new size and layout that doesn't match either. So it's better to make
some change, I think.

Note that the difference between "do nothing" and option 2 is
basically nothing except putting padding around ut_session so that
ut_tv will start on a 0 mod 8 boundary. This will happen naturally on
most archs but not i386 (and m68k but there's no corresponding 64-bit
arch there anyway). The proposal I have in mind is basically:

-	long ut_session;
+#if __BYTE_ORDER == 1234
+	int ut_session, __ut_pad2;
+#else
+	int __ut_pad2, ut_session;
+#endif

doing this for 64-bit too since ut_session is semantically 32-bit
(pid_t) and glibc has it as 32-bit on x86_64. (I'd also add explicit
padding for ut_type just because m68k is wacky and doesn't align ints
even, to fix that while we have the chance.)

> On-disk data is not a problem. On the distro that I know uses utmps
> (Adélie), the utmp/wtmp records, by design, do not survive a reboot,
> so a reboot will fix everything - and will be mandatory anyway on
> arches where the musl ABI changes.

Reboot is not mandatory; as usual, just atomic replacement of libc.so
is.

> I'm not aware of any distribution that uses musl, doesn't use utmps,
> and still keeps on-disk utmpx records.

Thanks.

Rich


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] remaining steps for time64 switchover
  2019-10-27  8:32   ` Laurent Bercot
  2019-10-27 14:53     ` Rich Felker
@ 2019-10-27 20:12     ` Matias Fonzo
  2019-10-27 21:14       ` Rich Felker
  1 sibling, 1 reply; 15+ messages in thread
From: Matias Fonzo @ 2019-10-27 20:12 UTC (permalink / raw)
  To: musl; +Cc: Laurent Bercot

Hello Laurent,

Can utmps work without s6?.  I mean, independently of the init system or 
distribution...

El 2019-10-27 05:32, Laurent Bercot escribió:
>> Or here. So, the story on utmpx: we can either
>> 
>> 1. match the current size on 32-bit archs, but move the timeval to
>>    unused space at the end where a time64 version fits, or
>> 
>> 2. match the current size and layout of the 64-bit struct, making it
>>    possible to share records between 32- and 64-bit processes on the
>>    same machine.
>> 
>> Keep in mind that this struct is not used anywhere in libc presently,
>> but normally it's used as a format for on-disk records.
>> 
>> I'm kinda leaning towards option 2, but being that I don't use (and
>> hate) utmp, I'd rather hear opinions from people who do use it. Either
>> way time fields in existing data will break, so it's a question of
>> whether that one-time breakage is already sufficient to go a bit
>> further and get 32/64 compat afterwards.
> 
> I don't use the libc's utmpx, but I maintain utmps, which is a secure
> implementation of utmp, including the definition of struct utmpx.
> I haven't been following the time64 thing closely. The current struct
> utmpx definition includes a struct timeval. Will it need to change,
> or will musl's struct timeval change be enough and naturally propagate
> so the struct utmpx will become time64-compatible?
> 
> On-disk data is not a problem. On the distro that I know uses utmps
> (Adélie), the utmp/wtmp records, by design, do not survive a reboot,
> so a reboot will fix everything - and will be mandatory anyway on
> arches where the musl ABI changes.
> 
> I'm not aware of any distribution that uses musl, doesn't use utmps,
> and still keeps on-disk utmpx records.
> 
> --
> Laurent


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] remaining steps for time64 switchover
  2019-10-27 20:12     ` Matias Fonzo
@ 2019-10-27 21:14       ` Rich Felker
  2019-10-27 21:53         ` Matias Fonzo
  0 siblings, 1 reply; 15+ messages in thread
From: Rich Felker @ 2019-10-27 21:14 UTC (permalink / raw)
  To: musl

On Sun, Oct 27, 2019 at 05:12:59PM -0300, Matias Fonzo wrote:
> Hello Laurent,
> 
> Can utmps work without s6?.  I mean, independently of the init
> system or distribution...

Laurent could answer in better detail, but as a quick answer, there's
no requirement from having s6 installed that you use it as your init
system.

Rich


> El 2019-10-27 05:32, Laurent Bercot escribió:
> >>Or here. So, the story on utmpx: we can either
> >>
> >>1. match the current size on 32-bit archs, but move the timeval to
> >>   unused space at the end where a time64 version fits, or
> >>
> >>2. match the current size and layout of the 64-bit struct, making it
> >>   possible to share records between 32- and 64-bit processes on the
> >>   same machine.
> >>
> >>Keep in mind that this struct is not used anywhere in libc presently,
> >>but normally it's used as a format for on-disk records.
> >>
> >>I'm kinda leaning towards option 2, but being that I don't use (and
> >>hate) utmp, I'd rather hear opinions from people who do use it. Either
> >>way time fields in existing data will break, so it's a question of
> >>whether that one-time breakage is already sufficient to go a bit
> >>further and get 32/64 compat afterwards.
> >
> >I don't use the libc's utmpx, but I maintain utmps, which is a secure
> >implementation of utmp, including the definition of struct utmpx.
> >I haven't been following the time64 thing closely. The current struct
> >utmpx definition includes a struct timeval. Will it need to change,
> >or will musl's struct timeval change be enough and naturally propagate
> >so the struct utmpx will become time64-compatible?
> >
> >On-disk data is not a problem. On the distro that I know uses utmps
> >(Adélie), the utmp/wtmp records, by design, do not survive a reboot,
> >so a reboot will fix everything - and will be mandatory anyway on
> >arches where the musl ABI changes.
> >
> >I'm not aware of any distribution that uses musl, doesn't use utmps,
> >and still keeps on-disk utmpx records.
> >
> >--
> >Laurent


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] remaining steps for time64 switchover
  2019-10-27 21:14       ` Rich Felker
@ 2019-10-27 21:53         ` Matias Fonzo
  2019-10-27 23:27           ` Laurent Bercot
  0 siblings, 1 reply; 15+ messages in thread
From: Matias Fonzo @ 2019-10-27 21:53 UTC (permalink / raw)
  To: musl

Hello Rich,

El 2019-10-27 18:14, Rich Felker escribió:
> On Sun, Oct 27, 2019 at 05:12:59PM -0300, Matias Fonzo wrote:
>> Hello Laurent,
>> 
>> Can utmps work without s6?.  I mean, independently of the init
>> system or distribution...
> 
> Laurent could answer in better detail, but as a quick answer, there's
> no requirement from having s6 installed that you use it as your init
> system.
> 

I thought so, but there could be a configuration-side requirement or 
daemon (setup) to work properly, I don't know.  We are using perp for 
Dragora.

> 
> 
>> El 2019-10-27 05:32, Laurent Bercot escribió:
>> >>Or here. So, the story on utmpx: we can either
>> >>
>> >>1. match the current size on 32-bit archs, but move the timeval to
>> >>   unused space at the end where a time64 version fits, or
>> >>
>> >>2. match the current size and layout of the 64-bit struct, making it
>> >>   possible to share records between 32- and 64-bit processes on the
>> >>   same machine.
>> >>
>> >>Keep in mind that this struct is not used anywhere in libc presently,
>> >>but normally it's used as a format for on-disk records.
>> >>
>> >>I'm kinda leaning towards option 2, but being that I don't use (and
>> >>hate) utmp, I'd rather hear opinions from people who do use it. Either
>> >>way time fields in existing data will break, so it's a question of
>> >>whether that one-time breakage is already sufficient to go a bit
>> >>further and get 32/64 compat afterwards.
>> >
>> >I don't use the libc's utmpx, but I maintain utmps, which is a secure
>> >implementation of utmp, including the definition of struct utmpx.
>> >I haven't been following the time64 thing closely. The current struct
>> >utmpx definition includes a struct timeval. Will it need to change,
>> >or will musl's struct timeval change be enough and naturally propagate
>> >so the struct utmpx will become time64-compatible?
>> >
>> >On-disk data is not a problem. On the distro that I know uses utmps
>> >(Adélie), the utmp/wtmp records, by design, do not survive a reboot,
>> >so a reboot will fix everything - and will be mandatory anyway on
>> >arches where the musl ABI changes.
>> >
>> >I'm not aware of any distribution that uses musl, doesn't use utmps,
>> >and still keeps on-disk utmpx records.
>> >
>> >--
>> >Laurent


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] remaining steps for time64 switchover
  2019-10-27 21:53         ` Matias Fonzo
@ 2019-10-27 23:27           ` Laurent Bercot
  2019-10-28 21:31             ` Matias Fonzo
  0 siblings, 1 reply; 15+ messages in thread
From: Laurent Bercot @ 2019-10-27 23:27 UTC (permalink / raw)
  To: musl


  Hi Matias,

  There is a run-time requirement for s6, but it's not an absolute one:
the utmps-utmpd and utmps-wtmpd programs simply rely on an interface
provided by s6-ipcserver(d). If you can provide the same interface,
you can do without s6.

  utmps-utmpd and utmps-wtmpd expect:
  - to be launched via an inetd-like listening on the configured Unix
domain socket, with stdin reading from the client and stdout writing
to the client.
  - some environment variables:
    * PROTO must be set to IPC.
    * IPCREMOTEEUID must be set to the effective uid of the client.
    * IPCREMOTEEGID must be set to the effective gid of the client.
    Those last two are obtained on Linux via a struct ucred and the
SO_PEERCRED option to getsockopt(). You can't fake that, it's the
very reason why utmps is secure.

  Of course, you could also package s6 in Dragora. If you already have
a perp supervision tree, you don't even have to run a s6 one. On the
other hand, that's a risky proposition, because you might end up liking
it and wanting to use it more. %-)

--
  Laurent



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] remaining steps for time64 switchover
  2019-10-27 23:27           ` Laurent Bercot
@ 2019-10-28 21:31             ` Matias Fonzo
  0 siblings, 0 replies; 15+ messages in thread
From: Matias Fonzo @ 2019-10-28 21:31 UTC (permalink / raw)
  To: musl

Hi Laurent,

Thanks for the explanation and to give more details about it.  :-)

El 2019-10-27 20:27, Laurent Bercot escribió:
> 
>  There is a run-time requirement for s6, but it's not an absolute one:
> the utmps-utmpd and utmps-wtmpd programs simply rely on an interface
> provided by s6-ipcserver(d). If you can provide the same interface,
> you can do without s6.
> 
>  utmps-utmpd and utmps-wtmpd expect:
>  - to be launched via an inetd-like listening on the configured Unix
> domain socket, with stdin reading from the client and stdout writing
> to the client.
>  - some environment variables:
>    * PROTO must be set to IPC.
>    * IPCREMOTEEUID must be set to the effective uid of the client.
>    * IPCREMOTEEGID must be set to the effective gid of the client.
>    Those last two are obtained on Linux via a struct ucred and the
> SO_PEERCRED option to getsockopt(). You can't fake that, it's the
> very reason why utmps is secure.
> 
>  Of course, you could also package s6 in Dragora. If you already have
> a perp supervision tree, you don't even have to run a s6 one. On the
> other hand, that's a risky proposition, because you might end up liking
> it and wanting to use it more. %-)
> 
> --
>  Laurent


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] remaining steps for time64 switchover
  2019-10-27  4:26 ` Rich Felker
  2019-10-27  8:32   ` Laurent Bercot
@ 2019-10-28 22:22   ` Rich Felker
  1 sibling, 0 replies; 15+ messages in thread
From: Rich Felker @ 2019-10-28 22:22 UTC (permalink / raw)
  To: musl

On Sun, Oct 27, 2019 at 12:26:45AM -0400, Rich Felker wrote:
> On Sun, Oct 20, 2019 at 10:46:43PM -0400, Rich Felker wrote:
> > demonstrably working). The one omission I'm aware of is what to do
> > with struct utmpx, which is not actually used at present in any libc
> > interfaces and thus not part of the ABI surface of libc. That will be
> > addressed in a separate thread.
> 
> Or here. So, the story on utmpx: we can either
> 
> 1. match the current size on 32-bit archs, but move the timeval to
>    unused space at the end where a time64 version fits, or
> 
> 2. match the current size and layout of the 64-bit struct, making it
>    possible to share records between 32- and 64-bit processes on the
>    same machine.
> 
> Keep in mind that this struct is not used anywhere in libc presently,
> but normally it's used as a format for on-disk records.
> 
> I'm kinda leaning towards option 2, but being that I don't use (and
> hate) utmp, I'd rather hear opinions from people who do use it. Either
> way time fields in existing data will break, so it's a question of
> whether that one-time breakage is already sufficient to go a bit
> further and get 32/64 compat afterwards.

Thanks to git://repo.or.cz/musl-tools.git abi checker, I found a few
other minor details that have been overlooked. In addition to utmp[x],
there's also struct lastlog which depends on time_t. For it there's
really no choice to be made; change necessarily breaks size/layout of
the type, and the change that falls out naturally from time_t changing
is the "right" one (matches 64-bit struct too).

There's also ntptimeval, which I'd mentioned at one point before but
forgotten about. It's not used anywhere in libc and dubious that we
even have the type defined at all. So changes in it are no big deal.

Finally, prstatus_t (struct elf_prstatus) has timeval members, and as
I understand it this structure is ABI for core files or something. I
can't find any code that's actually using it though. This structure
can't maintain both ABI and API, so presumably API must break, i.e.
the types of the members must change. Or we just remove it entirely.
I'd be rather happy if we could do that, actually. Can any distro
folks chime in on whether you've actually encountered users of this
cruft?

Rich


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] remaining steps for time64 switchover
  2019-10-21  2:46 [PATCH] remaining steps for time64 switchover Rich Felker
  2019-10-21 12:43 ` Rich Felker
  2019-10-27  4:26 ` Rich Felker
@ 2019-10-29 19:52 ` Rich Felker
  2019-10-29 19:53   ` Rich Felker
  2019-10-29 23:08 ` Rich Felker
  3 siblings, 1 reply; 15+ messages in thread
From: Rich Felker @ 2019-10-29 19:52 UTC (permalink / raw)
  To: musl

On Sun, Oct 20, 2019 at 10:46:43PM -0400, Rich Felker wrote:
> The attached patch series on top of present git master (commit
> 9b2921bea1d5017832e1b45d1fd64220047a9802) should contain all changes
> needed for fully working time64 on 32-bit archs, in a form that's
> plausibly ready for commit (no makeshift hacks just to get things
> demonstrably working). The one omission I'm aware of is what to do
> with struct utmpx, which is not actually used at present in any libc
> interfaces and thus not part of the ABI surface of libc. That will be
> addressed in a separate thread.
> 
> Comments and basic testing are welcome at this point. It should be
> possible to build for any of the 32-bit archs, but I have only tested
> build for a few and only tested execution on i386 and sh.
> 
> Some useful checks for anyone wanting to help test, especially on the
> more obscure archs:
> 
> [...]
> 
> - Anything look odd about time-related types? timeval/timespec members
>   at positions that aren't naturally aligned?

I tested this on i386 (with low alignment requirement, only 4 bytes)
with the attached program and it seems like I indeed got the padding
slots as-intended on the ipc types. This should mean the adjacent
explicit-padding members have no effect on other archs using the same
changes but with natural alignment, which matches the intent. As usual
mips and ppc are gratuitously different and seemed right to me but
should perhaps be double-checked at some point. However since they
have natural alignment the worst that could happen is leaving extra
padding slots we don't need.

> [...]
> 
> - Does it work with clock set post-2038?

I tested this for arch/sh on j2 (fpga) which was the most convenient
place I had a 5.x kernel, and indeed it works!

> Being that only the final switchover patches are a big step to take,
> I'll probably start pushing the earlier patches in this series pretty
> soon, but want to give a little time for more eyes on them.

I'm going to push them all as a group very soon.

> Note that the final switchovers are split out by arch right now,
> mainly because that was the way that made sense to create them (sed to
> replace arch name, apply to next arch, fix rejects manually) but also
> because it helps compare/review them against each other. It would be
> possible to squash them together for final merge but I probably won't.

I've actually opted to squash them together just because it
facilitates writing a meaningful commit message that explains the ABI
properties, consequences, stability policy, mechanics of the change,
etc. in a non-redundant manner (the explanation is the same across all
archs). The diff naturally splits by arch just by the default pathname
sorting (or by applying the diff just to the appropriate dir under
arch/), so nothing is lost in terms of ability to look at changes for
individual archs separately or compare them.

Rich


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] remaining steps for time64 switchover
  2019-10-29 19:52 ` Rich Felker
@ 2019-10-29 19:53   ` Rich Felker
  0 siblings, 0 replies; 15+ messages in thread
From: Rich Felker @ 2019-10-29 19:53 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 1853 bytes --]

On Tue, Oct 29, 2019 at 03:52:45PM -0400, Rich Felker wrote:
> On Sun, Oct 20, 2019 at 10:46:43PM -0400, Rich Felker wrote:
> > The attached patch series on top of present git master (commit
> > 9b2921bea1d5017832e1b45d1fd64220047a9802) should contain all changes
> > needed for fully working time64 on 32-bit archs, in a form that's
> > plausibly ready for commit (no makeshift hacks just to get things
> > demonstrably working). The one omission I'm aware of is what to do
> > with struct utmpx, which is not actually used at present in any libc
> > interfaces and thus not part of the ABI surface of libc. That will be
> > addressed in a separate thread.
> > 
> > Comments and basic testing are welcome at this point. It should be
> > possible to build for any of the 32-bit archs, but I have only tested
> > build for a few and only tested execution on i386 and sh.
> > 
> > Some useful checks for anyone wanting to help test, especially on the
> > more obscure archs:
> > 
> > [...]
> > 
> > - Anything look odd about time-related types? timeval/timespec members
> >   at positions that aren't naturally aligned?
> 
> I tested this on i386 (with low alignment requirement, only 4 bytes)
> with the attached program and it seems like I indeed got the padding
> slots as-intended on the ipc types. This should mean the adjacent
> explicit-padding members have no effect on other archs using the same
> changes but with natural alignment, which matches the intent. As usual
> mips and ppc are gratuitously different and seemed right to me but
> should perhaps be double-checked at some point. However since they
> have natural alignment the worst that could happen is leaving extra
> padding slots we don't need.

Attachment forgotten, here. Usage is to build against the appropriate
libc/headers and save output, then diff outputs as desired.

Rich


[-- Attachment #2: offsets.c --]
[-- Type: text/plain, Size: 1226 bytes --]


#include <stddef.h>
#include <stdio.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/stat.h>

#define O(s,m) printf("offsetof(%s, %s)==%zd\n", #s, #m, offsetof(s,m))

int main()
{
	O(struct semid_ds, sem_perm);
	O(struct semid_ds, sem_otime);
	O(struct semid_ds, sem_ctime);
	O(struct semid_ds, sem_nsems);

	O(struct shmid_ds, shm_perm);
	O(struct shmid_ds, shm_segsz);
	O(struct shmid_ds, shm_atime);
	O(struct shmid_ds, shm_dtime);
	O(struct shmid_ds, shm_ctime);
	O(struct shmid_ds, shm_cpid);
	O(struct shmid_ds, shm_lpid);
	O(struct shmid_ds, shm_nattch);

	O(struct msqid_ds, msg_perm);
	O(struct msqid_ds, msg_stime);
	O(struct msqid_ds, msg_rtime);
	O(struct msqid_ds, msg_ctime);
	O(struct msqid_ds, msg_cbytes);
	O(struct msqid_ds, msg_qnum);
	O(struct msqid_ds, msg_qbytes);
	O(struct msqid_ds, msg_lspid);
	O(struct msqid_ds, msg_lrpid);

	O(struct stat, st_dev);
	O(struct stat, st_ino);
	O(struct stat, st_mode);
	O(struct stat, st_nlink);
	O(struct stat, st_uid);
	O(struct stat, st_gid);
	O(struct stat, st_rdev);
	O(struct stat, st_size);
	O(struct stat, st_blksize);
	O(struct stat, st_blocks);
	O(struct stat, st_atim);
	O(struct stat, st_mtim);
	O(struct stat, st_ctim);
}

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] remaining steps for time64 switchover
  2019-10-21  2:46 [PATCH] remaining steps for time64 switchover Rich Felker
                   ` (2 preceding siblings ...)
  2019-10-29 19:52 ` Rich Felker
@ 2019-10-29 23:08 ` Rich Felker
  3 siblings, 0 replies; 15+ messages in thread
From: Rich Felker @ 2019-10-29 23:08 UTC (permalink / raw)
  To: musl

On Sun, Oct 20, 2019 at 10:46:43PM -0400, Rich Felker wrote:
> The attached patch series on top of present git master (commit
> 9b2921bea1d5017832e1b45d1fd64220047a9802) should contain all changes
> needed for fully working time64 on 32-bit archs, in a form that's
> plausibly ready for commit (no makeshift hacks just to get things
> demonstrably working). The one omission I'm aware of is what to do
> with struct utmpx, which is not actually used at present in any libc
> interfaces and thus not part of the ABI surface of libc. That will be
> addressed in a separate thread.
> 
> Comments and basic testing are welcome at this point. It should be
> possible to build for any of the 32-bit archs, but I have only tested
> build for a few and only tested execution on i386 and sh.
> 
> Some useful checks for anyone wanting to help test, especially on the
> more obscure archs:
> 
> [...]
> 
> - Does software built against new libc headers basically work?

strace breaks at build time with static_assert that IPC_STAT==2. This
had me momentarily doubting the whole approach of redefining it rather
than making __semctl_time64, etc., but it turns out strace also
depends on struct semid_ds, shmid_ds, and msqid_ds matching the kernel
layouts, which is impossible with time64, so there's really a
fundamental problem here.

Fortunately, strace already had the right code and just wasn't using
it: if HAVE_SYS_SEM_H, etc. aren't defined in config.h (from
autoconf), it falls back to using linux/sem.h, etc., which are exactly
what it should have been using all along: the kernel struct layouts
and command macro definitions.

I think the right patch to strace will be simply removing use of libc
sysvipc headers (always using the kernel ones); it doesn't seem
practical to write a configure test to determine that the libc ones
are usable for parsing the kernel struct.

So, first "oh no!" averted! But this may be a preview of what's to
come. (And I might have chosen strace as an early test case because I
expected things like this.)

Rich


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2019-10-29 23:08 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-21  2:46 [PATCH] remaining steps for time64 switchover Rich Felker
2019-10-21 12:43 ` Rich Felker
2019-10-27  4:15   ` Rich Felker
2019-10-27  4:26 ` Rich Felker
2019-10-27  8:32   ` Laurent Bercot
2019-10-27 14:53     ` Rich Felker
2019-10-27 20:12     ` Matias Fonzo
2019-10-27 21:14       ` Rich Felker
2019-10-27 21:53         ` Matias Fonzo
2019-10-27 23:27           ` Laurent Bercot
2019-10-28 21:31             ` Matias Fonzo
2019-10-28 22:22   ` Rich Felker
2019-10-29 19:52 ` Rich Felker
2019-10-29 19:53   ` Rich Felker
2019-10-29 23:08 ` Rich Felker

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).