Update wasi-libc to 3189cd1ceec8771e8f27faab58ad05d4d6c369ef (#15817)

Also remove all the wasi-libc files we used to ship, but never compile.

The latest wasi-libc HEAD has an extra commit (a6f871343313220b76009827ed0153586361c0d5), which makes preopen initialization lazy.

Unfortunately, that breaks quite a lot of things on our end. Applications now need to explicitly call __wasilibc_populate_preopens() everywhere when the libc is linked. That can wait after 0.11.
This commit is contained in:
Frank Denis 2023-05-23 22:12:53 +02:00 committed by GitHub
parent 0000b34a2d
commit dcc1b4fd15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1107 changed files with 27 additions and 27261 deletions

View File

@ -1,7 +1,27 @@
#if defined(_REENTRANT)
#include <stdatomic.h>
extern void __wasi_init_tp(void);
#endif
extern void __wasm_call_ctors(void);
__attribute__((export_name("_initialize")))
void _initialize(void) {
#if defined(_REENTRANT)
static volatile atomic_int initialized = 0;
int expected = 0;
if (!atomic_compare_exchange_strong(&initialized, &expected, 1)) {
__builtin_trap();
}
__wasi_init_tp();
#else
static volatile int initialized = 0;
if (initialized != 0) {
__builtin_trap();
}
initialized = 1;
#endif
// The linker synthesizes this to call constructors.
__wasm_call_ctors();
}

View File

@ -0,0 +1,5 @@
#include <errno.h>
int *__errno_location(void) {
return &errno;
}

View File

@ -662,7 +662,7 @@ __wasi_errno_t __wasi_sock_shutdown(
#ifdef _REENTRANT
int32_t __imported_wasi_thread_spawn(int32_t arg0) __attribute__((
__import_module__("wasi"),
__import_name__("thread_spawn")
__import_name__("thread-spawn")
));
int32_t __wasi_thread_spawn(void* start_arg) {

View File

@ -1,4 +1,3 @@
#define a_barrier() (__sync_synchronize())
#define a_cas(p, t, s) (__sync_val_compare_and_swap((p), (t), (s)))
#define a_crash() (__builtin_trap())
#define a_clz_32 __builtin_clz

View File

@ -55,15 +55,9 @@ extern "C" {
#define PTHREAD_PROCESS_SHARED 1
#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
#define PTHREAD_MUTEX_INITIALIZER {{{0}}}
#define PTHREAD_RWLOCK_INITIALIZER {{{0}}}
#define PTHREAD_COND_INITIALIZER {{{0}}}
#else
#define PTHREAD_MUTEX_INITIALIZER 0
#define PTHREAD_RWLOCK_INITIALIZER 0
#define PTHREAD_COND_INITIALIZER 0
#endif
#define PTHREAD_ONCE_INIT 0

View File

@ -1,418 +0,0 @@
#include <aio.h>
#include <pthread.h>
#include <semaphore.h>
#include <limits.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/auxv.h>
#include "syscall.h"
#include "atomic.h"
#include "pthread_impl.h"
#include "aio_impl.h"
#define malloc __libc_malloc
#define calloc __libc_calloc
#define realloc __libc_realloc
#define free __libc_free
/* The following is a threads-based implementation of AIO with minimal
* dependence on implementation details. Most synchronization is
* performed with pthread primitives, but atomics and futex operations
* are used for notification in a couple places where the pthread
* primitives would be inefficient or impractical.
*
* For each fd with outstanding aio operations, an aio_queue structure
* is maintained. These are reference-counted and destroyed by the last
* aio worker thread to exit. Accessing any member of the aio_queue
* structure requires a lock on the aio_queue. Adding and removing aio
* queues themselves requires a write lock on the global map object,
* a 4-level table mapping file descriptor numbers to aio queues. A
* read lock on the map is used to obtain locks on existing queues by
* excluding destruction of the queue by a different thread while it is
* being locked.
*
* Each aio queue has a list of active threads/operations. Presently there
* is a one to one relationship between threads and operations. The only
* members of the aio_thread structure which are accessed by other threads
* are the linked list pointers, op (which is immutable), running (which
* is updated atomically), and err (which is synchronized via running),
* so no locking is necessary. Most of the other other members are used
* for sharing data between the main flow of execution and cancellation
* cleanup handler.
*
* Taking any aio locks requires having all signals blocked. This is
* necessary because aio_cancel is needed by close, and close is required
* to be async-signal safe. All aio worker threads run with all signals
* blocked permanently.
*/
struct aio_thread {
pthread_t td;
struct aiocb *cb;
struct aio_thread *next, *prev;
struct aio_queue *q;
volatile int running;
int err, op;
ssize_t ret;
};
struct aio_queue {
int fd, seekable, append, ref, init;
pthread_mutex_t lock;
pthread_cond_t cond;
struct aio_thread *head;
};
struct aio_args {
struct aiocb *cb;
struct aio_queue *q;
int op;
sem_t sem;
};
static pthread_rwlock_t maplock = PTHREAD_RWLOCK_INITIALIZER;
static struct aio_queue *****map;
static volatile int aio_fd_cnt;
volatile int __aio_fut;
static size_t io_thread_stack_size;
#define MAX(a,b) ((a)>(b) ? (a) : (b))
static struct aio_queue *__aio_get_queue(int fd, int need)
{
if (fd < 0) {
errno = EBADF;
return 0;
}
int a=fd>>24;
unsigned char b=fd>>16, c=fd>>8, d=fd;
struct aio_queue *q = 0;
pthread_rwlock_rdlock(&maplock);
if ((!map || !map[a] || !map[a][b] || !map[a][b][c] || !(q=map[a][b][c][d])) && need) {
pthread_rwlock_unlock(&maplock);
if (fcntl(fd, F_GETFD) < 0) return 0;
pthread_rwlock_wrlock(&maplock);
if (!io_thread_stack_size) {
unsigned long val = __getauxval(AT_MINSIGSTKSZ);
io_thread_stack_size = MAX(MINSIGSTKSZ+2048, val+512);
}
if (!map) map = calloc(sizeof *map, (-1U/2+1)>>24);
if (!map) goto out;
if (!map[a]) map[a] = calloc(sizeof **map, 256);
if (!map[a]) goto out;
if (!map[a][b]) map[a][b] = calloc(sizeof ***map, 256);
if (!map[a][b]) goto out;
if (!map[a][b][c]) map[a][b][c] = calloc(sizeof ****map, 256);
if (!map[a][b][c]) goto out;
if (!(q = map[a][b][c][d])) {
map[a][b][c][d] = q = calloc(sizeof *****map, 1);
if (q) {
q->fd = fd;
pthread_mutex_init(&q->lock, 0);
pthread_cond_init(&q->cond, 0);
a_inc(&aio_fd_cnt);
}
}
}
if (q) pthread_mutex_lock(&q->lock);
out:
pthread_rwlock_unlock(&maplock);
return q;
}
static void __aio_unref_queue(struct aio_queue *q)
{
if (q->ref > 1) {
q->ref--;
pthread_mutex_unlock(&q->lock);
return;
}
/* This is potentially the last reference, but a new reference
* may arrive since we cannot free the queue object without first
* taking the maplock, which requires releasing the queue lock. */
pthread_mutex_unlock(&q->lock);
pthread_rwlock_wrlock(&maplock);
pthread_mutex_lock(&q->lock);
if (q->ref == 1) {
int fd=q->fd;
int a=fd>>24;
unsigned char b=fd>>16, c=fd>>8, d=fd;
map[a][b][c][d] = 0;
a_dec(&aio_fd_cnt);
pthread_rwlock_unlock(&maplock);
pthread_mutex_unlock(&q->lock);
free(q);
} else {
q->ref--;
pthread_rwlock_unlock(&maplock);
pthread_mutex_unlock(&q->lock);
}
}
static void cleanup(void *ctx)
{
struct aio_thread *at = ctx;
struct aio_queue *q = at->q;
struct aiocb *cb = at->cb;
struct sigevent sev = cb->aio_sigevent;
/* There are four potential types of waiters we could need to wake:
* 1. Callers of aio_cancel/close.
* 2. Callers of aio_suspend with a single aiocb.
* 3. Callers of aio_suspend with a list.
* 4. AIO worker threads waiting for sequenced operations.
* Types 1-3 are notified via atomics/futexes, mainly for AS-safety
* considerations. Type 4 is notified later via a cond var. */
cb->__ret = at->ret;
if (a_swap(&at->running, 0) < 0)
__wake(&at->running, -1, 1);
if (a_swap(&cb->__err, at->err) != EINPROGRESS)
__wake(&cb->__err, -1, 1);
if (a_swap(&__aio_fut, 0))
__wake(&__aio_fut, -1, 1);
pthread_mutex_lock(&q->lock);
if (at->next) at->next->prev = at->prev;
if (at->prev) at->prev->next = at->next;
else q->head = at->next;
/* Signal aio worker threads waiting for sequenced operations. */
pthread_cond_broadcast(&q->cond);
__aio_unref_queue(q);
if (sev.sigev_notify == SIGEV_SIGNAL) {
siginfo_t si = {
.si_signo = sev.sigev_signo,
.si_value = sev.sigev_value,
.si_code = SI_ASYNCIO,
.si_pid = getpid(),
.si_uid = getuid()
};
__syscall(SYS_rt_sigqueueinfo, si.si_pid, si.si_signo, &si);
}
if (sev.sigev_notify == SIGEV_THREAD) {
a_store(&__pthread_self()->cancel, 0);
sev.sigev_notify_function(sev.sigev_value);
}
}
static void *io_thread_func(void *ctx)
{
struct aio_thread at, *p;
struct aio_args *args = ctx;
struct aiocb *cb = args->cb;
int fd = cb->aio_fildes;
int op = args->op;
void *buf = (void *)cb->aio_buf;
size_t len = cb->aio_nbytes;
off_t off = cb->aio_offset;
struct aio_queue *q = args->q;
ssize_t ret;
pthread_mutex_lock(&q->lock);
sem_post(&args->sem);
at.op = op;
at.running = 1;
at.ret = -1;
at.err = ECANCELED;
at.q = q;
at.td = __pthread_self();
at.cb = cb;
at.prev = 0;
if ((at.next = q->head)) at.next->prev = &at;
q->head = &at;
if (!q->init) {
int seekable = lseek(fd, 0, SEEK_CUR) >= 0;
q->seekable = seekable;
q->append = !seekable || (fcntl(fd, F_GETFL) & O_APPEND);
q->init = 1;
}
pthread_cleanup_push(cleanup, &at);
/* Wait for sequenced operations. */
if (op!=LIO_READ && (op!=LIO_WRITE || q->append)) {
for (;;) {
for (p=at.next; p && p->op!=LIO_WRITE; p=p->next);
if (!p) break;
pthread_cond_wait(&q->cond, &q->lock);
}
}
pthread_mutex_unlock(&q->lock);
switch (op) {
case LIO_WRITE:
ret = q->append ? write(fd, buf, len) : pwrite(fd, buf, len, off);
break;
case LIO_READ:
ret = !q->seekable ? read(fd, buf, len) : pread(fd, buf, len, off);
break;
case O_SYNC:
ret = fsync(fd);
break;
case O_DSYNC:
ret = fdatasync(fd);
break;
}
at.ret = ret;
at.err = ret<0 ? errno : 0;
pthread_cleanup_pop(1);
return 0;
}
static int submit(struct aiocb *cb, int op)
{
int ret = 0;
pthread_attr_t a;
sigset_t allmask, origmask;
pthread_t td;
struct aio_queue *q = __aio_get_queue(cb->aio_fildes, 1);
struct aio_args args = { .cb = cb, .op = op, .q = q };
sem_init(&args.sem, 0, 0);
if (!q) {
if (errno != EBADF) errno = EAGAIN;
cb->__ret = -1;
cb->__err = errno;
return -1;
}
q->ref++;
pthread_mutex_unlock(&q->lock);
if (cb->aio_sigevent.sigev_notify == SIGEV_THREAD) {
if (cb->aio_sigevent.sigev_notify_attributes)
a = *cb->aio_sigevent.sigev_notify_attributes;
else
pthread_attr_init(&a);
} else {
pthread_attr_init(&a);
pthread_attr_setstacksize(&a, io_thread_stack_size);
pthread_attr_setguardsize(&a, 0);
}
pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);
sigfillset(&allmask);
pthread_sigmask(SIG_BLOCK, &allmask, &origmask);
cb->__err = EINPROGRESS;
if (pthread_create(&td, &a, io_thread_func, &args)) {
pthread_mutex_lock(&q->lock);
__aio_unref_queue(q);
cb->__err = errno = EAGAIN;
cb->__ret = ret = -1;
}
pthread_sigmask(SIG_SETMASK, &origmask, 0);
if (!ret) {
while (sem_wait(&args.sem));
}
return ret;
}
int aio_read(struct aiocb *cb)
{
return submit(cb, LIO_READ);
}
int aio_write(struct aiocb *cb)
{
return submit(cb, LIO_WRITE);
}
int aio_fsync(int op, struct aiocb *cb)
{
if (op != O_SYNC && op != O_DSYNC) {
errno = EINVAL;
return -1;
}
return submit(cb, op);
}
ssize_t aio_return(struct aiocb *cb)
{
return cb->__ret;
}
int aio_error(const struct aiocb *cb)
{
a_barrier();
return cb->__err & 0x7fffffff;
}
int aio_cancel(int fd, struct aiocb *cb)
{
sigset_t allmask, origmask;
int ret = AIO_ALLDONE;
struct aio_thread *p;
struct aio_queue *q;
/* Unspecified behavior case. Report an error. */
if (cb && fd != cb->aio_fildes) {
errno = EINVAL;
return -1;
}
sigfillset(&allmask);
pthread_sigmask(SIG_BLOCK, &allmask, &origmask);
errno = ENOENT;
if (!(q = __aio_get_queue(fd, 0))) {
if (errno == EBADF) ret = -1;
goto done;
}
for (p = q->head; p; p = p->next) {
if (cb && cb != p->cb) continue;
/* Transition target from running to running-with-waiters */
if (a_cas(&p->running, 1, -1)) {
pthread_cancel(p->td);
__wait(&p->running, 0, -1, 1);
if (p->err == ECANCELED) ret = AIO_CANCELED;
}
}
pthread_mutex_unlock(&q->lock);
done:
pthread_sigmask(SIG_SETMASK, &origmask, 0);
return ret;
}
int __aio_close(int fd)
{
a_barrier();
if (aio_fd_cnt) aio_cancel(fd, 0);
return fd;
}
void __aio_atfork(int who)
{
if (who<0) {
pthread_rwlock_rdlock(&maplock);
return;
}
if (who>0 && map) for (int a=0; a<(-1U/2+1)>>24; a++)
if (map[a]) for (int b=0; b<256; b++)
if (map[a][b]) for (int c=0; c<256; c++)
if (map[a][b][c]) for (int d=0; d<256; d++)
map[a][b][c][d] = 0;
pthread_rwlock_unlock(&maplock);
}
weak_alias(aio_cancel, aio_cancel64);
weak_alias(aio_error, aio_error64);
weak_alias(aio_fsync, aio_fsync64);
weak_alias(aio_read, aio_read64);
weak_alias(aio_write, aio_write64);
weak_alias(aio_return, aio_return64);

View File

@ -1,79 +0,0 @@
#include <aio.h>
#include <errno.h>
#include <time.h>
#include "atomic.h"
#include "pthread_impl.h"
#include "aio_impl.h"
int aio_suspend(const struct aiocb *const cbs[], int cnt, const struct timespec *ts)
{
int i, tid = 0, ret, expect = 0;
struct timespec at;
volatile int dummy_fut, *pfut;
int nzcnt = 0;
const struct aiocb *cb = 0;
pthread_testcancel();
if (cnt<0) {
errno = EINVAL;
return -1;
}
for (i=0; i<cnt; i++) if (cbs[i]) {
if (aio_error(cbs[i]) != EINPROGRESS) return 0;
nzcnt++;
cb = cbs[i];
}
if (ts) {
clock_gettime(CLOCK_MONOTONIC, &at);
at.tv_sec += ts->tv_sec;
if ((at.tv_nsec += ts->tv_nsec) >= 1000000000) {
at.tv_nsec -= 1000000000;
at.tv_sec++;
}
}
for (;;) {
for (i=0; i<cnt; i++)
if (cbs[i] && aio_error(cbs[i]) != EINPROGRESS)
return 0;
switch (nzcnt) {
case 0:
pfut = &dummy_fut;
break;
case 1:
pfut = (void *)&cb->__err;
expect = EINPROGRESS | 0x80000000;
a_cas(pfut, EINPROGRESS, expect);
break;
default:
pfut = &__aio_fut;
if (!tid) tid = __pthread_self()->tid;
expect = a_cas(pfut, 0, tid);
if (!expect) expect = tid;
/* Need to recheck the predicate before waiting. */
for (i=0; i<cnt; i++)
if (cbs[i] && aio_error(cbs[i]) != EINPROGRESS)
return 0;
break;
}
ret = __timedwait_cp(pfut, expect, CLOCK_MONOTONIC, ts?&at:0, 1);
switch (ret) {
case ETIMEDOUT:
ret = EAGAIN;
case ECANCELED:
case EINTR:
errno = ret;
return -1;
}
}
}
#if !_REDIR_TIME64
weak_alias(aio_suspend, aio_suspend64);
#endif

View File

@ -1,143 +0,0 @@
#include <aio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include "pthread_impl.h"
struct lio_state {
struct sigevent *sev;
int cnt;
struct aiocb *cbs[];
};
static int lio_wait(struct lio_state *st)
{
int i, err, got_err = 0;
int cnt = st->cnt;
struct aiocb **cbs = st->cbs;
for (;;) {
for (i=0; i<cnt; i++) {
if (!cbs[i]) continue;
err = aio_error(cbs[i]);
if (err==EINPROGRESS)
break;
if (err) got_err=1;
cbs[i] = 0;
}
if (i==cnt) {
if (got_err) {
errno = EIO;
return -1;
}
return 0;
}
if (aio_suspend((void *)cbs, cnt, 0))
return -1;
}
}
static void notify_signal(struct sigevent *sev)
{
siginfo_t si = {
.si_signo = sev->sigev_signo,
.si_value = sev->sigev_value,
.si_code = SI_ASYNCIO,
.si_pid = getpid(),
.si_uid = getuid()
};
__syscall(SYS_rt_sigqueueinfo, si.si_pid, si.si_signo, &si);
}
static void *wait_thread(void *p)
{
struct lio_state *st = p;
struct sigevent *sev = st->sev;
lio_wait(st);
free(st);
switch (sev->sigev_notify) {
case SIGEV_SIGNAL:
notify_signal(sev);
break;
case SIGEV_THREAD:
sev->sigev_notify_function(sev->sigev_value);
break;
}
return 0;
}
int lio_listio(int mode, struct aiocb *restrict const *restrict cbs, int cnt, struct sigevent *restrict sev)
{
int i, ret;
struct lio_state *st=0;
if (cnt < 0) {
errno = EINVAL;
return -1;
}
if (mode == LIO_WAIT || (sev && sev->sigev_notify != SIGEV_NONE)) {
if (!(st = malloc(sizeof *st + cnt*sizeof *cbs))) {
errno = EAGAIN;
return -1;
}
st->cnt = cnt;
st->sev = sev;
memcpy(st->cbs, (void*) cbs, cnt*sizeof *cbs);
}
for (i=0; i<cnt; i++) {
if (!cbs[i]) continue;
switch (cbs[i]->aio_lio_opcode) {
case LIO_READ:
ret = aio_read(cbs[i]);
break;
case LIO_WRITE:
ret = aio_write(cbs[i]);
break;
default:
continue;
}
if (ret) {
free(st);
errno = EAGAIN;
return -1;
}
}
if (mode == LIO_WAIT) {
ret = lio_wait(st);
free(st);
return ret;
}
if (st) {
pthread_attr_t a;
sigset_t set, set_old;
pthread_t td;
if (sev->sigev_notify == SIGEV_THREAD) {
if (sev->sigev_notify_attributes)
a = *sev->sigev_notify_attributes;
else
pthread_attr_init(&a);
} else {
pthread_attr_init(&a);
pthread_attr_setstacksize(&a, PAGE_SIZE);
pthread_attr_setguardsize(&a, 0);
}
pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);
sigfillset(&set);
pthread_sigmask(SIG_BLOCK, &set, &set_old);
if (pthread_create(&td, &a, wait_thread, st)) {
free(st);
errno = EAGAIN;
return -1;
}
pthread_sigmask(SIG_SETMASK, &set_old, 0);
}
return 0;
}
weak_alias(lio_listio, lio_listio64);

View File

@ -1,6 +0,0 @@
#include "complex_impl.h"
double (cimag)(double complex z)
{
return cimag(z);
}

View File

@ -1,6 +0,0 @@
#include "complex_impl.h"
float (cimagf)(float complex z)
{
return cimagf(z);
}

View File

@ -1,6 +0,0 @@
#include "complex_impl.h"
long double (cimagl)(long double complex z)
{
return cimagl(z);
}

View File

@ -1,6 +0,0 @@
#include <complex.h>
double (creal)(double complex z)
{
return creal(z);
}

View File

@ -1,6 +0,0 @@
#include <complex.h>
float (crealf)(float complex z)
{
return crealf(z);
}

View File

@ -1,6 +0,0 @@
#include <complex.h>
long double (creall)(long double complex z)
{
return creall(z);
}

View File

@ -1,11 +0,0 @@
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include "__dirent.h"
int closedir(DIR *dir)
{
int ret = close(dir->fd);
free(dir);
return ret;
}

View File

@ -1,7 +0,0 @@
#include <dirent.h>
#include "__dirent.h"
int dirfd(DIR *d)
{
return d->fd;
}

View File

@ -1,31 +0,0 @@
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>
#include "__dirent.h"
DIR *fdopendir(int fd)
{
DIR *dir;
struct stat st;
if (fstat(fd, &st) < 0) {
return 0;
}
if (fcntl(fd, F_GETFL) & O_PATH) {
errno = EBADF;
return 0;
}
if (!S_ISDIR(st.st_mode)) {
errno = ENOTDIR;
return 0;
}
if (!(dir = calloc(1, sizeof *dir))) {
return 0;
}
fcntl(fd, F_SETFD, FD_CLOEXEC);
dir->fd = fd;
return dir;
}

View File

@ -1,21 +0,0 @@
#define _GNU_SOURCE
#include <dirent.h>
#include <fcntl.h>
#include <stdlib.h>
#include "__dirent.h"
#include "syscall.h"
DIR *opendir(const char *name)
{
int fd;
DIR *dir;
if ((fd = open(name, O_RDONLY|O_DIRECTORY|O_CLOEXEC)) < 0)
return 0;
if (!(dir = calloc(1, sizeof *dir))) {
__syscall(SYS_close, fd);
return 0;
}
dir->fd = fd;
return dir;
}

View File

@ -1,29 +0,0 @@
#include <dirent.h>
#include <errno.h>
#include <stddef.h>
#include "__dirent.h"
#include "syscall.h"
typedef char dirstream_buf_alignment_check[1-2*(int)(
offsetof(struct __dirstream, buf) % sizeof(off_t))];
struct dirent *readdir(DIR *dir)
{
struct dirent *de;
if (dir->buf_pos >= dir->buf_end) {
int len = __syscall(SYS_getdents, dir->fd, dir->buf, sizeof dir->buf);
if (len <= 0) {
if (len < 0 && len != -ENOENT) errno = -len;
return 0;
}
dir->buf_end = len;
dir->buf_pos = 0;
}
de = (void *)(dir->buf + dir->buf_pos);
dir->buf_pos += de->d_reclen;
dir->tell = de->d_off;
return de;
}
weak_alias(readdir, readdir64);

View File

@ -1,29 +0,0 @@
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include "__dirent.h"
#include "lock.h"
int readdir_r(DIR *restrict dir, struct dirent *restrict buf, struct dirent **restrict result)
{
struct dirent *de;
int errno_save = errno;
int ret;
LOCK(dir->lock);
errno = 0;
de = readdir(dir);
if ((ret = errno)) {
UNLOCK(dir->lock);
return ret;
}
errno = errno_save;
if (de) memcpy(buf, de, de->d_reclen);
else buf = NULL;
UNLOCK(dir->lock);
*result = buf;
return 0;
}
weak_alias(readdir_r, readdir64_r);

View File

@ -1,13 +0,0 @@
#include <dirent.h>
#include <unistd.h>
#include "__dirent.h"
#include "lock.h"
void rewinddir(DIR *dir)
{
LOCK(dir->lock);
lseek(dir->fd, 0, SEEK_SET);
dir->buf_pos = dir->buf_end = 0;
dir->tell = 0;
UNLOCK(dir->lock);
}

View File

@ -1,47 +0,0 @@
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <stddef.h>
int scandir(const char *path, struct dirent ***res,
int (*sel)(const struct dirent *),
int (*cmp)(const struct dirent **, const struct dirent **))
{
DIR *d = opendir(path);
struct dirent *de, **names=0, **tmp;
size_t cnt=0, len=0;
int old_errno = errno;
if (!d) return -1;
while ((errno=0), (de = readdir(d))) {
if (sel && !sel(de)) continue;
if (cnt >= len) {
len = 2*len+1;
if (len > SIZE_MAX/sizeof *names) break;
tmp = realloc(names, len * sizeof *names);
if (!tmp) break;
names = tmp;
}
names[cnt] = malloc(de->d_reclen);
if (!names[cnt]) break;
memcpy(names[cnt++], de, de->d_reclen);
}
closedir(d);
if (errno) {
if (names) while (cnt-->0) free(names[cnt]);
free(names);
return -1;
}
errno = old_errno;
if (cmp) qsort(names, cnt, sizeof *names, (int (*)(const void *, const void *))cmp);
*res = names;
return cnt;
}
weak_alias(scandir, scandir64);

View File

@ -1,12 +0,0 @@
#include <dirent.h>
#include <unistd.h>
#include "__dirent.h"
#include "lock.h"
void seekdir(DIR *dir, long off)
{
LOCK(dir->lock);
dir->tell = lseek(dir->fd, off, SEEK_SET);
dir->buf_pos = dir->buf_end = 0;
UNLOCK(dir->lock);
}

View File

@ -1,7 +0,0 @@
#include <dirent.h>
#include "__dirent.h"
long telldir(DIR *dir)
{
return dir->tell;
}

View File

@ -1,6 +0,0 @@
#include <unistd.h>
char **__environ = 0;
weak_alias(__environ, ___environ);
weak_alias(__environ, _environ);
weak_alias(__environ, environ);

View File

@ -1,237 +0,0 @@
#ifdef __wasilibc_unmodified_upstream
#define SYSCALL_NO_TLS 1
#include <elf.h>
#endif
#include <limits.h>
#ifdef __wasilibc_unmodified_upstream
#include <sys/mman.h>
#endif
#include <string.h>
#include <stddef.h>
#include "pthread_impl.h"
#include "libc.h"
#include "atomic.h"
#include "syscall.h"
volatile int __thread_list_lock;
#ifndef __wasilibc_unmodified_upstream
/* These symbols are generated by wasm-ld. __stack_high/__stack_low
* symbols are only available in LLVM v16 and higher, therefore they're
* defined as weak symbols and if not available, __heap_base/__data_end
* is used instead.
*
* TODO: remove usage of __heap_base/__data_end for stack size calculation
* once we drop support for LLVM v15 and older.
*/
extern unsigned char __heap_base;
extern unsigned char __data_end;
extern unsigned char __global_base;
extern weak unsigned char __stack_high;
extern weak unsigned char __stack_low;
static inline void setup_default_stack_size()
{
ptrdiff_t stack_size;
if (&__stack_high)
stack_size = &__stack_high - &__stack_low;
else {
unsigned char *sp;
__asm__(
".globaltype __stack_pointer, i32\n"
"global.get __stack_pointer\n"
"local.set %0\n"
: "=r"(sp));
stack_size = sp > &__global_base ? &__heap_base - &__data_end : (ptrdiff_t)&__global_base;
}
if (stack_size > __default_stacksize)
__default_stacksize =
stack_size < DEFAULT_STACK_MAX ?
stack_size : DEFAULT_STACK_MAX;
}
void __wasi_init_tp() {
__init_tp((void *)__get_tp());
}
#endif
int __init_tp(void *p)
{
pthread_t td = p;
td->self = td;
#ifdef __wasilibc_unmodified_upstream
int r = __set_thread_area(TP_ADJ(p));
if (r < 0) return -1;
if (!r) libc.can_do_threads = 1;
td->detach_state = DT_JOINABLE;
td->tid = __syscall(SYS_set_tid_address, &__thread_list_lock);
#else
setup_default_stack_size();
td->detach_state = DT_JOINABLE;
/*
* Initialize the TID to a value which doesn't conflict with
* host-allocated TIDs, so that TID-based locks can work.
*
* Note:
* - Host-allocated TIDs range from 1 to 0x1fffffff. (inclusive)
* - __tl_lock and __lockfile uses TID 0 as "unlocked".
* - __lockfile relies on the fact the most significant two bits
* of TIDs are 0.
*/
td->tid = 0x3fffffff;
#endif
td->locale = &libc.global_locale;
td->robust_list.head = &td->robust_list.head;
td->sysinfo = __sysinfo;
td->next = td->prev = td;
return 0;
}
#ifdef __wasilibc_unmodified_upstream
static struct builtin_tls {
char c;
struct pthread pt;
void *space[16];
} builtin_tls[1];
#define MIN_TLS_ALIGN offsetof(struct builtin_tls, pt)
static struct tls_module main_tls;
#endif
#ifndef __wasilibc_unmodified_upstream
extern void __wasm_init_tls(void*);
#endif
void *__copy_tls(unsigned char *mem)
{
#ifdef __wasilibc_unmodified_upstream
pthread_t td;
struct tls_module *p;
size_t i;
uintptr_t *dtv;
#ifdef TLS_ABOVE_TP
dtv = (uintptr_t*)(mem + libc.tls_size) - (libc.tls_cnt + 1);
mem += -((uintptr_t)mem + sizeof(struct pthread)) & (libc.tls_align-1);
td = (pthread_t)mem;
mem += sizeof(struct pthread);
for (i=1, p=libc.tls_head; p; i++, p=p->next) {
dtv[i] = (uintptr_t)(mem + p->offset) + DTP_OFFSET;
memcpy(mem + p->offset, p->image, p->len);
}
#else
dtv = (uintptr_t *)mem;
mem += libc.tls_size - sizeof(struct pthread);
mem -= (uintptr_t)mem & (libc.tls_align-1);
td = (pthread_t)mem;
for (i=1, p=libc.tls_head; p; i++, p=p->next) {
dtv[i] = (uintptr_t)(mem - p->offset) + DTP_OFFSET;
memcpy(mem - p->offset, p->image, p->len);
}
#endif
dtv[0] = libc.tls_cnt;
td->dtv = dtv;
return td;
#else
size_t tls_align = __builtin_wasm_tls_align();
volatile void* tls_base = __builtin_wasm_tls_base();
mem += tls_align;
mem -= (uintptr_t)mem & (tls_align-1);
__wasm_init_tls(mem);
__asm__("local.get %0\n"
"global.set __tls_base\n"
:: "r"(tls_base));
return mem;
#endif
}
#ifdef __wasilibc_unmodified_upstream
#if ULONG_MAX == 0xffffffff
typedef Elf32_Phdr Phdr;
#else
typedef Elf64_Phdr Phdr;
#endif
extern weak hidden const size_t _DYNAMIC[];
static void static_init_tls(size_t *aux)
{
unsigned char *p;
size_t n;
Phdr *phdr, *tls_phdr=0;
size_t base = 0;
void *mem;
for (p=(void *)aux[AT_PHDR],n=aux[AT_PHNUM]; n; n--,p+=aux[AT_PHENT]) {
phdr = (void *)p;
if (phdr->p_type == PT_PHDR)
base = aux[AT_PHDR] - phdr->p_vaddr;
if (phdr->p_type == PT_DYNAMIC && _DYNAMIC)
base = (size_t)_DYNAMIC - phdr->p_vaddr;
if (phdr->p_type == PT_TLS)
tls_phdr = phdr;
if (phdr->p_type == PT_GNU_STACK &&
phdr->p_memsz > __default_stacksize)
__default_stacksize =
phdr->p_memsz < DEFAULT_STACK_MAX ?
phdr->p_memsz : DEFAULT_STACK_MAX;
}
if (tls_phdr) {
main_tls.image = (void *)(base + tls_phdr->p_vaddr);
main_tls.len = tls_phdr->p_filesz;
main_tls.size = tls_phdr->p_memsz;
main_tls.align = tls_phdr->p_align;
libc.tls_cnt = 1;
libc.tls_head = &main_tls;
}
main_tls.size += (-main_tls.size - (uintptr_t)main_tls.image)
& (main_tls.align-1);
#ifdef TLS_ABOVE_TP
main_tls.offset = GAP_ABOVE_TP;
main_tls.offset += (-GAP_ABOVE_TP + (uintptr_t)main_tls.image)
& (main_tls.align-1);
#else
main_tls.offset = main_tls.size;
#endif
if (main_tls.align < MIN_TLS_ALIGN) main_tls.align = MIN_TLS_ALIGN;
libc.tls_align = main_tls.align;
libc.tls_size = 2*sizeof(void *) + sizeof(struct pthread)
#ifdef TLS_ABOVE_TP
+ main_tls.offset
#endif
+ main_tls.size + main_tls.align
+ MIN_TLS_ALIGN-1 & -MIN_TLS_ALIGN;
if (libc.tls_size > sizeof builtin_tls) {
#ifndef SYS_mmap2
#define SYS_mmap2 SYS_mmap
#endif
mem = (void *)__syscall(
SYS_mmap2,
0, libc.tls_size, PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
/* -4095...-1 cast to void * will crash on dereference anyway,
* so don't bloat the init code checking for error codes and
* explicitly calling a_crash(). */
} else {
mem = builtin_tls;
}
/* Failure to initialize thread pointer is always fatal. */
if (__init_tp(__copy_tls(mem)) < 0)
a_crash();
}
weak_alias(static_init_tls, __init_tls);
#endif

View File

@ -1,97 +0,0 @@
#include <elf.h>
#include <poll.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include "syscall.h"
#include "atomic.h"
#include "libc.h"
static void dummy(void) {}
weak_alias(dummy, _init);
extern weak hidden void (*const __init_array_start)(void), (*const __init_array_end)(void);
static void dummy1(void *p) {}
weak_alias(dummy1, __init_ssp);
#define AUX_CNT 38
#ifdef __GNUC__
__attribute__((__noinline__))
#endif
void __init_libc(char **envp, char *pn)
{
size_t i, *auxv, aux[AUX_CNT] = { 0 };
__environ = envp;
for (i=0; envp[i]; i++);
libc.auxv = auxv = (void *)(envp+i+1);
for (i=0; auxv[i]; i+=2) if (auxv[i]<AUX_CNT) aux[auxv[i]] = auxv[i+1];
__hwcap = aux[AT_HWCAP];
if (aux[AT_SYSINFO]) __sysinfo = aux[AT_SYSINFO];
libc.page_size = aux[AT_PAGESZ];
if (!pn) pn = (void*)aux[AT_EXECFN];
if (!pn) pn = "";
__progname = __progname_full = pn;
for (i=0; pn[i]; i++) if (pn[i]=='/') __progname = pn+i+1;
__init_tls(aux);
__init_ssp((void *)aux[AT_RANDOM]);
if (aux[AT_UID]==aux[AT_EUID] && aux[AT_GID]==aux[AT_EGID]
&& !aux[AT_SECURE]) return;
struct pollfd pfd[3] = { {.fd=0}, {.fd=1}, {.fd=2} };
int r =
#ifdef SYS_poll
__syscall(SYS_poll, pfd, 3, 0);
#else
__syscall(SYS_ppoll, pfd, 3, &(struct timespec){0}, 0, _NSIG/8);
#endif
if (r<0) a_crash();
for (i=0; i<3; i++) if (pfd[i].revents&POLLNVAL)
if (__sys_open("/dev/null", O_RDWR)<0)
a_crash();
libc.secure = 1;
}
static void libc_start_init(void)
{
_init();
uintptr_t a = (uintptr_t)&__init_array_start;
for (; a<(uintptr_t)&__init_array_end; a+=sizeof(void(*)()))
(*(void (**)(void))a)();
}
weak_alias(libc_start_init, __libc_start_init);
typedef int lsm2_fn(int (*)(int,char **,char **), int, char **);
static lsm2_fn libc_start_main_stage2;
int __libc_start_main(int (*main)(int,char **,char **), int argc, char **argv,
void (*init_dummy)(), void(*fini_dummy)(), void(*ldso_dummy)())
{
char **envp = argv+argc+1;
/* External linkage, and explicit noinline attribute if available,
* are used to prevent the stack frame used during init from
* persisting for the entire process lifetime. */
__init_libc(envp, argv[0]);
/* Barrier against hoisting application code or anything using ssp
* or thread pointer prior to its initialization above. */
lsm2_fn *stage2 = libc_start_main_stage2;
__asm__ ( "" : "+r"(stage2) : : "memory" );
return stage2(main, argc, argv);
}
static int libc_start_main_stage2(int (*main)(int,char **,char **), int argc, char **argv)
{
char **envp = argv+argc+1;
__libc_start_init();
/* Pass control to the application */
exit(main(argc, argv, envp));
return 0;
}

View File

@ -1,15 +0,0 @@
#include <string.h>
#include "pthread_impl.h"
#include "libc.h"
void __reset_tls()
{
pthread_t self = __pthread_self();
struct tls_module *p;
size_t i, n = self->dtv[0];
if (n) for (p=libc.tls_head, i=1; i<=n; i++, p=p->next) {
char *mem = (char *)(self->dtv[i] - DTP_OFFSET);
memcpy(mem, p->image, p->len);
memset(mem+p->len, 0, p->size - p->len);
}
}

View File

@ -1,8 +0,0 @@
#define _GNU_SOURCE
#include <stdlib.h>
#include "libc.h"
char *secure_getenv(const char *name)
{
return libc.secure ? NULL : getenv(name);
}

View File

@ -1,9 +0,0 @@
#include <errno.h>
#include "pthread_impl.h"
int *__errno_location(void)
{
return &__pthread_self()->errno_val;
}
weak_alias(__errno_location, ___errno_location);

View File

@ -1,8 +0,0 @@
#include <stdlib.h>
#include "syscall.h"
_Noreturn void _Exit(int ec)
{
__syscall(SYS_exit_group, ec);
for (;;) __syscall(SYS_exit, ec);
}

View File

@ -1,30 +0,0 @@
#include <stdlib.h>
#include <signal.h>
#include "syscall.h"
#include "pthread_impl.h"
#include "atomic.h"
#include "lock.h"
#include "ksigaction.h"
_Noreturn void abort(void)
{
raise(SIGABRT);
/* If there was a SIGABRT handler installed and it returned, or if
* SIGABRT was blocked or ignored, take an AS-safe lock to prevent
* sigaction from installing a new SIGABRT handler, uninstall any
* handler that may be present, and re-raise the signal to generate
* the default action of abnormal termination. */
__block_all_sigs(0);
LOCK(__abort_lock);
__syscall(SYS_rt_sigaction, SIGABRT,
&(struct k_sigaction){.handler = SIG_DFL}, 0, _NSIG/8);
__syscall(SYS_tkill, __pthread_self()->tid, SIGABRT);
__syscall(SYS_rt_sigprocmask, SIG_UNBLOCK,
&(long[_NSIG/(8*sizeof(long))]){1UL<<(SIGABRT-1)}, 0, _NSIG/8);
/* Beyond this point should be unreachable. */
a_crash();
raise(SIGKILL);
_Exit(127);
}

View File

@ -1,3 +0,0 @@
#include "pthread_impl.h"
volatile int __abort_lock[1];

View File

@ -1,6 +0,0 @@
int __cxa_atexit(void (*func)(void *), void *arg, void *dso);
int __aeabi_atexit (void *obj, void (*func) (void *), void *d)
{
return __cxa_atexit (func, obj, d);
}

View File

@ -1,48 +0,0 @@
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
#include "syscall.h"
int fcntl(int fd, int cmd, ...)
{
unsigned long arg;
va_list ap;
va_start(ap, cmd);
arg = va_arg(ap, unsigned long);
va_end(ap);
if (cmd == F_SETFL) arg |= O_LARGEFILE;
if (cmd == F_SETLKW) return syscall_cp(SYS_fcntl, fd, cmd, (void *)arg);
if (cmd == F_GETOWN) {
struct f_owner_ex ex;
int ret = __syscall(SYS_fcntl, fd, F_GETOWN_EX, &ex);
if (ret == -EINVAL) return __syscall(SYS_fcntl, fd, cmd, (void *)arg);
if (ret) return __syscall_ret(ret);
return ex.type == F_OWNER_PGRP ? -ex.pid : ex.pid;
}
if (cmd == F_DUPFD_CLOEXEC) {
int ret = __syscall(SYS_fcntl, fd, F_DUPFD_CLOEXEC, arg);
if (ret != -EINVAL) {
if (ret >= 0)
__syscall(SYS_fcntl, ret, F_SETFD, FD_CLOEXEC);
return __syscall_ret(ret);
}
ret = __syscall(SYS_fcntl, fd, F_DUPFD_CLOEXEC, 0);
if (ret != -EINVAL) {
if (ret >= 0) __syscall(SYS_close, ret);
return __syscall_ret(-EINVAL);
}
ret = __syscall(SYS_fcntl, fd, F_DUPFD, arg);
if (ret >= 0) __syscall(SYS_fcntl, ret, F_SETFD, FD_CLOEXEC);
return __syscall_ret(ret);
}
switch (cmd) {
case F_SETLK:
case F_GETLK:
case F_GETOWN_EX:
case F_SETOWN_EX:
return syscall(SYS_fcntl, fd, cmd, (void *)arg);
default:
return syscall(SYS_fcntl, fd, cmd, arg);
}
}

View File

@ -1,23 +0,0 @@
#include <fcntl.h>
#include <stdarg.h>
#include "syscall.h"
int open(const char *filename, int flags, ...)
{
mode_t mode = 0;
if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) {
va_list ap;
va_start(ap, flags);
mode = va_arg(ap, mode_t);
va_end(ap);
}
int fd = __sys_open_cp(filename, flags, mode);
if (fd>=0 && (flags & O_CLOEXEC))
__syscall(SYS_fcntl, fd, F_SETFD, FD_CLOEXEC);
return __syscall_ret(fd);
}
weak_alias(open, open64);

View File

@ -1,19 +0,0 @@
#include <fcntl.h>
#include <stdarg.h>
#include "syscall.h"
int openat(int fd, const char *filename, int flags, ...)
{
mode_t mode = 0;
if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) {
va_list ap;
va_start(ap, flags);
mode = va_arg(ap, mode_t);
va_end(ap);
}
return syscall_cp(SYS_openat, fd, filename, flags|O_LARGEFILE, mode);
}
weak_alias(openat, openat64);

View File

@ -1,18 +0,0 @@
#include <fcntl.h>
#include "syscall.h"
int posix_fadvise(int fd, off_t base, off_t len, int advice)
{
#if defined(SYSCALL_FADVISE_6_ARG)
/* Some archs, at least arm and powerpc, have the syscall
* arguments reordered to avoid needing 7 argument registers
* due to 64-bit argument alignment. */
return -__syscall(SYS_fadvise, fd, advice,
__SYSCALL_LL_E(base), __SYSCALL_LL_E(len));
#else
return -__syscall(SYS_fadvise, fd, __SYSCALL_LL_O(base),
__SYSCALL_LL_E(len), advice);
#endif
}
weak_alias(posix_fadvise, posix_fadvise64);

View File

@ -1,10 +0,0 @@
#include <fcntl.h>
#include "syscall.h"
int posix_fallocate(int fd, off_t base, off_t len)
{
return -__syscall(SYS_fallocate, fd, 0, __SYSCALL_LL_E(base),
__SYSCALL_LL_E(len));
}
weak_alias(posix_fallocate, posix_fallocate64);

View File

@ -1,19 +0,0 @@
#include <float.h>
#include <fenv.h>
int __flt_rounds()
{
switch (fegetround()) {
#ifdef FE_TOWARDZERO
case FE_TOWARDZERO: return 0;
#endif
case FE_TONEAREST: return 1;
#ifdef FE_UPWARD
case FE_UPWARD: return 2;
#endif
#ifdef FE_DOWNWARD
case FE_DOWNWARD: return 3;
#endif
}
return -1;
}

View File

@ -1,68 +0,0 @@
.global fegetround
.type fegetround,%function
fegetround:
mrs x0, fpcr
and w0, w0, #0xc00000
ret
.global __fesetround
.hidden __fesetround
.type __fesetround,%function
__fesetround:
mrs x1, fpcr
bic w1, w1, #0xc00000
orr w1, w1, w0
msr fpcr, x1
mov w0, #0
ret
.global fetestexcept
.type fetestexcept,%function
fetestexcept:
and w0, w0, #0x1f
mrs x1, fpsr
and w0, w0, w1
ret
.global feclearexcept
.type feclearexcept,%function
feclearexcept:
and w0, w0, #0x1f
mrs x1, fpsr
bic w1, w1, w0
msr fpsr, x1
mov w0, #0
ret
.global feraiseexcept
.type feraiseexcept,%function
feraiseexcept:
and w0, w0, #0x1f
mrs x1, fpsr
orr w1, w1, w0
msr fpsr, x1
mov w0, #0
ret
.global fegetenv
.type fegetenv,%function
fegetenv:
mrs x1, fpcr
mrs x2, fpsr
stp w1, w2, [x0]
mov w0, #0
ret
// TODO preserve some bits
.global fesetenv
.type fesetenv,%function
fesetenv:
mov x1, #0
mov x2, #0
cmn x0, #1
b.eq 1f
ldp w1, w2, [x0]
1: msr fpcr, x1
msr fpsr, x2
mov w0, #0
ret

View File

@ -1,3 +0,0 @@
#if !__ARM_PCS_VFP
#include "../fenv.c"
#endif

View File

@ -1,164 +0,0 @@
.hidden __hwcap
.global feclearexcept
.type feclearexcept,@function
feclearexcept:
mov 4(%esp),%ecx
and $0x3f,%ecx
fnstsw %ax
# consider sse fenv as well if the cpu has XMM capability
call 1f
1: addl $__hwcap-1b,(%esp)
pop %edx
testl $0x02000000,(%edx)
jz 2f
# maintain exceptions in the sse mxcsr, clear x87 exceptions
test %eax,%ecx
jz 1f
fnclex
1: push %edx
stmxcsr (%esp)
pop %edx
and $0x3f,%eax
or %eax,%edx
test %edx,%ecx
jz 1f
not %ecx
and %ecx,%edx
push %edx
ldmxcsr (%esp)
pop %edx
1: xor %eax,%eax
ret
# only do the expensive x87 fenv load/store when needed
2: test %eax,%ecx
jz 1b
not %ecx
and %ecx,%eax
test $0x3f,%eax
jz 1f
fnclex
jmp 1b
1: sub $32,%esp
fnstenv (%esp)
mov %al,4(%esp)
fldenv (%esp)
add $32,%esp
xor %eax,%eax
ret
.global feraiseexcept
.type feraiseexcept,@function
feraiseexcept:
mov 4(%esp),%eax
and $0x3f,%eax
sub $32,%esp
fnstenv (%esp)
or %al,4(%esp)
fldenv (%esp)
add $32,%esp
xor %eax,%eax
ret
.global __fesetround
.hidden __fesetround
.type __fesetround,@function
__fesetround:
mov 4(%esp),%ecx
push %eax
xor %eax,%eax
fnstcw (%esp)
andb $0xf3,1(%esp)
or %ch,1(%esp)
fldcw (%esp)
# consider sse fenv as well if the cpu has XMM capability
call 1f
1: addl $__hwcap-1b,(%esp)
pop %edx
testl $0x02000000,(%edx)
jz 1f
stmxcsr (%esp)
shl $3,%ch
andb $0x9f,1(%esp)
or %ch,1(%esp)
ldmxcsr (%esp)
1: pop %ecx
ret
.global fegetround
.type fegetround,@function
fegetround:
push %eax
fnstcw (%esp)
pop %eax
and $0xc00,%eax
ret
.global fegetenv
.type fegetenv,@function
fegetenv:
mov 4(%esp),%ecx
xor %eax,%eax
fnstenv (%ecx)
# consider sse fenv as well if the cpu has XMM capability
call 1f
1: addl $__hwcap-1b,(%esp)
pop %edx
testl $0x02000000,(%edx)
jz 1f
push %eax
stmxcsr (%esp)
pop %edx
and $0x3f,%edx
or %edx,4(%ecx)
1: ret
.global fesetenv
.type fesetenv,@function
fesetenv:
mov 4(%esp),%ecx
xor %eax,%eax
inc %ecx
jz 1f
fldenv -1(%ecx)
movl -1(%ecx),%ecx
jmp 2f
1: push %eax
push %eax
push %eax
push %eax
pushl $0xffff
push %eax
pushl $0x37f
fldenv (%esp)
add $28,%esp
# consider sse fenv as well if the cpu has XMM capability
2: call 1f
1: addl $__hwcap-1b,(%esp)
pop %edx
testl $0x02000000,(%edx)
jz 1f
# mxcsr := same rounding mode, cleared exceptions, default mask
and $0xc00,%ecx
shl $3,%ecx
or $0x1f80,%ecx
mov %ecx,4(%esp)
ldmxcsr 4(%esp)
1: ret
.global fetestexcept
.type fetestexcept,@function
fetestexcept:
mov 4(%esp),%ecx
and $0x3f,%ecx
fnstsw %ax
# consider sse fenv as well if the cpu has XMM capability
call 1f
1: addl $__hwcap-1b,(%esp)
pop %edx
testl $0x02000000,(%edx)
jz 1f
stmxcsr 4(%esp)
or 4(%esp),%eax
1: and %ecx,%eax
ret

View File

@ -1,85 +0,0 @@
#include <fenv.h>
#include <features.h>
#if __HAVE_68881__ || __mcffpu__
static unsigned getsr()
{
unsigned v;
__asm__ __volatile__ ("fmove.l %%fpsr,%0" : "=dm"(v));
return v;
}
static void setsr(unsigned v)
{
__asm__ __volatile__ ("fmove.l %0,%%fpsr" : : "dm"(v));
}
static unsigned getcr()
{
unsigned v;
__asm__ __volatile__ ("fmove.l %%fpcr,%0" : "=dm"(v));
return v;
}
static void setcr(unsigned v)
{
__asm__ __volatile__ ("fmove.l %0,%%fpcr" : : "dm"(v));
}
int feclearexcept(int mask)
{
if (mask & ~FE_ALL_EXCEPT) return -1;
setsr(getsr() & ~mask);
return 0;
}
int feraiseexcept(int mask)
{
if (mask & ~FE_ALL_EXCEPT) return -1;
setsr(getsr() | mask);
return 0;
}
int fetestexcept(int mask)
{
return getsr() & mask;
}
int fegetround(void)
{
return getcr() & FE_UPWARD;
}
hidden int __fesetround(int r)
{
setcr((getcr() & ~FE_UPWARD) | r);
return 0;
}
int fegetenv(fenv_t *envp)
{
envp->__control_register = getcr();
envp->__status_register = getsr();
__asm__ __volatile__ ("fmove.l %%fpiar,%0"
: "=dm"(envp->__instruction_address));
return 0;
}
int fesetenv(const fenv_t *envp)
{
static const fenv_t default_env = { 0 };
if (envp == FE_DFL_ENV)
envp = &default_env;
setcr(envp->__control_register);
setsr(envp->__status_register);
__asm__ __volatile__ ("fmove.l %0,%%fpiar"
: : "dm"(envp->__instruction_address));
return 0;
}
#else
#include "../fenv.c"
#endif

View File

@ -1,3 +0,0 @@
#ifdef __mips_soft_float
#include "../fenv.c"
#endif

View File

@ -1,3 +0,0 @@
#ifdef __mips_soft_float
#include "../fenv.c"
#endif

View File

@ -1,3 +0,0 @@
#ifdef __mips_soft_float
#include "../fenv.c"
#endif

View File

@ -1,3 +0,0 @@
#if defined(_SOFT_FLOAT) || defined(__NO_FPRS__)
#include "../fenv.c"
#endif

View File

@ -1,69 +0,0 @@
#define _GNU_SOURCE
#include <fenv.h>
#include <features.h>
static inline double get_fpscr_f(void)
{
double d;
__asm__ __volatile__("mffs %0" : "=d"(d));
return d;
}
static inline long get_fpscr(void)
{
return (union {double f; long i;}) {get_fpscr_f()}.i;
}
static inline void set_fpscr_f(double fpscr)
{
__asm__ __volatile__("mtfsf 255, %0" : : "d"(fpscr));
}
static void set_fpscr(long fpscr)
{
set_fpscr_f((union {long i; double f;}) {fpscr}.f);
}
int feclearexcept(int mask)
{
mask &= FE_ALL_EXCEPT;
if (mask & FE_INVALID) mask |= FE_ALL_INVALID;
set_fpscr(get_fpscr() & ~mask);
return 0;
}
int feraiseexcept(int mask)
{
mask &= FE_ALL_EXCEPT;
if (mask & FE_INVALID) mask |= FE_INVALID_SOFTWARE;
set_fpscr(get_fpscr() | mask);
return 0;
}
int fetestexcept(int mask)
{
return get_fpscr() & mask & FE_ALL_EXCEPT;
}
int fegetround(void)
{
return get_fpscr() & 3;
}
hidden int __fesetround(int r)
{
set_fpscr(get_fpscr() & ~3L | r);
return 0;
}
int fegetenv(fenv_t *envp)
{
*envp = get_fpscr_f();
return 0;
}
int fesetenv(const fenv_t *envp)
{
set_fpscr_f(envp != FE_DFL_ENV ? *envp : 0);
return 0;
}

View File

@ -1,3 +0,0 @@
#ifndef __riscv_flen
#include "../fenv.c"
#endif

View File

@ -1,56 +0,0 @@
#include <fenv.h>
#include <features.h>
static inline unsigned get_fpc(void)
{
unsigned fpc;
__asm__ __volatile__("efpc %0" : "=r"(fpc));
return fpc;
}
static inline void set_fpc(unsigned fpc)
{
__asm__ __volatile__("sfpc %0" :: "r"(fpc));
}
int feclearexcept(int mask)
{
mask &= FE_ALL_EXCEPT;
set_fpc(get_fpc() & ~mask);
return 0;
}
int feraiseexcept(int mask)
{
mask &= FE_ALL_EXCEPT;
set_fpc(get_fpc() | mask);
return 0;
}
int fetestexcept(int mask)
{
return get_fpc() & mask & FE_ALL_EXCEPT;
}
int fegetround(void)
{
return get_fpc() & 3;
}
hidden int __fesetround(int r)
{
set_fpc(get_fpc() & ~3L | r);
return 0;
}
int fegetenv(fenv_t *envp)
{
*envp = get_fpc();
return 0;
}
int fesetenv(const fenv_t *envp)
{
set_fpc(envp != FE_DFL_ENV ? *envp : 0);
return 0;
}

View File

@ -1,3 +0,0 @@
#if !__SH_FPU_ANY__ && !__SH4__
#include "../fenv.c"
#endif

View File

@ -1,98 +0,0 @@
.global feclearexcept
.type feclearexcept,@function
feclearexcept:
# maintain exceptions in the sse mxcsr, clear x87 exceptions
mov %edi,%ecx
and $0x3f,%ecx
fnstsw %ax
test %eax,%ecx
jz 1f
fnclex
1: stmxcsr -8(%esp)
and $0x3f,%eax
or %eax,-8(%esp)
test %ecx,-8(%esp)
jz 1f
not %ecx
and %ecx,-8(%esp)
ldmxcsr -8(%esp)
1: xor %eax,%eax
ret
.global feraiseexcept
.type feraiseexcept,@function
feraiseexcept:
and $0x3f,%edi
stmxcsr -8(%esp)
or %edi,-8(%esp)
ldmxcsr -8(%esp)
xor %eax,%eax
ret
.global __fesetround
.hidden __fesetround
.type __fesetround,@function
__fesetround:
push %rax
xor %eax,%eax
mov %edi,%ecx
fnstcw (%esp)
andb $0xf3,1(%esp)
or %ch,1(%esp)
fldcw (%esp)
stmxcsr (%esp)
shl $3,%ch
andb $0x9f,1(%esp)
or %ch,1(%esp)
ldmxcsr (%esp)
pop %rcx
ret
.global fegetround
.type fegetround,@function
fegetround:
push %rax
stmxcsr (%esp)
pop %rax
shr $3,%eax
and $0xc00,%eax
ret
.global fegetenv
.type fegetenv,@function
fegetenv:
xor %eax,%eax
fnstenv (%edi)
stmxcsr 28(%edi)
ret
.global fesetenv
.type fesetenv,@function
fesetenv:
xor %eax,%eax
inc %edi
jz 1f
fldenv -1(%edi)
ldmxcsr 27(%edi)
ret
1: push %rax
push %rax
pushq $0xffff
pushq $0x37f
fldenv (%esp)
pushq $0x1f80
ldmxcsr (%esp)
add $40,%esp
ret
.global fetestexcept
.type fetestexcept,@function
fetestexcept:
and $0x3f,%edi
push %rax
stmxcsr (%esp)
pop %rsi
fnstsw %ax
or %esi,%eax
and %edi,%eax
ret

View File

@ -1,98 +0,0 @@
.global feclearexcept
.type feclearexcept,@function
feclearexcept:
# maintain exceptions in the sse mxcsr, clear x87 exceptions
mov %edi,%ecx
and $0x3f,%ecx
fnstsw %ax
test %eax,%ecx
jz 1f
fnclex
1: stmxcsr -8(%rsp)
and $0x3f,%eax
or %eax,-8(%rsp)
test %ecx,-8(%rsp)
jz 1f
not %ecx
and %ecx,-8(%rsp)
ldmxcsr -8(%rsp)
1: xor %eax,%eax
ret
.global feraiseexcept
.type feraiseexcept,@function
feraiseexcept:
and $0x3f,%edi
stmxcsr -8(%rsp)
or %edi,-8(%rsp)
ldmxcsr -8(%rsp)
xor %eax,%eax
ret
.global __fesetround
.hidden __fesetround
.type __fesetround,@function
__fesetround:
push %rax
xor %eax,%eax
mov %edi,%ecx
fnstcw (%rsp)
andb $0xf3,1(%rsp)
or %ch,1(%rsp)
fldcw (%rsp)
stmxcsr (%rsp)
shl $3,%ch
andb $0x9f,1(%rsp)
or %ch,1(%rsp)
ldmxcsr (%rsp)
pop %rcx
ret
.global fegetround
.type fegetround,@function
fegetround:
push %rax
stmxcsr (%rsp)
pop %rax
shr $3,%eax
and $0xc00,%eax
ret
.global fegetenv
.type fegetenv,@function
fegetenv:
xor %eax,%eax
fnstenv (%rdi)
stmxcsr 28(%rdi)
ret
.global fesetenv
.type fesetenv,@function
fesetenv:
xor %eax,%eax
inc %rdi
jz 1f
fldenv -1(%rdi)
ldmxcsr 27(%rdi)
ret
1: push %rax
push %rax
pushq $0xffff
pushq $0x37f
fldenv (%rsp)
pushq $0x1f80
ldmxcsr (%rsp)
add $40,%rsp
ret
.global fetestexcept
.type fetestexcept,@function
fetestexcept:
and $0x3f,%edi
push %rax
stmxcsr (%rsp)
pop %rsi
fnstsw %ax
or %esi,%eax
and %edi,%eax
ret

View File

@ -1,9 +0,0 @@
1: int $128
ret
.data
.align 4
.hidden __sysinfo
.global __sysinfo
__sysinfo:
.long 1b

View File

@ -1,15 +0,0 @@
#include "syscall.h"
void __procfdname(char *buf, unsigned fd)
{
unsigned i, j;
for (i=0; (buf[i] = "/proc/self/fd/"[i]); i++);
if (!fd) {
buf[i] = '0';
buf[i+1] = 0;
return;
}
for (j=fd; j; j/=10, i++);
buf[i] = 0;
for (; fd; fd/=10) buf[--i] = '0' + fd%10;
}

View File

@ -1,6 +0,0 @@
#include <features.h>
hidden int __shcall(void *arg, int (*func)(void *))
{
return func(arg);
}

View File

@ -1,11 +0,0 @@
#include <errno.h>
#include "syscall.h"
long __syscall_ret(unsigned long r)
{
if (r > -4096UL) {
errno = -r;
return -1;
}
return r;
}

View File

@ -1,93 +0,0 @@
#include <elf.h>
#include <link.h>
#include <limits.h>
#include <stdint.h>
#include <string.h>
#include "libc.h"
#include "syscall.h"
#ifdef VDSO_USEFUL
#if ULONG_MAX == 0xffffffff
typedef Elf32_Ehdr Ehdr;
typedef Elf32_Phdr Phdr;
typedef Elf32_Sym Sym;
typedef Elf32_Verdef Verdef;
typedef Elf32_Verdaux Verdaux;
#else
typedef Elf64_Ehdr Ehdr;
typedef Elf64_Phdr Phdr;
typedef Elf64_Sym Sym;
typedef Elf64_Verdef Verdef;
typedef Elf64_Verdaux Verdaux;
#endif
static int checkver(Verdef *def, int vsym, const char *vername, char *strings)
{
vsym &= 0x7fff;
for (;;) {
if (!(def->vd_flags & VER_FLG_BASE)
&& (def->vd_ndx & 0x7fff) == vsym)
break;
if (def->vd_next == 0)
return 0;
def = (Verdef *)((char *)def + def->vd_next);
}
Verdaux *aux = (Verdaux *)((char *)def + def->vd_aux);
return !strcmp(vername, strings + aux->vda_name);
}
#define OK_TYPES (1<<STT_NOTYPE | 1<<STT_OBJECT | 1<<STT_FUNC | 1<<STT_COMMON)
#define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK | 1<<STB_GNU_UNIQUE)
void *__vdsosym(const char *vername, const char *name)
{
size_t i;
for (i=0; libc.auxv[i] != AT_SYSINFO_EHDR; i+=2)
if (!libc.auxv[i]) return 0;
if (!libc.auxv[i+1]) return 0;
Ehdr *eh = (void *)libc.auxv[i+1];
Phdr *ph = (void *)((char *)eh + eh->e_phoff);
size_t *dynv=0, base=-1;
for (i=0; i<eh->e_phnum; i++, ph=(void *)((char *)ph+eh->e_phentsize)) {
if (ph->p_type == PT_LOAD)
base = (size_t)eh + ph->p_offset - ph->p_vaddr;
else if (ph->p_type == PT_DYNAMIC)
dynv = (void *)((char *)eh + ph->p_offset);
}
if (!dynv || base==(size_t)-1) return 0;
char *strings = 0;
Sym *syms = 0;
Elf_Symndx *hashtab = 0;
uint16_t *versym = 0;
Verdef *verdef = 0;
for (i=0; dynv[i]; i+=2) {
void *p = (void *)(base + dynv[i+1]);
switch(dynv[i]) {
case DT_STRTAB: strings = p; break;
case DT_SYMTAB: syms = p; break;
case DT_HASH: hashtab = p; break;
case DT_VERSYM: versym = p; break;
case DT_VERDEF: verdef = p; break;
}
}
if (!strings || !syms || !hashtab) return 0;
if (!verdef) versym = 0;
for (i=0; i<hashtab[1]; i++) {
if (!(1<<(syms[i].st_info&0xf) & OK_TYPES)) continue;
if (!(1<<(syms[i].st_info>>4) & OK_BINDS)) continue;
if (!syms[i].st_shndx) continue;
if (strcmp(name, strings+syms[i].st_name)) continue;
if (versym && !checkver(verdef, versym[i], vername, strings))
continue;
return (void *)(base + syms[i].st_value);
}
return 0;
}
#endif

View File

@ -1,4 +0,0 @@
#include "version.h"
#include "libc.h"
const char __libc_version[] = VERSION;

View File

@ -1,10 +0,0 @@
#include <sys/ipc.h>
#include <sys/stat.h>
key_t ftok(const char *path, int id)
{
struct stat st;
if (stat(path, &st) < 0) return -1;
return ((st.st_ino & 0xffff) | ((st.st_dev & 0xff) << 16) | ((id & 0xffu) << 24));
}

View File

@ -1,51 +0,0 @@
#include <sys/msg.h>
#include <endian.h>
#include "syscall.h"
#include "ipc.h"
#if __BYTE_ORDER != __BIG_ENDIAN
#undef SYSCALL_IPC_BROKEN_MODE
#endif
int msgctl(int q, int cmd, struct msqid_ds *buf)
{
#if IPC_TIME64
struct msqid_ds out, *orig;
if (cmd&IPC_TIME64) {
out = (struct msqid_ds){0};
orig = buf;
buf = &out;
}
#endif
#ifdef SYSCALL_IPC_BROKEN_MODE
struct msqid_ds tmp;
if (cmd == IPC_SET) {
tmp = *buf;
tmp.msg_perm.mode *= 0x10000U;
buf = &tmp;
}
#endif
#ifndef SYS_ipc
int r = __syscall(SYS_msgctl, q, IPC_CMD(cmd), buf);
#else
int r = __syscall(SYS_ipc, IPCOP_msgctl, q, IPC_CMD(cmd), 0, buf, 0);
#endif
#ifdef SYSCALL_IPC_BROKEN_MODE
if (r >= 0) switch (cmd | IPC_TIME64) {
case IPC_STAT:
case MSG_STAT:
case MSG_STAT_ANY:
buf->msg_perm.mode >>= 16;
}
#endif
#if IPC_TIME64
if (r >= 0 && (cmd&IPC_TIME64)) {
buf = orig;
*buf = out;
IPC_HILO(buf, msg_stime);
IPC_HILO(buf, msg_rtime);
IPC_HILO(buf, msg_ctime);
}
#endif
return __syscall_ret(r);
}

View File

@ -1,12 +0,0 @@
#include <sys/msg.h>
#include "syscall.h"
#include "ipc.h"
int msgget(key_t k, int flag)
{
#ifndef SYS_ipc
return syscall(SYS_msgget, k, flag);
#else
return syscall(SYS_ipc, IPCOP_msgget, k, flag);
#endif
}

View File

@ -1,12 +0,0 @@
#include <sys/msg.h>
#include "syscall.h"
#include "ipc.h"
ssize_t msgrcv(int q, void *m, size_t len, long type, int flag)
{
#ifndef SYS_ipc
return syscall_cp(SYS_msgrcv, q, m, len, type, flag);
#else
return syscall_cp(SYS_ipc, IPCOP_msgrcv, q, len, flag, ((long[]){ (long)m, type }));
#endif
}

View File

@ -1,12 +0,0 @@
#include <sys/msg.h>
#include "syscall.h"
#include "ipc.h"
int msgsnd(int q, const void *m, size_t len, int flag)
{
#ifndef SYS_ipc
return syscall_cp(SYS_msgsnd, q, m, len, flag);
#else
return syscall_cp(SYS_ipc, IPCOP_msgsnd, q, len, flag, m);
#endif
}

View File

@ -1,69 +0,0 @@
#include <sys/sem.h>
#include <stdarg.h>
#include <endian.h>
#include "syscall.h"
#include "ipc.h"
#if __BYTE_ORDER != __BIG_ENDIAN
#undef SYSCALL_IPC_BROKEN_MODE
#endif
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
int semctl(int id, int num, int cmd, ...)
{
union semun arg = {0};
va_list ap;
switch (cmd & ~IPC_TIME64) {
case SETVAL: case GETALL: case SETALL: case IPC_SET:
case IPC_INFO: case SEM_INFO:
case IPC_STAT & ~IPC_TIME64:
case SEM_STAT & ~IPC_TIME64:
case SEM_STAT_ANY & ~IPC_TIME64:
va_start(ap, cmd);
arg = va_arg(ap, union semun);
va_end(ap);
}
#if IPC_TIME64
struct semid_ds out, *orig;
if (cmd&IPC_TIME64) {
out = (struct semid_ds){0};
orig = arg.buf;
arg.buf = &out;
}
#endif
#ifdef SYSCALL_IPC_BROKEN_MODE
struct semid_ds tmp;
if (cmd == IPC_SET) {
tmp = *arg.buf;
tmp.sem_perm.mode *= 0x10000U;
arg.buf = &tmp;
}
#endif
#ifndef SYS_ipc
int r = __syscall(SYS_semctl, id, num, IPC_CMD(cmd), arg.buf);
#else
int r = __syscall(SYS_ipc, IPCOP_semctl, id, num, IPC_CMD(cmd), &arg.buf);
#endif
#ifdef SYSCALL_IPC_BROKEN_MODE
if (r >= 0) switch (cmd | IPC_TIME64) {
case IPC_STAT:
case SEM_STAT:
case SEM_STAT_ANY:
arg.buf->sem_perm.mode >>= 16;
}
#endif
#if IPC_TIME64
if (r >= 0 && (cmd&IPC_TIME64)) {
arg.buf = orig;
*arg.buf = out;
IPC_HILO(arg.buf, sem_otime);
IPC_HILO(arg.buf, sem_ctime);
}
#endif
return __syscall_ret(r);
}

View File

@ -1,19 +0,0 @@
#include <sys/sem.h>
#include <limits.h>
#include <errno.h>
#include "syscall.h"
#include "ipc.h"
int semget(key_t key, int n, int fl)
{
/* The kernel uses the wrong type for the sem_nsems member
* of struct semid_ds, and thus might not check that the
* n fits in the correct (per POSIX) userspace type, so
* we have to check here. */
if (n > USHRT_MAX) return __syscall_ret(-EINVAL);
#ifndef SYS_ipc
return syscall(SYS_semget, key, n, fl);
#else
return syscall(SYS_ipc, IPCOP_semget, key, n, fl);
#endif
}

View File

@ -1,12 +0,0 @@
#include <sys/sem.h>
#include "syscall.h"
#include "ipc.h"
int semop(int id, struct sembuf *buf, size_t n)
{
#ifndef SYS_ipc
return syscall(SYS_semop, id, buf, n);
#else
return syscall(SYS_ipc, IPCOP_semop, id, n, 0, buf);
#endif
}

View File

@ -1,35 +0,0 @@
#define _GNU_SOURCE
#include <sys/sem.h>
#include <errno.h>
#include "syscall.h"
#include "ipc.h"
#define IS32BIT(x) !((x)+0x80000000ULL>>32)
#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
#if !defined(SYS_semtimedop) && !defined(SYS_ipc)
#define NO_TIME32 1
#else
#define NO_TIME32 0
#endif
int semtimedop(int id, struct sembuf *buf, size_t n, const struct timespec *ts)
{
#ifdef SYS_semtimedop_time64
time_t s = ts ? ts->tv_sec : 0;
long ns = ts ? ts->tv_nsec : 0;
int r = -ENOSYS;
if (NO_TIME32 || !IS32BIT(s))
r = __syscall(SYS_semtimedop_time64, id, buf, n,
ts ? ((long long[]){s, ns}) : 0);
if (NO_TIME32 || r!=-ENOSYS) return __syscall_ret(r);
ts = ts ? (void *)(long[]){CLAMP(s), ns} : 0;
#endif
#if defined(SYS_ipc)
return syscall(SYS_ipc, IPCOP_semtimedop, id, n, 0, buf, ts);
#elif defined(SYS_semtimedop)
return syscall(SYS_semtimedop, id, buf, n, ts);
#else
return __syscall_ret(-ENOSYS);
#endif
}

View File

@ -1,17 +0,0 @@
#include <sys/shm.h>
#include "syscall.h"
#include "ipc.h"
#ifndef SYS_ipc
void *shmat(int id, const void *addr, int flag)
{
return (void *)syscall(SYS_shmat, id, addr, flag);
}
#else
void *shmat(int id, const void *addr, int flag)
{
unsigned long ret;
ret = syscall(SYS_ipc, IPCOP_shmat, id, flag, &addr, addr);
return (ret > -(unsigned long)SHMLBA) ? (void *)ret : (void *)addr;
}
#endif

View File

@ -1,51 +0,0 @@
#include <sys/shm.h>
#include <endian.h>
#include "syscall.h"
#include "ipc.h"
#if __BYTE_ORDER != __BIG_ENDIAN
#undef SYSCALL_IPC_BROKEN_MODE
#endif
int shmctl(int id, int cmd, struct shmid_ds *buf)
{
#if IPC_TIME64
struct shmid_ds out, *orig;
if (cmd&IPC_TIME64) {
out = (struct shmid_ds){0};
orig = buf;
buf = &out;
}
#endif
#ifdef SYSCALL_IPC_BROKEN_MODE
struct shmid_ds tmp;
if (cmd == IPC_SET) {
tmp = *buf;
tmp.shm_perm.mode *= 0x10000U;
buf = &tmp;
}
#endif
#ifndef SYS_ipc
int r = __syscall(SYS_shmctl, id, IPC_CMD(cmd), buf);
#else
int r = __syscall(SYS_ipc, IPCOP_shmctl, id, IPC_CMD(cmd), 0, buf, 0);
#endif
#ifdef SYSCALL_IPC_BROKEN_MODE
if (r >= 0) switch (cmd | IPC_TIME64) {
case IPC_STAT:
case SHM_STAT:
case SHM_STAT_ANY:
buf->shm_perm.mode >>= 16;
}
#endif
#if IPC_TIME64
if (r >= 0 && (cmd&IPC_TIME64)) {
buf = orig;
*buf = out;
IPC_HILO(buf, shm_atime);
IPC_HILO(buf, shm_dtime);
IPC_HILO(buf, shm_ctime);
}
#endif
return __syscall_ret(r);
}

View File

@ -1,12 +0,0 @@
#include <sys/shm.h>
#include "syscall.h"
#include "ipc.h"
int shmdt(const void *addr)
{
#ifndef SYS_ipc
return syscall(SYS_shmdt, addr);
#else
return syscall(SYS_ipc, IPCOP_shmdt, 0, 0, 0, addr);
#endif
}

View File

@ -1,14 +0,0 @@
#include <sys/shm.h>
#include <stdint.h>
#include "syscall.h"
#include "ipc.h"
int shmget(key_t key, size_t size, int flag)
{
if (size > PTRDIFF_MAX) size = SIZE_MAX;
#ifndef SYS_ipc
return syscall(SYS_shmget, key, size, flag);
#else
return syscall(SYS_ipc, IPCOP_shmget, key, size, flag);
#endif
}

View File

@ -1,14 +0,0 @@
#include <dlfcn.h>
#include "dynlink.h"
static void *stub_dlsym(void *restrict p, const char *restrict s, void *restrict ra)
{
__dl_seterr("Symbol not found: %s", s);
return 0;
}
weak_alias(stub_dlsym, __dlsym);
#if _REDIR_TIME64
weak_alias(stub_dlsym, __dlsym_redir_time64);
#endif

View File

@ -1,6 +0,0 @@
.global dlsym
.hidden __dlsym
.type dlsym,%function
dlsym:
mov x2,x30
b __dlsym

View File

@ -1,31 +0,0 @@
// size_t __tlsdesc_static(size_t *a)
// {
// return a[1];
// }
.global __tlsdesc_static
.hidden __tlsdesc_static
.type __tlsdesc_static,@function
__tlsdesc_static:
ldr x0,[x0,#8]
ret
// size_t __tlsdesc_dynamic(size_t *a)
// {
// struct {size_t modidx,off;} *p = (void*)a[1];
// size_t *dtv = *(size_t**)(tp - 8);
// return dtv[p->modidx] + p->off - tp;
// }
.global __tlsdesc_dynamic
.hidden __tlsdesc_dynamic
.type __tlsdesc_dynamic,@function
__tlsdesc_dynamic:
stp x1,x2,[sp,#-16]!
mrs x1,tpidr_el0 // tp
ldr x0,[x0,#8] // p
ldp x0,x2,[x0] // p->modidx, p->off
sub x2,x2,x1 // p->off - tp
ldr x1,[x1,#-8] // dtv
ldr x1,[x1,x0,lsl #3] // dtv[p->modidx]
add x0,x1,x2 // dtv[p->modidx] + p->off - tp
ldp x1,x2,[sp],#16
ret

View File

@ -1,8 +0,0 @@
.syntax unified
.text
.global dlsym
.hidden __dlsym
.type dlsym,%function
dlsym:
mov r2,lr
b __dlsym

View File

@ -1,42 +0,0 @@
#define _GNU_SOURCE
#include <link.h>
#include <stdint.h>
struct find_exidx_data {
uintptr_t pc, exidx_start;
int exidx_len;
};
static int find_exidx(struct dl_phdr_info *info, size_t size, void *ptr)
{
struct find_exidx_data *data = ptr;
const ElfW(Phdr) *phdr = info->dlpi_phdr;
uintptr_t addr, exidx_start = 0;
int i, match = 0, exidx_len = 0;
for (i = info->dlpi_phnum; i > 0; i--, phdr++) {
addr = info->dlpi_addr + phdr->p_vaddr;
switch (phdr->p_type) {
case PT_LOAD:
match |= data->pc >= addr && data->pc < addr + phdr->p_memsz;
break;
case PT_ARM_EXIDX:
exidx_start = addr;
exidx_len = phdr->p_memsz;
break;
}
}
data->exidx_start = exidx_start;
data->exidx_len = exidx_len;
return match;
}
uintptr_t __gnu_Unwind_Find_exidx(uintptr_t pc, int *pcount)
{
struct find_exidx_data data;
data.pc = pc;
if (dl_iterate_phdr(find_exidx, &data) <= 0)
return 0;
*pcount = data.exidx_len / 8;
return data.exidx_start;
}

View File

@ -1,47 +0,0 @@
#include <elf.h>
#include <link.h>
#include "pthread_impl.h"
#include "libc.h"
#define AUX_CNT 38
extern weak hidden const size_t _DYNAMIC[];
static int static_dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void *data), void *data)
{
unsigned char *p;
ElfW(Phdr) *phdr, *tls_phdr=0;
size_t base = 0;
size_t n;
struct dl_phdr_info info;
size_t i, aux[AUX_CNT] = {0};
for (i=0; libc.auxv[i]; i+=2)
if (libc.auxv[i]<AUX_CNT) aux[libc.auxv[i]] = libc.auxv[i+1];
for (p=(void *)aux[AT_PHDR],n=aux[AT_PHNUM]; n; n--,p+=aux[AT_PHENT]) {
phdr = (void *)p;
if (phdr->p_type == PT_PHDR)
base = aux[AT_PHDR] - phdr->p_vaddr;
if (phdr->p_type == PT_DYNAMIC && _DYNAMIC)
base = (size_t)_DYNAMIC - phdr->p_vaddr;
if (phdr->p_type == PT_TLS)
tls_phdr = phdr;
}
info.dlpi_addr = base;
info.dlpi_name = "/proc/self/exe";
info.dlpi_phdr = (void *)aux[AT_PHDR];
info.dlpi_phnum = aux[AT_PHNUM];
info.dlpi_adds = 0;
info.dlpi_subs = 0;
if (tls_phdr) {
info.dlpi_tls_modid = 1;
info.dlpi_tls_data = __tls_get_addr((tls_mod_off_t[]){1,0});
} else {
info.dlpi_tls_modid = 0;
info.dlpi_tls_data = 0;
}
return (callback)(&info, sizeof (info), data);
}
weak_alias(static_dl_iterate_phdr, dl_iterate_phdr);

View File

@ -1,9 +0,0 @@
#define _GNU_SOURCE
#include <dlfcn.h>
static int stub_dladdr(const void *addr, Dl_info *info)
{
return 0;
}
weak_alias(stub_dladdr, dladdr);

View File

@ -1,7 +0,0 @@
#include <dlfcn.h>
#include "dynlink.h"
int dlclose(void *p)
{
return __dl_invalid_handle(p);
}

View File

@ -1,87 +0,0 @@
#include <dlfcn.h>
#include <stdlib.h>
#include <stdarg.h>
#include "pthread_impl.h"
#include "dynlink.h"
#include "lock.h"
#include "fork_impl.h"
#define malloc __libc_malloc
#define calloc __libc_calloc
#define realloc __libc_realloc
#define free __libc_free
char *dlerror()
{
pthread_t self = __pthread_self();
if (!self->dlerror_flag) return 0;
self->dlerror_flag = 0;
char *s = self->dlerror_buf;
if (s == (void *)-1)
return "Dynamic linker failed to allocate memory for error message";
else
return s;
}
static volatile int freebuf_queue_lock[1];
static void **freebuf_queue;
volatile int *const __dlerror_lockptr = freebuf_queue_lock;
void __dl_thread_cleanup(void)
{
pthread_t self = __pthread_self();
if (self->dlerror_buf && self->dlerror_buf != (void *)-1) {
LOCK(freebuf_queue_lock);
void **p = (void **)self->dlerror_buf;
*p = freebuf_queue;
freebuf_queue = p;
UNLOCK(freebuf_queue_lock);
}
}
hidden void __dl_vseterr(const char *fmt, va_list ap)
{
LOCK(freebuf_queue_lock);
void **q = freebuf_queue;
freebuf_queue = 0;
UNLOCK(freebuf_queue_lock);
while (q) {
void **p = *q;
free(q);
q = p;
}
va_list ap2;
va_copy(ap2, ap);
pthread_t self = __pthread_self();
if (self->dlerror_buf != (void *)-1)
free(self->dlerror_buf);
size_t len = vsnprintf(0, 0, fmt, ap2);
if (len < sizeof(void *)) len = sizeof(void *);
va_end(ap2);
char *buf = malloc(len+1);
if (buf) {
vsnprintf(buf, len+1, fmt, ap);
} else {
buf = (void *)-1;
}
self->dlerror_buf = buf;
self->dlerror_flag = 1;
}
hidden void __dl_seterr(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
__dl_vseterr(fmt, ap);
va_end(ap);
}
static int stub_invalid_handle(void *h)
{
__dl_seterr("Invalid library handle %p", (void *)h);
return 1;
}
weak_alias(stub_invalid_handle, __dl_invalid_handle);

View File

@ -1,14 +0,0 @@
#define _GNU_SOURCE
#include <dlfcn.h>
#include "dynlink.h"
int dlinfo(void *dso, int req, void *res)
{
if (__dl_invalid_handle(dso)) return -1;
if (req != RTLD_DI_LINKMAP) {
__dl_seterr("Unsupported request %d", req);
return -1;
}
*(struct link_map **)res = dso;
return 0;
}

View File

@ -1,10 +0,0 @@
#include <dlfcn.h>
#include "dynlink.h"
static void *stub_dlopen(const char *file, int mode)
{
__dl_seterr("Dynamic loading not supported");
return 0;
}
weak_alias(stub_dlopen, dlopen);

View File

@ -1,7 +0,0 @@
#include <dlfcn.h>
#include "dynlink.h"
void *dlsym(void *restrict p, const char *restrict s)
{
return __dlsym(p, s, 0);
}

View File

@ -1,11 +0,0 @@
.text
.global dlsym
.hidden __dlsym
.type dlsym,@function
dlsym:
push (%esp)
push 12(%esp)
push 12(%esp)
call __dlsym
add $12,%esp
ret

View File

@ -1,23 +0,0 @@
.text
.global __tlsdesc_static
.hidden __tlsdesc_static
.type __tlsdesc_static,@function
__tlsdesc_static:
mov 4(%eax),%eax
ret
.global __tlsdesc_dynamic
.hidden __tlsdesc_dynamic
.type __tlsdesc_dynamic,@function
__tlsdesc_dynamic:
mov 4(%eax),%eax
push %edx
mov %gs:4,%edx
push %ecx
mov (%eax),%ecx
mov 4(%eax),%eax
add (%edx,%ecx,4),%eax
pop %ecx
sub %gs:0,%eax
pop %edx
ret

View File

@ -1,12 +0,0 @@
.text
.global dlsym
.hidden __dlsym
.type dlsym,@function
dlsym:
move.l (%sp),-(%sp)
move.l 12(%sp),-(%sp)
move.l 12(%sp),-(%sp)
lea __dlsym-.-8,%a1
jsr (%pc,%a1)
add.l #12,%sp
rts

View File

@ -1,6 +0,0 @@
.global dlsym
.hidden __dlsym
.type dlsym,@function
dlsym:
brid __dlsym
add r7, r15, r0

View File

@ -1,17 +0,0 @@
.set noreorder
.global dlsym
.hidden __dlsym
.type dlsym,@function
dlsym:
lui $gp, %hi(_gp_disp)
addiu $gp, %lo(_gp_disp)
addu $gp, $gp, $25
move $6, $ra
lw $25, %call16(__dlsym)($gp)
addiu $sp, $sp, -16
sw $ra, 12($sp)
jalr $25
nop
lw $ra, 12($sp)
jr $ra
addiu $sp, $sp, 16

View File

@ -1,17 +0,0 @@
.set noreorder
.global dlsym
.hidden __dlsym
.type dlsym,@function
dlsym:
lui $3, %hi(%neg(%gp_rel(dlsym)))
daddiu $3, $3, %lo(%neg(%gp_rel(dlsym)))
daddu $3, $3, $25
move $6, $ra
ld $25, %got_disp(__dlsym)($3)
daddiu $sp, $sp, -32
sd $ra, 24($sp)
jalr $25
nop
ld $ra, 24($sp)
jr $ra
daddiu $sp, $sp, 32

View File

@ -1,17 +0,0 @@
.set noreorder
.global dlsym
.hidden __dlsym
.type dlsym,@function
dlsym:
lui $3, %hi(%neg(%gp_rel(dlsym)))
addiu $3, $3, %lo(%neg(%gp_rel(dlsym)))
addu $3, $3, $25
move $6, $ra
lw $25, %got_disp(__dlsym)($3)
addiu $sp, $sp, -32
sd $ra, 16($sp)
jalr $25
nop
ld $ra, 16($sp)
jr $ra
addiu $sp, $sp, 32

View File

@ -1,6 +0,0 @@
.global dlsym
.hidden __dlsym
.type dlsym,@function
dlsym:
l.j __dlsym
l.ori r5, r9, 0

View File

@ -1,8 +0,0 @@
.text
.global dlsym
.hidden __dlsym
.type dlsym,@function
dlsym:
mflr 5 # The return address is arg3.
b __dlsym
.size dlsym, .-dlsym

View File

@ -1,11 +0,0 @@
.text
.global dlsym
.hidden __dlsym
.type dlsym,@function
dlsym:
addis 2, 12, .TOC.-dlsym@ha
addi 2, 2, .TOC.-dlsym@l
.localentry dlsym,.-dlsym
mflr 5 # The return address is arg3.
b __dlsym
.size dlsym, .-dlsym

View File

@ -1,6 +0,0 @@
.global dlsym
.hidden __dlsym
.type dlsym, %function
dlsym:
mv a2, ra
tail __dlsym

View File

@ -1,6 +0,0 @@
.global dlsym
.hidden __dlsym
.type dlsym,@function
dlsym:
lgr %r4, %r14
jg __dlsym

View File

@ -1,11 +0,0 @@
.text
.global dlsym
.hidden __dlsym
.type dlsym, @function
dlsym:
mov.l L1, r0
1: braf r0
mov.l @r15, r6
.align 2
L1: .long __dlsym@PLT-(1b+4-.)

View File

@ -1,9 +0,0 @@
#include <stddef.h>
#include <dynlink.h>
ptrdiff_t __tlsdesc_static()
{
return 0;
}
weak_alias(__tlsdesc_static, __tlsdesc_dynamic);

View File

@ -1,7 +0,0 @@
.text
.global dlsym
.hidden __dlsym
.type dlsym,@function
dlsym:
mov (%rsp),%rdx
jmp __dlsym

Some files were not shown because too many files have changed in this diff Show More