mirror of
https://github.com/ziglang/zig.git
synced 2024-11-14 16:13:24 +00:00
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:
parent
0000b34a2d
commit
dcc1b4fd15
@ -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();
|
||||
}
|
||||
|
5
lib/libc/wasi/libc-bottom-half/sources/__errno_location.c
vendored
Normal file
5
lib/libc/wasi/libc-bottom-half/sources/__errno_location.c
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
#include <errno.h>
|
||||
|
||||
int *__errno_location(void) {
|
||||
return &errno;
|
||||
}
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
418
lib/libc/wasi/libc-top-half/musl/src/aio/aio.c
vendored
418
lib/libc/wasi/libc-top-half/musl/src/aio/aio.c
vendored
@ -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);
|
@ -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
|
@ -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);
|
@ -1,6 +0,0 @@
|
||||
#include "complex_impl.h"
|
||||
|
||||
double (cimag)(double complex z)
|
||||
{
|
||||
return cimag(z);
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
#include "complex_impl.h"
|
||||
|
||||
float (cimagf)(float complex z)
|
||||
{
|
||||
return cimagf(z);
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
#include "complex_impl.h"
|
||||
|
||||
long double (cimagl)(long double complex z)
|
||||
{
|
||||
return cimagl(z);
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
#include <complex.h>
|
||||
|
||||
double (creal)(double complex z)
|
||||
{
|
||||
return creal(z);
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
#include <complex.h>
|
||||
|
||||
float (crealf)(float complex z)
|
||||
{
|
||||
return crealf(z);
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
#include <complex.h>
|
||||
|
||||
long double (creall)(long double complex z)
|
||||
{
|
||||
return creall(z);
|
||||
}
|
@ -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;
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#include <dirent.h>
|
||||
#include "__dirent.h"
|
||||
|
||||
int dirfd(DIR *d)
|
||||
{
|
||||
return d->fd;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
@ -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);
|
@ -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);
|
||||
}
|
@ -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);
|
@ -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);
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#include <dirent.h>
|
||||
#include "__dirent.h"
|
||||
|
||||
long telldir(DIR *dir)
|
||||
{
|
||||
return dir->tell;
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
#include <unistd.h>
|
||||
|
||||
char **__environ = 0;
|
||||
weak_alias(__environ, ___environ);
|
||||
weak_alias(__environ, _environ);
|
||||
weak_alias(__environ, environ);
|
@ -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
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
#include "pthread_impl.h"
|
||||
|
||||
volatile int __abort_lock[1];
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
@ -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);
|
@ -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);
|
@ -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);
|
@ -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;
|
||||
}
|
@ -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
|
@ -1,3 +0,0 @@
|
||||
#if !__ARM_PCS_VFP
|
||||
#include "../fenv.c"
|
||||
#endif
|
@ -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
|
@ -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
|
@ -1,3 +0,0 @@
|
||||
#ifdef __mips_soft_float
|
||||
#include "../fenv.c"
|
||||
#endif
|
@ -1,3 +0,0 @@
|
||||
#ifdef __mips_soft_float
|
||||
#include "../fenv.c"
|
||||
#endif
|
@ -1,3 +0,0 @@
|
||||
#ifdef __mips_soft_float
|
||||
#include "../fenv.c"
|
||||
#endif
|
@ -1,3 +0,0 @@
|
||||
#if defined(_SOFT_FLOAT) || defined(__NO_FPRS__)
|
||||
#include "../fenv.c"
|
||||
#endif
|
@ -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;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
#ifndef __riscv_flen
|
||||
#include "../fenv.c"
|
||||
#endif
|
@ -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;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
#if !__SH_FPU_ANY__ && !__SH4__
|
||||
#include "../fenv.c"
|
||||
#endif
|
@ -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
|
@ -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
|
@ -1,9 +0,0 @@
|
||||
1: int $128
|
||||
ret
|
||||
|
||||
.data
|
||||
.align 4
|
||||
.hidden __sysinfo
|
||||
.global __sysinfo
|
||||
__sysinfo:
|
||||
.long 1b
|
@ -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;
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
#include <features.h>
|
||||
|
||||
hidden int __shcall(void *arg, int (*func)(void *))
|
||||
{
|
||||
return func(arg);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
@ -1,4 +0,0 @@
|
||||
#include "version.h"
|
||||
#include "libc.h"
|
||||
|
||||
const char __libc_version[] = VERSION;
|
10
lib/libc/wasi/libc-top-half/musl/src/ipc/ftok.c
vendored
10
lib/libc/wasi/libc-top-half/musl/src/ipc/ftok.c
vendored
@ -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));
|
||||
}
|
@ -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);
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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);
|
||||
}
|
@ -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
|
||||
}
|
12
lib/libc/wasi/libc-top-half/musl/src/ipc/semop.c
vendored
12
lib/libc/wasi/libc-top-half/musl/src/ipc/semop.c
vendored
@ -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
|
||||
}
|
@ -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
|
||||
}
|
17
lib/libc/wasi/libc-top-half/musl/src/ipc/shmat.c
vendored
17
lib/libc/wasi/libc-top-half/musl/src/ipc/shmat.c
vendored
@ -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
|
@ -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);
|
||||
}
|
12
lib/libc/wasi/libc-top-half/musl/src/ipc/shmdt.c
vendored
12
lib/libc/wasi/libc-top-half/musl/src/ipc/shmdt.c
vendored
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
@ -1,6 +0,0 @@
|
||||
.global dlsym
|
||||
.hidden __dlsym
|
||||
.type dlsym,%function
|
||||
dlsym:
|
||||
mov x2,x30
|
||||
b __dlsym
|
@ -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
|
@ -1,8 +0,0 @@
|
||||
.syntax unified
|
||||
.text
|
||||
.global dlsym
|
||||
.hidden __dlsym
|
||||
.type dlsym,%function
|
||||
dlsym:
|
||||
mov r2,lr
|
||||
b __dlsym
|
@ -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;
|
||||
}
|
@ -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);
|
@ -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);
|
@ -1,7 +0,0 @@
|
||||
#include <dlfcn.h>
|
||||
#include "dynlink.h"
|
||||
|
||||
int dlclose(void *p)
|
||||
{
|
||||
return __dl_invalid_handle(p);
|
||||
}
|
@ -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);
|
@ -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;
|
||||
}
|
@ -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);
|
@ -1,7 +0,0 @@
|
||||
#include <dlfcn.h>
|
||||
#include "dynlink.h"
|
||||
|
||||
void *dlsym(void *restrict p, const char *restrict s)
|
||||
{
|
||||
return __dlsym(p, s, 0);
|
||||
}
|
@ -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
|
@ -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
|
@ -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
|
@ -1,6 +0,0 @@
|
||||
.global dlsym
|
||||
.hidden __dlsym
|
||||
.type dlsym,@function
|
||||
dlsym:
|
||||
brid __dlsym
|
||||
add r7, r15, r0
|
@ -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
|
@ -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
|
@ -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
|
@ -1,6 +0,0 @@
|
||||
.global dlsym
|
||||
.hidden __dlsym
|
||||
.type dlsym,@function
|
||||
dlsym:
|
||||
l.j __dlsym
|
||||
l.ori r5, r9, 0
|
@ -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
|
@ -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
|
@ -1,6 +0,0 @@
|
||||
.global dlsym
|
||||
.hidden __dlsym
|
||||
.type dlsym, %function
|
||||
dlsym:
|
||||
mv a2, ra
|
||||
tail __dlsym
|
@ -1,6 +0,0 @@
|
||||
.global dlsym
|
||||
.hidden __dlsym
|
||||
.type dlsym,@function
|
||||
dlsym:
|
||||
lgr %r4, %r14
|
||||
jg __dlsym
|
@ -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-.)
|
@ -1,9 +0,0 @@
|
||||
#include <stddef.h>
|
||||
#include <dynlink.h>
|
||||
|
||||
ptrdiff_t __tlsdesc_static()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
weak_alias(__tlsdesc_static, __tlsdesc_dynamic);
|
@ -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
Loading…
Reference in New Issue
Block a user