[PATCH 1/3] prepare to hide kernel symbols: add macros to expose and hide symbols

33 views
Skip to first unread message

Waldemar Kozaczuk

unread,
Nov 21, 2021, 4:09:39 AM11/21/21
to osv...@googlegroups.com, Waldemar Kozaczuk
This patch is the first one in the series that annotates relevant
symbols across number of source files in order to expose or hide them
when kernel is compiled to hide non-glibc symbols. Please note that none
of this patches neither hides nor exposes any symbols. In essense it will
only have an effect once we make changes to the makefile to allow compiling
the kernel with most symbols hidden.

This patch adds new header - export.h - with new macros that either
expose (__visibility__("default")) or hide (__visibility__("hidden"))
the symbols. Please read the comments in the header file for more
details.

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
---
include/osv/export.h | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
create mode 100644 include/osv/export.h

diff --git a/include/osv/export.h b/include/osv/export.h
new file mode 100644
index 00000000..e6266fcc
--- /dev/null
+++ b/include/osv/export.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 Waldemar Kozaczuk
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#ifndef EXPORT_H
+#define EXPORT_H
+
+//
+// Please note that the macros below are used in the source files and
+// are intended to expose the annotated symbols as public when the kernel
+// files are compiled with the flag '-fvisibility=hidden'. When the kernel
+// is compiled without compatibility flag, these macro do not have any affect
+// as all symbols in this case are exposed as public. So either way, the symbols
+// annotated with these macros yield desired effect.
+// We do not really need to define a macro for each Linux glibc library and we could
+// have had single OSV_GLIBC_API macro instead of eight ones below. However by
+// having a macro for each library shared file where a symbol is part of,
+// we automatically self-document the code and in future could auto-generate some
+// docs.
+#define OSV_LIBAIO_API __attribute__((__visibility__("default")))
+#define OSV_LIBC_API __attribute__((__visibility__("default")))
+#define OSV_LIBM_API __attribute__((__visibility__("default")))
+#define OSV_LIBBSD_API __attribute__((__visibility__("default")))
+#define OSV_LIBPTHREAD_API __attribute__((__visibility__("default")))
+#define OSV_LIBUTIL_API __attribute__((__visibility__("default")))
+#define OSV_LIBXENSTORE_API __attribute__((__visibility__("default")))
+#define OSV_LD_LINUX_x86_64_API __attribute__((__visibility__("default")))
+
+// In some very few cases, when source files are compiled without compatibility
+// flag in order to expose most symbols in the corresponding file, there are some specific
+// symbols in the same file that we want to hide and this is where we use this macro.
+// Regardless if we hide most symbols in the kernel or not, the annotated symbols would
+// be always hidden.
+#define OSV_HIDDEN __attribute__((__visibility__("hidden")))
+
+#endif /* EXPORT_H */
--
2.31.1

Waldemar Kozaczuk

unread,
Nov 21, 2021, 4:09:46 AM11/21/21
to osv...@googlegroups.com, Waldemar Kozaczuk
This 2nd patch in the series annotates number of standard glibc symbols
across number of source files, mostly under bsd, core, fs and libc
folders. This does not have any effect until we introduce the changes to
the makefile to support compiling kernel with most symbols hidden.

We choose to annotate the symbols that need to be exposed because the relevant files
will be compiled with the flag '-fvisibility=hidden' which would hide
all symbols unless annotated otherwise which takes precedence. This
approach helps to minimize the number of symbols that need to be annotated.

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
---
bsd/porting/sync_stub.h | 11 +-
bsd/sys/kern/uipc_syscalls_wrap.cc | 37 +++---
bsd/sys/netinet/in.h | 11 +-
bsd/sys/rpc/xdr.h | 75 +++++++------
bsd/sys/sys/libkern.h | 3 +-
bsd/sys/sys/md5.h | 7 +-
bsd/sys/xen/xenstore/xenstorevar.h | 17 +--
core/app.cc | 5 +-
core/elf.cc | 6 +-
core/epoll.cc | 11 +-
core/libaio.cc | 11 +-
core/math.cc | 13 ++-
core/mempool.cc | 9 +-
core/poll.cc | 7 +-
core/power.cc | 3 +-
core/select.cc | 7 +-
fs/vfs/kern_descrip.cc | 3 +-
fs/vfs/main.cc | 175 +++++++++++++++--------------
include/api/__fenv.h | 8 +-
include/osv/sched.hh | 1 +
libc/eventfd.cc | 6 +-
libc/internal/libc.h | 3 +-
libc/misc/getopt.cc | 10 +-
libc/misc/getopt_long.cc | 5 +-
libc/misc/mntent.cc | 12 +-
libc/mman.cc | 16 +--
libc/pipe.cc | 4 +-
libc/pthread.cc | 13 ++-
libc/resource.cc | 1 -
libc/sem.cc | 12 +-
libc/signal.cc | 41 +++----
libc/time.cc | 16 +--
libc/timerfd.cc | 6 +-
linux.cc | 5 +-
runtime.cc | 101 ++++++++---------
35 files changed, 344 insertions(+), 327 deletions(-)

diff --git a/bsd/porting/sync_stub.h b/bsd/porting/sync_stub.h
index f6669844..65185746 100644
--- a/bsd/porting/sync_stub.h
+++ b/bsd/porting/sync_stub.h
@@ -11,6 +11,7 @@
#include <sys/cdefs.h>
#include <osv/mutex.h>
#include <osv/rwlock.h>
+#include <osv/export.h>

struct mtx {
mutex_t _mutex;
@@ -29,11 +30,11 @@ struct sx {
#define MA_NOTRECURSED (0x08)

__BEGIN_DECLS
-void mtx_init(struct mtx *m, const char *name, const char *type, int opts);
-void mtx_destroy(struct mtx *m);
-void mtx_lock(struct mtx *mp);
-int mtx_trylock(struct mtx *mp);
-void mtx_unlock(struct mtx *mp);
+OSV_LIBPTHREAD_API void mtx_init(struct mtx *m, const char *name, const char *type, int opts);
+OSV_LIBPTHREAD_API void mtx_destroy(struct mtx *m);
+OSV_LIBPTHREAD_API void mtx_lock(struct mtx *mp);
+OSV_LIBPTHREAD_API int mtx_trylock(struct mtx *mp);
+OSV_LIBPTHREAD_API void mtx_unlock(struct mtx *mp);
void mtx_assert(struct mtx *mp, int flag);

void sx_init(struct sx *m, const char *name);
diff --git a/bsd/sys/kern/uipc_syscalls_wrap.cc b/bsd/sys/kern/uipc_syscalls_wrap.cc
index ca666ca2..720cab35 100644
--- a/bsd/sys/kern/uipc_syscalls_wrap.cc
+++ b/bsd/sys/kern/uipc_syscalls_wrap.cc
@@ -5,6 +5,7 @@

#include <bsd/uipc_syscalls.h>
#include <osv/debug.h>
+#include <osv/export.h>
#include "libc/af_local.h"

#include "libc/internal/libc.h"
@@ -12,7 +13,7 @@
#define sock_d(...) tprintf_d("socket-api", __VA_ARGS__);

extern "C"
-int socketpair(int domain, int type, int protocol, int sv[2])
+OSV_LIBC_API int socketpair(int domain, int type, int protocol, int sv[2])
{
int error;

@@ -33,7 +34,7 @@ int socketpair(int domain, int type, int protocol, int sv[2])
}

extern "C"
-int getsockname(int sockfd, struct bsd_sockaddr *addr, socklen_t *addrlen)
+OSV_LIBC_API int getsockname(int sockfd, struct bsd_sockaddr *addr, socklen_t *addrlen)
{
int error;

@@ -50,7 +51,7 @@ int getsockname(int sockfd, struct bsd_sockaddr *addr, socklen_t *addrlen)
}

extern "C"
-int getpeername(int sockfd, struct bsd_sockaddr *addr, socklen_t *addrlen)
+OSV_LIBC_API int getpeername(int sockfd, struct bsd_sockaddr *addr, socklen_t *addrlen)
{
int error;

@@ -67,7 +68,7 @@ int getpeername(int sockfd, struct bsd_sockaddr *addr, socklen_t *addrlen)
}

extern "C"
-int accept4(int fd, struct bsd_sockaddr *__restrict addr, socklen_t *__restrict len, int flg)
+OSV_LIBC_API int accept4(int fd, struct bsd_sockaddr *__restrict addr, socklen_t *__restrict len, int flg)
{
int fd2, error;

@@ -84,7 +85,7 @@ int accept4(int fd, struct bsd_sockaddr *__restrict addr, socklen_t *__restrict
}

extern "C"
-int accept(int fd, struct bsd_sockaddr *__restrict addr, socklen_t *__restrict len)
+OSV_LIBC_API int accept(int fd, struct bsd_sockaddr *__restrict addr, socklen_t *__restrict len)
{
int fd2, error;

@@ -101,7 +102,7 @@ int accept(int fd, struct bsd_sockaddr *__restrict addr, socklen_t *__restrict l
}

extern "C"
-int bind(int fd, const struct bsd_sockaddr *addr, socklen_t len)
+OSV_LIBC_API int bind(int fd, const struct bsd_sockaddr *addr, socklen_t len)
{
int error;

@@ -118,7 +119,7 @@ int bind(int fd, const struct bsd_sockaddr *addr, socklen_t len)
}

extern "C"
-int connect(int fd, const struct bsd_sockaddr *addr, socklen_t len)
+OSV_LIBC_API int connect(int fd, const struct bsd_sockaddr *addr, socklen_t len)
{
int error;

@@ -135,7 +136,7 @@ int connect(int fd, const struct bsd_sockaddr *addr, socklen_t len)
}

extern "C"
-int listen(int fd, int backlog)
+OSV_LIBC_API int listen(int fd, int backlog)
{
int error;

@@ -152,7 +153,7 @@ int listen(int fd, int backlog)
}

extern "C"
-ssize_t recvfrom(int fd, void *__restrict buf, size_t len, int flags,
+OSV_LIBC_API ssize_t recvfrom(int fd, void *__restrict buf, size_t len, int flags,
struct bsd_sockaddr *__restrict addr, socklen_t *__restrict alen)
{
int error;
@@ -172,7 +173,7 @@ ssize_t recvfrom(int fd, void *__restrict buf, size_t len, int flags,
}

extern "C"
-ssize_t recv(int fd, void *buf, size_t len, int flags)
+OSV_LIBC_API ssize_t recv(int fd, void *buf, size_t len, int flags)
{
int error;
ssize_t bytes;
@@ -190,7 +191,7 @@ ssize_t recv(int fd, void *buf, size_t len, int flags)
}

extern "C"
-ssize_t recvmsg(int fd, struct msghdr *msg, int flags)
+OSV_LIBC_API ssize_t recvmsg(int fd, struct msghdr *msg, int flags)
{
ssize_t bytes;
int error;
@@ -208,7 +209,7 @@ ssize_t recvmsg(int fd, struct msghdr *msg, int flags)
}

extern "C"
-ssize_t sendto(int fd, const void *buf, size_t len, int flags,
+OSV_LIBC_API ssize_t sendto(int fd, const void *buf, size_t len, int flags,
const struct bsd_sockaddr *addr, socklen_t alen)
{
int error;
@@ -228,7 +229,7 @@ ssize_t sendto(int fd, const void *buf, size_t len, int flags,
}

extern "C"
-ssize_t send(int fd, const void *buf, size_t len, int flags)
+OSV_LIBC_API ssize_t send(int fd, const void *buf, size_t len, int flags)
{
int error;
ssize_t bytes;
@@ -246,7 +247,7 @@ ssize_t send(int fd, const void *buf, size_t len, int flags)
}

extern "C"
-ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)
+OSV_LIBC_API ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)
{
ssize_t bytes;
int error;
@@ -264,7 +265,7 @@ ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)
}

extern "C"
-int getsockopt(int fd, int level, int optname, void *__restrict optval,
+OSV_LIBC_API int getsockopt(int fd, int level, int optname, void *__restrict optval,
socklen_t *__restrict optlen)
{
int error;
@@ -282,7 +283,7 @@ int getsockopt(int fd, int level, int optname, void *__restrict optval,
}

extern "C"
-int setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)
+OSV_LIBC_API int setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)
{
int error;

@@ -300,7 +301,7 @@ int setsockopt(int fd, int level, int optname, const void *optval, socklen_t opt
}

extern "C"
-int shutdown(int fd, int how)
+OSV_LIBC_API int shutdown(int fd, int how)
{
int error;

@@ -323,7 +324,7 @@ int shutdown(int fd, int how)
}

extern "C"
-int socket(int domain, int type, int protocol)
+OSV_LIBC_API int socket(int domain, int type, int protocol)
{
int s, error;

diff --git a/bsd/sys/netinet/in.h b/bsd/sys/netinet/in.h
index 43291b74..224389f0 100644
--- a/bsd/sys/netinet/in.h
+++ b/bsd/sys/netinet/in.h
@@ -48,6 +48,7 @@
#include <netinet/__in.h>

#include <bsd/sys/sys/_sockaddr_storage.h>
+#include <osv/export.h>

/* Socket address, internet style. */
struct bsd_sockaddr_in {
@@ -464,11 +465,11 @@ int in_broadcast(struct in_addr, struct ifnet *);
int in_canforward(struct in_addr);
int in_localaddr(struct in_addr);
int in_localip(struct in_addr);
-int inet_aton(const char *, struct in_addr *); /* in libkern */
-char *inet_ntoa(struct in_addr); /* in libkern */
-const char *inet_ntoa_r(struct in_addr ina, char *buf, socklen_t); /* in libkern */
-const char *inet_ntop(int, const void *, char *, socklen_t); /* in libkern */
-int inet_pton(int af, const char *, void *); /* in libkern */
+OSV_LIBC_API int inet_aton(const char *, struct in_addr *); /* in libkern */
+OSV_LIBC_API char *inet_ntoa(struct in_addr); /* in libkern */
+OSV_LIBC_API const char *inet_ntoa_r(struct in_addr ina, char *buf, socklen_t); /* in libkern */
+OSV_LIBC_API const char *inet_ntop(int, const void *, char *, socklen_t); /* in libkern */
+OSV_LIBC_API int inet_pton(int af, const char *, void *); /* in libkern */
void in_ifdetach(struct ifnet *);
__END_DECLS

diff --git a/bsd/sys/rpc/xdr.h b/bsd/sys/rpc/xdr.h
index 92af2302..f9380bc7 100644
--- a/bsd/sys/rpc/xdr.h
+++ b/bsd/sys/rpc/xdr.h
@@ -42,6 +42,7 @@
#ifndef _KRPC_XDR_H
#define _KRPC_XDR_H
#include <sys/cdefs.h>
+#include <osv/export.h>

/*
* XDR provides a conventional way for converting between C data
@@ -288,41 +289,41 @@ struct xdr_discrim {
* These are the "generic" xdr routines.
*/
__BEGIN_DECLS
-extern bool_t xdr_void(void);
-extern bool_t xdr_int(XDR *, int *);
-extern bool_t xdr_u_int(XDR *, u_int *);
-extern bool_t xdr_long(XDR *, long *);
-extern bool_t xdr_u_long(XDR *, u_long *);
-extern bool_t xdr_short(XDR *, short *);
-extern bool_t xdr_u_short(XDR *, u_short *);
-extern bool_t xdr_int16_t(XDR *, int16_t *);
-extern bool_t xdr_uint16_t(XDR *, uint16_t *);
-extern bool_t xdr_int32_t(XDR *, int32_t *);
-extern bool_t xdr_uint32_t(XDR *, uint32_t *);
-extern bool_t xdr_int64_t(XDR *, int64_t *);
-extern bool_t xdr_uint64_t(XDR *, uint64_t *);
-extern bool_t xdr_bool(XDR *, bool_t *);
-extern bool_t xdr_enum(XDR *, enum_t *);
-extern bool_t xdr_array(XDR *, char **, u_int *, u_int, u_int, xdrproc_t);
-extern bool_t xdr_bytes(XDR *, char **, u_int *, u_int);
-extern bool_t xdr_opaque(XDR *, char *, u_int);
-extern bool_t xdr_string(XDR *, char **, u_int);
-extern bool_t xdr_union(XDR *, enum_t *, char *, const struct xdr_discrim *, xdrproc_t);
-extern bool_t xdr_char(XDR *, char *);
-extern bool_t xdr_u_char(XDR *, u_char *);
-extern bool_t xdr_vector(XDR *, char *, u_int, u_int, xdrproc_t);
-extern bool_t xdr_float(XDR *, float *);
-extern bool_t xdr_double(XDR *, double *);
-extern bool_t xdr_quadruple(XDR *, long double *);
-extern bool_t xdr_reference(XDR *, char **, u_int, xdrproc_t);
-extern bool_t xdr_pointer(XDR *, char **, u_int, xdrproc_t);
-extern bool_t xdr_wrapstring(XDR *, char **);
-extern void xdr_free(xdrproc_t, void *);
-extern bool_t xdr_hyper(XDR *, quad_t *);
-extern bool_t xdr_u_hyper(XDR *, u_quad_t *);
-extern bool_t xdr_longlong_t(XDR *, quad_t *);
-extern bool_t xdr_u_longlong_t(XDR *, u_quad_t *);
-extern unsigned long xdr_sizeof(xdrproc_t func, void *data);
+extern OSV_LIBC_API bool_t xdr_void(void);
+extern OSV_LIBC_API bool_t xdr_int(XDR *, int *);
+extern OSV_LIBC_API bool_t xdr_u_int(XDR *, u_int *);
+extern OSV_LIBC_API bool_t xdr_long(XDR *, long *);
+extern OSV_LIBC_API bool_t xdr_u_long(XDR *, u_long *);
+extern OSV_LIBC_API bool_t xdr_short(XDR *, short *);
+extern OSV_LIBC_API bool_t xdr_u_short(XDR *, u_short *);
+extern OSV_LIBC_API bool_t xdr_int16_t(XDR *, int16_t *);
+extern OSV_LIBC_API bool_t xdr_uint16_t(XDR *, uint16_t *);
+extern OSV_LIBC_API bool_t xdr_int32_t(XDR *, int32_t *);
+extern OSV_LIBC_API bool_t xdr_uint32_t(XDR *, uint32_t *);
+extern OSV_LIBC_API bool_t xdr_int64_t(XDR *, int64_t *);
+extern OSV_LIBC_API bool_t xdr_uint64_t(XDR *, uint64_t *);
+extern OSV_LIBC_API bool_t xdr_bool(XDR *, bool_t *);
+extern OSV_LIBC_API bool_t xdr_enum(XDR *, enum_t *);
+extern OSV_LIBC_API bool_t xdr_array(XDR *, char **, u_int *, u_int, u_int, xdrproc_t);
+extern OSV_LIBC_API bool_t xdr_bytes(XDR *, char **, u_int *, u_int);
+extern OSV_LIBC_API bool_t xdr_opaque(XDR *, char *, u_int);
+extern OSV_LIBC_API bool_t xdr_string(XDR *, char **, u_int);
+extern OSV_LIBC_API bool_t xdr_union(XDR *, enum_t *, char *, const struct xdr_discrim *, xdrproc_t);
+extern OSV_LIBC_API bool_t xdr_char(XDR *, char *);
+extern OSV_LIBC_API bool_t xdr_u_char(XDR *, u_char *);
+extern OSV_LIBC_API bool_t xdr_vector(XDR *, char *, u_int, u_int, xdrproc_t);
+extern OSV_LIBC_API bool_t xdr_float(XDR *, float *);
+extern OSV_LIBC_API bool_t xdr_double(XDR *, double *);
+extern OSV_LIBC_API bool_t xdr_quadruple(XDR *, long double *);
+extern OSV_LIBC_API bool_t xdr_reference(XDR *, char **, u_int, xdrproc_t);
+extern OSV_LIBC_API bool_t xdr_pointer(XDR *, char **, u_int, xdrproc_t);
+extern OSV_LIBC_API bool_t xdr_wrapstring(XDR *, char **);
+extern OSV_LIBC_API void xdr_free(xdrproc_t, void *);
+extern OSV_LIBC_API bool_t xdr_hyper(XDR *, quad_t *);
+extern OSV_LIBC_API bool_t xdr_u_hyper(XDR *, u_quad_t *);
+extern OSV_LIBC_API bool_t xdr_longlong_t(XDR *, quad_t *);
+extern OSV_LIBC_API bool_t xdr_u_longlong_t(XDR *, u_quad_t *);
+extern OSV_LIBC_API unsigned long xdr_sizeof(xdrproc_t func, void *data);
__END_DECLS

/*
@@ -335,7 +336,7 @@ struct netobj {
char *n_bytes;
};
typedef struct netobj netobj;
-extern bool_t xdr_netobj(XDR *, struct netobj *);
+extern OSV_LIBC_API bool_t xdr_netobj(XDR *, struct netobj *);

/*
* These are XDR control operators
@@ -359,7 +360,7 @@ typedef struct xdr_bytesrec xdr_bytesrec;
*/
__BEGIN_DECLS
/* XDR using memory buffers */
-extern void xdrmem_create(XDR *, char *, u_int, enum xdr_op);
+extern OSV_LIBC_API void xdrmem_create(XDR *, char *, u_int, enum xdr_op);

/* XDR using mbufs */
struct mbuf;
diff --git a/bsd/sys/sys/libkern.h b/bsd/sys/sys/libkern.h
index 1452a8bf..47cf665f 100644
--- a/bsd/sys/sys/libkern.h
+++ b/bsd/sys/sys/libkern.h
@@ -35,6 +35,7 @@

#include <sys/cdefs.h>
#include <sys/types.h>
+#include <osv/export.h>

#ifndef LIBKERN_INLINE
#define LIBKERN_INLINE static __inline
@@ -47,7 +48,7 @@ void bsd_srandom(u_long);

/* Prototypes for non-quad routines. */
void arc4_init(void);
-uint32_t arc4random(void);
+OSV_LIBBSD_API uint32_t arc4random(void);
void arc4rand(void *ptr, u_int len, int reseed);

static __inline int imax(int a, int b) { return (a > b ? a : b); }
diff --git a/bsd/sys/sys/md5.h b/bsd/sys/sys/md5.h
index e98b7afb..bcc99b37 100644
--- a/bsd/sys/sys/md5.h
+++ b/bsd/sys/sys/md5.h
@@ -40,11 +40,12 @@ typedef struct MD5Context {
} MD5_CTX;

#include <sys/cdefs.h>
+#include <osv/export.h>

__BEGIN_DECLS
-void MD5Init (MD5_CTX *);
-void MD5Update (MD5_CTX *, const void *, unsigned int);
-void MD5Final (unsigned char [16], MD5_CTX *);
+OSV_LIBBSD_API void MD5Init (MD5_CTX *);
+OSV_LIBBSD_API void MD5Update (MD5_CTX *, const void *, unsigned int);
+OSV_LIBBSD_API void MD5Final (unsigned char [16], MD5_CTX *);
char * MD5End(MD5_CTX *, char *);
char * MD5File(const char *, char *);
char * MD5FileChunk(const char *, char *, off_t, off_t);
diff --git a/bsd/sys/xen/xenstore/xenstorevar.h b/bsd/sys/xen/xenstore/xenstorevar.h
index 43429ded..eb7f85af 100644
--- a/bsd/sys/xen/xenstore/xenstorevar.h
+++ b/bsd/sys/xen/xenstore/xenstorevar.h
@@ -53,23 +53,24 @@ __BEGIN_DECLS
#include <xen/interface/grant_table.h>
#include <xen/interface/io/xenbus.h>
#include <xen/interface/io/xs_wire.h>
+#include <osv/export.h>

#include "xenbus_if.h"

-const char **xs_directory(void *h, struct xs_transaction t, const char *path, unsigned int *num);
+OSV_LIBXENSTORE_API const char **xs_directory(void *h, struct xs_transaction t, const char *path, unsigned int *num);

-char *xs_read(void *h, struct xs_transaction t, const char *path, unsigned int *len);
+OSV_LIBXENSTORE_API char *xs_read(void *h, struct xs_transaction t, const char *path, unsigned int *len);

-int xs_write(void *h, struct xs_transaction t, const char *path, const char *string);
+OSV_LIBXENSTORE_API int xs_write(void *h, struct xs_transaction t, const char *path, const char *string);

-int xs_rm(void *h, struct xs_transaction t, const char *path);
+OSV_LIBXENSTORE_API int xs_rm(void *h, struct xs_transaction t, const char *path);

-int xs_transaction_start(void *h);
+OSV_LIBXENSTORE_API int xs_transaction_start(void *h);

-int xs_transaction_end(void *h, struct xs_transaction t, int abort);
+OSV_LIBXENSTORE_API int xs_transaction_end(void *h, struct xs_transaction t, int abort);

-void *xs_daemon_open();
-void xs_close(void *);
+OSV_LIBXENSTORE_API void *xs_daemon_open();
+OSV_LIBXENSTORE_API void xs_close(void *);
__END_DECLS

/* XenStore allocations including XenStore data returned to clients. */
diff --git a/core/app.cc b/core/app.cc
index e124353d..d8ba1a4b 100644
--- a/core/app.cc
+++ b/core/app.cc
@@ -11,6 +11,7 @@
#include <osv/run.hh>
#include <osv/power.hh>
#include <osv/trace.hh>
+#include <osv/export.h>
#include <functional>
#include <thread>
#include <libgen.h>
@@ -26,9 +27,9 @@ extern int optind;

// Java uses this global variable (supplied by Glibc) to figure out
// aproximatively where the initial thread's stack end.
-void *__libc_stack_end;
+OSV_LD_LINUX_x86_64_API void *__libc_stack_end;

-extern "C" void __libc_start_main(int (*main)(int, char**), int, char**,
+extern "C" OSV_LIBC_API void __libc_start_main(int (*main)(int, char**), int, char**,
void(*)(), void(*)(), void(*)(), void*)
{
auto app = osv::application::get_current();
diff --git a/core/elf.cc b/core/elf.cc
index ad2fcf5a..7b7c0006 100644
--- a/core/elf.cc
+++ b/core/elf.cc
@@ -26,6 +26,7 @@
#include <osv/stubbing.hh>
#include <sys/utsname.h>
#include <osv/demangle.hh>
+#include <osv/export.h>
#include <boost/version.hpp>
#include <deque>

@@ -1325,6 +1326,7 @@ program::program(void* addr)
"libaio.so.1",
"libxenstore.so.3.0",
"libcrypt.so.1",
+ "libutil.so",
};
auto ml = new modules_list();
ml->objects.push_back(_core.get());
@@ -1877,7 +1879,7 @@ char *object::setup_tls()
}

extern "C"
-void* __tls_get_addr(module_and_offset* mao)
+OSV_LD_LINUX_x86_64_API void* __tls_get_addr(module_and_offset* mao)
{
#ifdef AARCH64_PORT_STUB
abort();
@@ -1902,7 +1904,7 @@ void* __tls_get_addr(module_and_offset* mao)
extern utsname utsname;

extern "C"
-unsigned long getauxval(unsigned long type)
+OSV_LIBC_API unsigned long getauxval(unsigned long type)
{
switch (type) {
// Implemented, and really 0
diff --git a/core/epoll.cc b/core/epoll.cc
index 3978d19d..e65ec240 100644
--- a/core/epoll.cc
+++ b/core/epoll.cc
@@ -21,6 +21,7 @@
#include <boost/lockfree/policies.hpp>

#include <osv/debug.hh>
+#include <osv/export.h>
#include <unordered_map>
#include <boost/range/algorithm/find.hpp>
#include <algorithm>
@@ -248,7 +249,7 @@ public:
}
};

-int epoll_create(int size)
+OSV_LIBC_API int epoll_create(int size)
{
// Note we ignore the size parameter. There's no point in checking it's
// positive, and on the other hand we can't trust it being meaningful
@@ -256,7 +257,7 @@ int epoll_create(int size)
return epoll_create1(0);
}

-int epoll_create1(int flags)
+OSV_LIBC_API int epoll_create1(int flags)
{
flags &= ~EPOLL_CLOEXEC;
assert(!flags);
@@ -272,7 +273,7 @@ int epoll_create1(int flags)
}
}

-int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
+OSV_LIBC_API int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
{
trace_epoll_ctl(epfd, fd,
op==EPOLL_CTL_ADD ? "EPOLL_CTL_ADD" :
@@ -321,7 +322,7 @@ int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
}
}

-int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout_ms)
+OSV_LIBC_API int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout_ms)
{
trace_epoll_wait(epfd, maxevents, timeout_ms);
fileref epfr(fileref_from_fd(epfd));
@@ -339,7 +340,7 @@ int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout_
return epo->wait(events, maxevents, timeout_ms);
}

-int epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout_ms,
+OSV_LIBC_API int epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout_ms,
const sigset_t *sigmask)
{
sigset_t origmask;
diff --git a/core/libaio.cc b/core/libaio.cc
index 34d7bfa7..81acf417 100644
--- a/core/libaio.cc
+++ b/core/libaio.cc
@@ -11,8 +11,9 @@
#include <api/libaio.h>

#include <osv/stubbing.hh>
+#include <osv/export.h>

-int io_setup(int nr_events, io_context_t *ctxp_idp) {
+OSV_LIBAIO_API int io_setup(int nr_events, io_context_t *ctxp_idp) {
// This is a stub that doesn't actually do anything. If the caller tries
// to follow the io_setup() call with any other libaio call, those will
// fail.
@@ -23,8 +24,8 @@ int io_setup(int nr_events, io_context_t *ctxp_idp) {
return 0;
}

-UNIMPL(int io_submit(io_context_t ctx, long nr, struct iocb *ios[]))
-UNIMPL(int io_getevents(io_context_t ctx_id, long min_nr, long nr,
+UNIMPL(OSV_LIBAIO_API int io_submit(io_context_t ctx, long nr, struct iocb *ios[]))
+UNIMPL(OSV_LIBAIO_API int io_getevents(io_context_t ctx_id, long min_nr, long nr,
struct io_event *events, struct timespec *timeout))
-UNIMPL(int io_destroy(io_context_t ctx))
-UNIMPL(int io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt))
+UNIMPL(OSV_LIBAIO_API int io_destroy(io_context_t ctx))
+UNIMPL(OSV_LIBAIO_API int io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt))
diff --git a/core/math.cc b/core/math.cc
index 3abce08e..04001694 100644
--- a/core/math.cc
+++ b/core/math.cc
@@ -7,41 +7,42 @@

#include <math.h>
#include <osv/types.h>
+#include <osv/export.h>
#include <cmath>
#include <ctgmath>

extern "C"
-int __isnan(double v)
+OSV_LIBC_API int __isnan(double v)
{
return std::isnan(v);
}

extern "C"
-int __isnanf(float v)
+OSV_LIBC_API int __isnanf(float v)
{
return std::isnan(v);
}

extern "C"
-int __isnanl(long double v)
+OSV_LIBC_API int __isnanl(long double v)
{
return std::isnan(v);
}

extern "C"
-int __isinf(double v)
+OSV_LIBC_API int __isinf(double v)
{
return std::isinf(v);
}

extern "C"
-int __isinff(float v)
+OSV_LIBC_API int __isinff(float v)
{
return std::isinf(v);
}

extern "C"
-int __isinfl(double v)
+OSV_LIBC_API int __isinfl(double v)
{
return std::isinf(v);
}
diff --git a/core/mempool.cc b/core/mempool.cc
index c85bc2be..c3109dac 100644
--- a/core/mempool.cc
+++ b/core/mempool.cc
@@ -35,6 +35,7 @@
#include <boost/lockfree/stack.hpp>
#include <boost/lockfree/policies.hpp>
#include <osv/migration-lock.hh>
+#include <osv/export.h>

TRACEPOINT(trace_memory_malloc, "buf=%p, len=%d, align=%d", void *, size_t,
size_t);
@@ -2010,14 +2011,14 @@ void* malloc(size_t size)
return buf;
}

-void* realloc(void* obj, size_t size)
+OSV_LIBC_API void* realloc(void* obj, size_t size)
{
void* buf = std_realloc(obj, size);
trace_memory_realloc(obj, size, buf);
return buf;
}

-extern "C" void *reallocarray(void *ptr, size_t nmemb, size_t elem_size)
+extern "C" OSV_LIBC_API void *reallocarray(void *ptr, size_t nmemb, size_t elem_size)
{
size_t bytes;
if (__builtin_mul_overflow(nmemb, elem_size, &bytes)) {
@@ -2027,7 +2028,7 @@ extern "C" void *reallocarray(void *ptr, size_t nmemb, size_t elem_size)
return realloc(ptr, nmemb * elem_size);
}

-size_t malloc_usable_size(void* obj)
+OSV_LIBC_API size_t malloc_usable_size(void* obj)
{
if ( obj == nullptr ) {
return 0;
@@ -2079,7 +2080,7 @@ void *aligned_alloc(size_t alignment, size_t size)
// that size be a multiple of alignment.
// memalign() is considered to be an obsolete SunOS-ism, but Linux's glibc
// supports it, and some applications still use it.
-void *memalign(size_t alignment, size_t size)
+OSV_LIBC_API void *memalign(size_t alignment, size_t size)
{
return aligned_alloc(alignment, size);
}
diff --git a/core/poll.cc b/core/poll.cc
index cd968e4f..7b79bb0d 100644
--- a/core/poll.cc
+++ b/core/poll.cc
@@ -48,6 +48,7 @@

#include <osv/file.h>
#include <osv/poll.h>
+#include <osv/export.h>
#include <sys/epoll.h>

#include <bsd/porting/netport.h>
@@ -334,7 +335,7 @@ static int poll_one(struct pollfd& pfd, file::timeout_t timeout)
return fref->poll_sync(pfd, timeout);
}

-int poll(struct pollfd _pfd[], nfds_t _nfds, int _timeout)
+OSV_LIBC_API int poll(struct pollfd _pfd[], nfds_t _nfds, int _timeout)
{
trace_poll(_pfd, _nfds, _timeout);

@@ -357,7 +358,7 @@ int poll(struct pollfd _pfd[], nfds_t _nfds, int _timeout)
return ret;
}

-int ppoll(struct pollfd *fds, nfds_t nfds,
+OSV_LIBC_API int ppoll(struct pollfd *fds, nfds_t nfds,
const struct timespec *timeout_ts, const sigset_t *sigmask)
{
sigset_t origmask;
@@ -372,7 +373,7 @@ int ppoll(struct pollfd *fds, nfds_t nfds,
}
/* Used by code compiled on Linux with -D_FORTIFY_SOURCE */
extern "C"
-int __poll_chk (struct pollfd _pfd[], nfds_t _nfds, int _timeout, size_t pdflen)
+OSV_LIBC_API int __poll_chk (struct pollfd _pfd[], nfds_t _nfds, int _timeout, size_t pdflen)
{
assert(pdflen / sizeof (_pfd[0]) >= _nfds);
return poll (_pfd, _nfds, _timeout);
diff --git a/core/power.cc b/core/power.cc
index a228e771..f26ae0be 100644
--- a/core/power.cc
+++ b/core/power.cc
@@ -7,6 +7,7 @@

#include <osv/power.hh>
#include <osv/debug.hh>
+#include <osv/export.h>
#include <smp.hh>
#include <processor.hh>
#include <arch.hh>
@@ -20,7 +21,7 @@
// is questionable (e.g., abort()) so a debug() call might call further
// problems.

-int reboot(int cmd)
+OSV_LIBC_API int reboot(int cmd)
{
switch (cmd) {
case RB_POWER_OFF:
diff --git a/core/select.cc b/core/select.cc
index b40904e2..518e5ef3 100644
--- a/core/select.cc
+++ b/core/select.cc
@@ -10,6 +10,7 @@
#include <errno.h>
#include <signal.h>
#include <osv/poll.h>
+#include <osv/export.h>
#include <osv/debug.h>
#include <api/sys/select.h>
#include <bsd/porting/synch.h>
@@ -17,7 +18,7 @@
#define select_d(...) tprintf_d("select", __VA_ARGS__)

/* Basic select() implementation on top of poll() */
-int select (int nfds,
+OSV_LIBC_API int select (int nfds,
fd_set * readfds,
fd_set * writefds,
fd_set * exceptfds,
@@ -184,7 +185,7 @@ int select (int nfds,
}

/* Basic pselect() on top of select() */
-int pselect(int nfds, fd_set *readfds, fd_set *writefds,
+OSV_LIBC_API int pselect(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, const struct timespec *timeout_ts,
const sigset_t *sigmask)
{
@@ -203,7 +204,7 @@ int pselect(int nfds, fd_set *readfds, fd_set *writefds,
return ret;
}

-extern "C" unsigned long int
+extern "C" OSV_LIBC_API unsigned long int
__fdelt_chk (unsigned long int d)
{
if (d >= FD_SETSIZE)
diff --git a/fs/vfs/kern_descrip.cc b/fs/vfs/kern_descrip.cc
index cd8dc771..0eb56b7a 100644
--- a/fs/vfs/kern_descrip.cc
+++ b/fs/vfs/kern_descrip.cc
@@ -14,6 +14,7 @@
#include <osv/debug.h>
#include <osv/mutex.h>
#include <osv/rcu.hh>
+#include <osv/export.h>
#include <boost/range/algorithm/find.hpp>

#include <bsd/sys/sys/queue.h>
@@ -62,7 +63,7 @@ int _fdalloc(struct file *fp, int *newfd, int min_fd)
}

extern "C"
-int getdtablesize(void)
+OSV_LIBC_API int getdtablesize(void)
{
return FDMAX;
}
diff --git a/fs/vfs/main.cc b/fs/vfs/main.cc
index 116c3f20..b47a9785 100644
--- a/fs/vfs/main.cc
+++ b/fs/vfs/main.cc
@@ -56,6 +56,7 @@
#include <dlfcn.h>

#include <osv/prex.h>
+#include <osv/export.h>
#include <osv/vnode.h>
#include <osv/stubbing.hh>
#include <osv/ioctl.h>
@@ -103,7 +104,7 @@ TRACEPOINT(trace_vfs_open_err, "%d", int);
struct task *main_task; /* we only have a single process */

extern "C"
-int open(const char *pathname, int flags, ...)
+OSV_LIBC_API int open(const char *pathname, int flags, ...)
{
mode_t mode = 0;
if (flags & O_CREAT) {
@@ -159,7 +160,7 @@ int open(const char *pathname, int flags, ...)

LFS64(open);

-int openat(int dirfd, const char *pathname, int flags, ...)
+OSV_LIBC_API int openat(int dirfd, const char *pathname, int flags, ...)
{
mode_t mode = 0;
if (flags & O_CREAT) {
@@ -205,13 +206,13 @@ LFS64(openat);
// some cases (when the O_CREAT mode is used). As a safety feature, recent
// versions of Glibc add a feature where open() with two arguments is replaced
// by a call to __open_2(), which verifies it isn't called with O_CREATE.
-extern "C" int __open_2(const char *pathname, int flags)
+extern "C" OSV_LIBC_API int __open_2(const char *pathname, int flags)
{
assert(!(flags & O_CREAT));
return open(pathname, flags, 0);
}

-extern "C" int __open64_2(const char *file, int flags)
+extern "C" OSV_LIBC_API int __open64_2(const char *file, int flags)
{
if (flags & O_CREAT) {
errno = EINVAL;
@@ -221,7 +222,7 @@ extern "C" int __open64_2(const char *file, int flags)
return open64(file, flags);
}

-int creat(const char *pathname, mode_t mode)
+OSV_LIBC_API int creat(const char *pathname, mode_t mode)
{
return open(pathname, O_CREAT|O_WRONLY|O_TRUNC, mode);
}
@@ -231,7 +232,7 @@ TRACEPOINT(trace_vfs_close, "%d", int);
TRACEPOINT(trace_vfs_close_ret, "");
TRACEPOINT(trace_vfs_close_err, "%d", int);

-int close(int fd)
+OSV_LIBC_API int close(int fd)
{
int error;

@@ -255,7 +256,7 @@ TRACEPOINT(trace_vfs_mknod_err, "%d", int);


extern "C"
-int __xmknod(int ver, const char *pathname, mode_t mode, dev_t *dev)
+OSV_LIBC_API int __xmknod(int ver, const char *pathname, mode_t mode, dev_t *dev)
{
assert(ver == 0); // On x86-64 Linux, _MKNOD_VER_LINUX is 0.
struct task *t = main_task;
@@ -279,7 +280,7 @@ int __xmknod(int ver, const char *pathname, mode_t mode, dev_t *dev)
return -1;
}

-int mknod(const char *pathname, mode_t mode, dev_t dev)
+OSV_LIBC_API int mknod(const char *pathname, mode_t mode, dev_t dev)
{
return __xmknod(0, pathname, mode, &dev);
}
@@ -289,7 +290,7 @@ TRACEPOINT(trace_vfs_lseek, "%d 0x%x %d", int, off_t, int);
TRACEPOINT(trace_vfs_lseek_ret, "0x%x", off_t);
TRACEPOINT(trace_vfs_lseek_err, "%d", int);

-off_t lseek(int fd, off_t offset, int whence)
+OSV_LIBC_API off_t lseek(int fd, off_t offset, int whence)
{
struct file *fp;
off_t org;
@@ -333,7 +334,7 @@ static inline bool has_error(int error, int bytes)
}


-ssize_t pread(int fd, void *buf, size_t count, off_t offset)
+OSV_LIBC_API ssize_t pread(int fd, void *buf, size_t count, off_t offset)
{
trace_vfs_pread(fd, buf, count, offset);
struct iovec iov = {
@@ -364,7 +365,7 @@ ssize_t pread(int fd, void *buf, size_t count, off_t offset)

LFS64(pread);

-ssize_t read(int fd, void *buf, size_t count)
+OSV_LIBC_API ssize_t read(int fd, void *buf, size_t count)
{
return pread(fd, buf, count, -1);
}
@@ -373,7 +374,7 @@ TRACEPOINT(trace_vfs_pwrite, "%d %p 0x%x 0x%x", int, const void*, size_t, off_t)
TRACEPOINT(trace_vfs_pwrite_ret, "0x%x", ssize_t);
TRACEPOINT(trace_vfs_pwrite_err, "%d", int);

-ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
+OSV_LIBC_API ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
{
trace_vfs_pwrite(fd, buf, count, offset);
struct iovec iov = {
@@ -404,12 +405,12 @@ ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)

LFS64(pwrite);

-ssize_t write(int fd, const void *buf, size_t count)
+OSV_LIBC_API ssize_t write(int fd, const void *buf, size_t count)
{
return pwrite(fd, buf, count, -1);
}

-ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
+OSV_LIBC_API ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
{
struct file *fp;
size_t bytes;
@@ -431,7 +432,7 @@ ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
return -1;
}

-ssize_t readv(int fd, const struct iovec *iov, int iovcnt)
+OSV_LIBC_API ssize_t readv(int fd, const struct iovec *iov, int iovcnt)
{
return preadv(fd, iov, iovcnt, -1);
}
@@ -440,7 +441,7 @@ TRACEPOINT(trace_vfs_pwritev, "%d %p 0x%x 0x%x", int, const struct iovec*, int,
TRACEPOINT(trace_vfs_pwritev_ret, "0x%x", ssize_t);
TRACEPOINT(trace_vfs_pwritev_err, "%d", int);

-ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
+OSV_LIBC_API ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
{
struct file *fp;
size_t bytes;
@@ -465,7 +466,7 @@ ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
return -1;
}

-ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
+OSV_LIBC_API ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
{
return pwritev(fd, iov, iovcnt, -1);
}
@@ -474,7 +475,7 @@ TRACEPOINT(trace_vfs_ioctl, "%d 0x%x", int, unsigned long);
TRACEPOINT(trace_vfs_ioctl_ret, "");
TRACEPOINT(trace_vfs_ioctl_err, "%d", int);

-int ioctl(int fd, unsigned long int request, ...)
+OSV_LIBC_API int ioctl(int fd, unsigned long int request, ...)
{
struct file *fp;
int error;
@@ -511,7 +512,7 @@ TRACEPOINT(trace_vfs_fsync, "%d", int);
TRACEPOINT(trace_vfs_fsync_ret, "");
TRACEPOINT(trace_vfs_fsync_err, "%d", int);

-int fsync(int fd)
+OSV_LIBC_API int fsync(int fd)
{
struct file *fp;
int error;
@@ -535,7 +536,7 @@ int fsync(int fd)
return -1;
}

-int fdatasync(int fd)
+OSV_LIBC_API int fdatasync(int fd)
{
// TODO: See if we can do less than fsync().
return fsync(fd);
@@ -546,7 +547,7 @@ TRACEPOINT(trace_vfs_fstat_ret, "");
TRACEPOINT(trace_vfs_fstat_err, "%d", int);

extern "C"
-int __fxstat(int ver, int fd, struct stat *st)
+OSV_LIBC_API int __fxstat(int ver, int fd, struct stat *st)
{
struct file *fp;
int error;
@@ -574,13 +575,13 @@ int __fxstat(int ver, int fd, struct stat *st)
LFS64(__fxstat);

extern "C"
-int fstat(int fd, struct stat *st)
+OSV_LIBC_API int fstat(int fd, struct stat *st)
{
return __fxstat(1, fd, st);
}

extern "C"
-int __fxstatat(int ver, int dirfd, const char *pathname, struct stat *st,
+OSV_LIBC_API int __fxstatat(int ver, int dirfd, const char *pathname, struct stat *st,
int flags)
{
if (pathname[0] == '/' || dirfd == AT_FDCWD) {
@@ -626,12 +627,12 @@ int __fxstatat(int ver, int dirfd, const char *pathname, struct stat *st,
LFS64(__fxstatat);

extern "C"
-int fstatat(int dirfd, const char *path, struct stat *st, int flags)
+OSV_LIBC_API int fstatat(int dirfd, const char *path, struct stat *st, int flags)
{
return __fxstatat(1, dirfd, path, st, flags);
}

-extern "C" int flock(int fd, int operation)
+extern "C" OSV_LIBC_API int flock(int fd, int operation)
{
if (!fileref_from_fd(fd)) {
return libc_error(EBADF);
@@ -660,7 +661,7 @@ struct __dirstream
int fd;
};

-DIR *opendir(const char *path)
+OSV_LIBC_API DIR *opendir(const char *path)
{
DIR *dir = new DIR;

@@ -675,7 +676,7 @@ DIR *opendir(const char *path)
return dir;
}

-DIR *fdopendir(int fd)
+OSV_LIBC_API DIR *fdopendir(int fd)
{
DIR *dir;
struct stat st;
@@ -692,7 +693,7 @@ DIR *fdopendir(int fd)

}

-int dirfd(DIR *dirp)
+OSV_LIBC_API int dirfd(DIR *dirp)
{
if (!dirp) {
return libc_error(EINVAL);
@@ -701,14 +702,14 @@ int dirfd(DIR *dirp)
return dirp->fd;
}

-int closedir(DIR *dir)
+OSV_LIBC_API int closedir(DIR *dir)
{
close(dir->fd);
delete dir;
return 0;
}

-struct dirent *readdir(DIR *dir)
+OSV_LIBC_API struct dirent *readdir(DIR *dir)
{
static __thread struct dirent entry, *result;
int ret;
@@ -721,7 +722,7 @@ struct dirent *readdir(DIR *dir)
return result;
}

-int readdir_r(DIR *dir, struct dirent *entry, struct dirent **result)
+OSV_LIBC_API int readdir_r(DIR *dir, struct dirent *entry, struct dirent **result)
{
int error;
struct file *fp;
@@ -752,14 +753,14 @@ int readdir_r(DIR *dir, struct dirent *entry, struct dirent **result)

// FIXME: in 64bit dirent64 and dirent are identical, so it's safe to alias
#undef readdir64_r
-extern "C" int readdir64_r(DIR *dir, struct dirent64 *entry,
+extern "C" OSV_LIBC_API int readdir64_r(DIR *dir, struct dirent64 *entry,
struct dirent64 **result)
__attribute__((alias("readdir_r")));

#undef readdir64
-extern "C" struct dirent *readdir64(DIR *dir) __attribute__((alias("readdir")));
+extern "C" OSV_LIBC_API struct dirent *readdir64(DIR *dir) __attribute__((alias("readdir")));

-void rewinddir(DIR *dirp)
+OSV_LIBC_API void rewinddir(DIR *dirp)
{
struct file *fp;

@@ -775,7 +776,7 @@ void rewinddir(DIR *dirp)
fdrop(fp);
}

-long telldir(DIR *dirp)
+OSV_LIBC_API long telldir(DIR *dirp)
{
struct file *fp;
int error = fget(dirp->fd, &fp);
@@ -792,7 +793,7 @@ long telldir(DIR *dirp)
return loc;
}

-void seekdir(DIR *dirp, long loc)
+OSV_LIBC_API void seekdir(DIR *dirp, long loc)
{
struct file *fp;
int error = fget(dirp->fd, &fp);
@@ -809,7 +810,7 @@ TRACEPOINT(trace_vfs_mkdir, "\"%s\" 0%0o", const char*, mode_t);
TRACEPOINT(trace_vfs_mkdir_ret, "");
TRACEPOINT(trace_vfs_mkdir_err, "%d", int);

-int
+OSV_LIBC_API int
mkdir(const char *pathname, mode_t mode)
{
struct task *t = main_task;
@@ -833,7 +834,7 @@ mkdir(const char *pathname, mode_t mode)
return -1;
}

-int mkdirat(int dirfd, const char *pathname, mode_t mode)
+OSV_LIBC_API int mkdirat(int dirfd, const char *pathname, mode_t mode)
{
mode = apply_umask(mode);

@@ -874,7 +875,7 @@ TRACEPOINT(trace_vfs_rmdir, "\"%s\"", const char*);
TRACEPOINT(trace_vfs_rmdir_ret, "");
TRACEPOINT(trace_vfs_rmdir_err, "%d", int);

-int rmdir(const char *pathname)
+OSV_LIBC_API int rmdir(const char *pathname)
{
struct task *t = main_task;
char path[PATH_MAX];
@@ -927,7 +928,7 @@ TRACEPOINT(trace_vfs_rename, "\"%s\" \"%s\"", const char*, const char*);
TRACEPOINT(trace_vfs_rename_ret, "");
TRACEPOINT(trace_vfs_rename_err, "%d", int);

-int rename(const char *oldpath, const char *newpath)
+OSV_LIBC_API int rename(const char *oldpath, const char *newpath)
{
trace_vfs_rename(oldpath, newpath);
struct task *t = main_task;
@@ -996,7 +997,7 @@ static int replace_cwd(struct task *t, struct file *new_cwdfp,
return error;
}

-int chdir(const char *pathname)
+OSV_LIBC_API int chdir(const char *pathname)
{
trace_vfs_chdir(pathname);
struct task *t = main_task;
@@ -1031,7 +1032,7 @@ TRACEPOINT(trace_vfs_fchdir, "%d", int);
TRACEPOINT(trace_vfs_fchdir_ret, "");
TRACEPOINT(trace_vfs_fchdir_err, "%d", int);

-int fchdir(int fd)
+OSV_LIBC_API int fchdir(int fd)
{
trace_vfs_fchdir(fd);
struct task *t = main_task;
@@ -1061,7 +1062,7 @@ TRACEPOINT(trace_vfs_link, "\"%s\" \"%s\"", const char*, const char*);
TRACEPOINT(trace_vfs_link_ret, "");
TRACEPOINT(trace_vfs_link_err, "%d", int);

-int link(const char *oldpath, const char *newpath)
+OSV_LIBC_API int link(const char *oldpath, const char *newpath)
{
struct task *t = main_task;
char path1[PATH_MAX];
@@ -1094,7 +1095,7 @@ TRACEPOINT(trace_vfs_symlink, "oldpath=%s, newpath=%s", const char*, const char*
TRACEPOINT(trace_vfs_symlink_ret, "");
TRACEPOINT(trace_vfs_symlink_err, "errno=%d", int);

-int symlink(const char *oldpath, const char *newpath)
+OSV_LIBC_API int symlink(const char *oldpath, const char *newpath)
{
int error;

@@ -1122,7 +1123,7 @@ TRACEPOINT(trace_vfs_unlink, "\"%s\"", const char*);
TRACEPOINT(trace_vfs_unlink_ret, "");
TRACEPOINT(trace_vfs_unlink_err, "%d", int);

-int unlink(const char *pathname)
+OSV_LIBC_API int unlink(const char *pathname)
{
trace_vfs_unlink(pathname);
struct task *t = main_task;
@@ -1146,7 +1147,7 @@ int unlink(const char *pathname)
return -1;
}

-int unlinkat(int dirfd, const char *pathname, int flags)
+OSV_LIBC_API int unlinkat(int dirfd, const char *pathname, int flags)
{
//TODO: Really implement it
if (dirfd != AT_FDCWD || flags) {
@@ -1160,7 +1161,7 @@ TRACEPOINT(trace_vfs_stat_ret, "");
TRACEPOINT(trace_vfs_stat_err, "%d", int);

extern "C"
-int __xstat(int ver, const char *pathname, struct stat *st)
+OSV_LIBC_API int __xstat(int ver, const char *pathname, struct stat *st)
{
struct task *t = main_task;
char path[PATH_MAX];
@@ -1186,7 +1187,7 @@ int __xstat(int ver, const char *pathname, struct stat *st)

LFS64(__xstat);

-int stat(const char *pathname, struct stat *st)
+OSV_LIBC_API int stat(const char *pathname, struct stat *st)
{
return __xstat(1, pathname, st);
}
@@ -1227,7 +1228,7 @@ struct statx {
extern "C" int statx(int dirfd, const char* pathname, int flags, unsigned int mask, struct statx *buf);
#define STATX_BASIC_STATS 0x000007ffU

-int statx(int dirfd, const char* pathname, int flags, unsigned int mask,
+OSV_LIBC_API int statx(int dirfd, const char* pathname, int flags, unsigned int mask,
struct statx *buf)
{
// This is a simplistic implementation which just calls the old fstatat()
@@ -1272,7 +1273,7 @@ TRACEPOINT(trace_vfs_lstat, "pathname=%s, stat=%p", const char*, struct stat*);
TRACEPOINT(trace_vfs_lstat_ret, "");
TRACEPOINT(trace_vfs_lstat_err, "errno=%d", int);
extern "C"
-int __lxstat(int ver, const char *pathname, struct stat *st)
+OSV_LIBC_API int __lxstat(int ver, const char *pathname, struct stat *st)
{
struct task *t = main_task;
char path[PATH_MAX];
@@ -1300,7 +1301,7 @@ int __lxstat(int ver, const char *pathname, struct stat *st)

LFS64(__lxstat);

-int lstat(const char *pathname, struct stat *st)
+OSV_LIBC_API int lstat(const char *pathname, struct stat *st)
{
return __lxstat(1, pathname, st);
}
@@ -1310,7 +1311,7 @@ TRACEPOINT(trace_vfs_statfs_ret, "");
TRACEPOINT(trace_vfs_statfs_err, "%d", int);

extern "C"
-int __statfs(const char *pathname, struct statfs *buf)
+OSV_LIBC_API int __statfs(const char *pathname, struct statfs *buf)
{
trace_vfs_statfs(pathname, buf);
struct task *t = main_task;
@@ -1331,7 +1332,7 @@ int __statfs(const char *pathname, struct statfs *buf)
errno = error;
return -1;
}
-weak_alias(__statfs, statfs);
+weak_alias(__statfs, statfs) OSV_LIBC_API;

TRACEPOINT(trace_vfs_fstatfs, "\"%s\" %p", int, struct statfs*);
TRACEPOINT(trace_vfs_fstatfs_ret, "");
@@ -1361,7 +1362,7 @@ int __fstatfs(int fd, struct statfs *buf)
errno = error;
return -1;
}
-weak_alias(__fstatfs, fstatfs);
+weak_alias(__fstatfs, fstatfs) OSV_LIBC_API;

static int
statfs_to_statvfs(struct statvfs *dst, struct statfs *src)
@@ -1380,7 +1381,7 @@ statfs_to_statvfs(struct statvfs *dst, struct statfs *src)
return 0;
}

-int
+OSV_LIBC_API int
statvfs(const char *pathname, struct statvfs *buf)
{
struct statfs st;
@@ -1390,7 +1391,7 @@ statvfs(const char *pathname, struct statvfs *buf)
return statfs_to_statvfs(buf, &st);
}

-int
+OSV_LIBC_API int
fstatvfs(int fd, struct statvfs *buf)
{
struct statfs st;
@@ -1404,7 +1405,7 @@ TRACEPOINT(trace_vfs_getcwd, "%p %d", char*, size_t);
TRACEPOINT(trace_vfs_getcwd_ret, "\"%s\"", const char*);
TRACEPOINT(trace_vfs_getcwd_err, "%d", int);

-char *getcwd(char *path, size_t size)
+OSV_LIBC_API char *getcwd(char *path, size_t size)
{
trace_vfs_getcwd(path, size);
struct task *t = main_task;
@@ -1447,7 +1448,7 @@ TRACEPOINT(trace_vfs_dup_err, "%d", int);
/*
* Duplicate a file descriptor
*/
-int dup(int oldfd)
+OSV_LIBC_API int dup(int oldfd)
{
struct file *fp;
int newfd;
@@ -1480,7 +1481,7 @@ TRACEPOINT(trace_vfs_dup3_err, "%d", int);
/*
* Duplicate a file descriptor to a particular value.
*/
-int dup3(int oldfd, int newfd, int flags)
+OSV_LIBC_API int dup3(int oldfd, int newfd, int flags)
{
struct file *fp;
int error;
@@ -1520,7 +1521,7 @@ int dup3(int oldfd, int newfd, int flags)
return -1;
}

-int dup2(int oldfd, int newfd)
+OSV_LIBC_API int dup2(int oldfd, int newfd)
{
if (oldfd == newfd)
return newfd;
@@ -1538,7 +1539,7 @@ TRACEPOINT(trace_vfs_fcntl_ret, "\"%s\"", int);
TRACEPOINT(trace_vfs_fcntl_err, "%d", int);

extern "C"
-int fcntl(int fd, int cmd, int arg)
+OSV_LIBC_API int fcntl(int fd, int cmd, int arg)
{
struct file *fp;
int ret = 0, error;
@@ -1632,7 +1633,7 @@ TRACEPOINT(trace_vfs_access_err, "%d", int);
/*
* Check permission for file access
*/
-int access(const char *pathname, int mode)
+OSV_LIBC_API int access(const char *pathname, int mode)
{
trace_vfs_access(pathname, mode);
struct task *t = main_task;
@@ -1659,7 +1660,7 @@ int access(const char *pathname, int mode)
return -1;
}

-int faccessat(int dirfd, const char *pathname, int mode, int flags)
+OSV_LIBC_API int faccessat(int dirfd, const char *pathname, int mode, int flags)
{
if (flags & AT_SYMLINK_NOFOLLOW) {
UNIMPLEMENTED("faccessat() with AT_SYMLINK_NOFOLLOW");
@@ -1697,12 +1698,12 @@ int faccessat(int dirfd, const char *pathname, int mode, int flags)
}

extern "C"
-int euidaccess(const char *pathname, int mode)
+OSV_LIBC_API int euidaccess(const char *pathname, int mode)
{
return access(pathname, mode);
}

-weak_alias(euidaccess,eaccess);
+weak_alias(euidaccess,eaccess) OSV_LIBC_API;

#if 0
static int
@@ -1756,7 +1757,7 @@ TRACEPOINT(trace_vfs_isatty_err, "%d", int);
/*
* Return if specified file is a tty
*/
-int isatty(int fd)
+OSV_LIBC_API int isatty(int fd)
{
struct file *fp;
int istty = 0;
@@ -1783,7 +1784,7 @@ TRACEPOINT(trace_vfs_truncate, "\"%s\" 0x%x", const char*, off_t);
TRACEPOINT(trace_vfs_truncate_ret, "");
TRACEPOINT(trace_vfs_truncate_err, "%d", int);

-int truncate(const char *pathname, off_t length)
+OSV_LIBC_API int truncate(const char *pathname, off_t length)
{
trace_vfs_truncate(pathname, length);
struct task *t = main_task;
@@ -1813,7 +1814,7 @@ TRACEPOINT(trace_vfs_ftruncate, "%d 0x%x", int, off_t);
TRACEPOINT(trace_vfs_ftruncate_ret, "");
TRACEPOINT(trace_vfs_ftruncate_err, "%d", int);

-int ftruncate(int fd, off_t length)
+OSV_LIBC_API int ftruncate(int fd, off_t length)
{
trace_vfs_ftruncate(fd, length);
struct file *fp;
@@ -1839,7 +1840,7 @@ int ftruncate(int fd, off_t length)

LFS64(ftruncate);

-ssize_t readlink(const char *pathname, char *buf, size_t bufsize)
+OSV_LIBC_API ssize_t readlink(const char *pathname, char *buf, size_t bufsize)
{
struct task *t = main_task;
char path[PATH_MAX];
@@ -1869,7 +1870,7 @@ ssize_t readlink(const char *pathname, char *buf, size_t bufsize)
return -1;
}

-ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsize)
+OSV_LIBC_API ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsize)
{
if (pathname[0] == '/' || dirfd == AT_FDCWD) {
return readlink(pathname, buf, bufsize);
@@ -1906,7 +1907,7 @@ TRACEPOINT(trace_vfs_fallocate, "%d %d 0x%x 0x%x", int, int, loff_t, loff_t);
TRACEPOINT(trace_vfs_fallocate_ret, "");
TRACEPOINT(trace_vfs_fallocate_err, "%d", int);

-int fallocate(int fd, int mode, loff_t offset, loff_t len)
+OSV_LIBC_API int fallocate(int fd, int mode, loff_t offset, loff_t len)
{
struct file *fp;
int error;
@@ -1936,12 +1937,12 @@ TRACEPOINT(trace_vfs_utimes, "\"%s\"", const char*);
TRACEPOINT(trace_vfs_utimes_ret, "");
TRACEPOINT(trace_vfs_utimes_err, "%d", int);

-int futimes(int fd, const struct timeval times[2])
+OSV_LIBC_API int futimes(int fd, const struct timeval times[2])
{
return futimesat(fd, nullptr, times);
}

-int futimesat(int dirfd, const char *pathname, const struct timeval times[2])
+OSV_LIBC_API int futimesat(int dirfd, const char *pathname, const struct timeval times[2])
{
struct stat st;
struct file *fp;
@@ -1999,7 +2000,7 @@ TRACEPOINT(trace_vfs_utimensat_ret, "");
TRACEPOINT(trace_vfs_utimensat_err, "%d", int);

extern "C"
-int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags)
+OSV_LIBC_API int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags)
{
trace_vfs_utimensat(pathname);

@@ -2019,7 +2020,7 @@ TRACEPOINT(trace_vfs_futimens_ret, "");
TRACEPOINT(trace_vfs_futimens_err, "%d", int);

extern "C"
-int futimens(int fd, const struct timespec times[2])
+OSV_LIBC_API int futimens(int fd, const struct timespec times[2])
{
trace_vfs_futimens(fd);

@@ -2059,19 +2060,19 @@ static int do_utimes(const char *pathname, const struct timeval times[2], int fl
}

extern "C"
-int utimes(const char *pathname, const struct timeval times[2])
+OSV_LIBC_API int utimes(const char *pathname, const struct timeval times[2])
{
return do_utimes(pathname, times, 0);
}

extern "C"
-int lutimes(const char *pathname, const struct timeval times[2])
+OSV_LIBC_API int lutimes(const char *pathname, const struct timeval times[2])
{
return do_utimes(pathname, times, AT_SYMLINK_NOFOLLOW);
}

extern "C"
-int utime(const char *pathname, const struct utimbuf *t)
+OSV_LIBC_API int utime(const char *pathname, const struct utimbuf *t)
{
using namespace std::chrono;

@@ -2094,7 +2095,7 @@ TRACEPOINT(trace_vfs_chmod, "\"%s\" 0%0o", const char*, mode_t);
TRACEPOINT(trace_vfs_chmod_ret, "");
TRACEPOINT(trace_vfs_chmod_err, "%d", int);

-int chmod(const char *pathname, mode_t mode)
+OSV_LIBC_API int chmod(const char *pathname, mode_t mode)
{
trace_vfs_chmod(pathname, mode);
struct task *t = main_task;
@@ -2118,7 +2119,7 @@ out_errno:
TRACEPOINT(trace_vfs_fchmod, "\"%d\" 0%0o", int, mode_t);
TRACEPOINT(trace_vfs_fchmod_ret, "");

-int fchmod(int fd, mode_t mode)
+OSV_LIBC_API int fchmod(int fd, mode_t mode)
{
trace_vfs_fchmod(fd, mode);
auto error = sys_fchmod(fd, mode & ALLPERMS);
@@ -2134,7 +2135,7 @@ int fchmod(int fd, mode_t mode)
TRACEPOINT(trace_vfs_fchown, "\"%d\" %d %d", int, uid_t, gid_t);
TRACEPOINT(trace_vfs_fchown_ret, "");

-int fchown(int fd, uid_t owner, gid_t group)
+OSV_LIBC_API int fchown(int fd, uid_t owner, gid_t group)
{
trace_vfs_fchown(fd, owner, group);
WARN_STUBBED();
@@ -2142,20 +2143,20 @@ int fchown(int fd, uid_t owner, gid_t group)
return 0;
}

-int chown(const char *path, uid_t owner, gid_t group)
+OSV_LIBC_API int chown(const char *path, uid_t owner, gid_t group)
{
WARN_STUBBED();
return 0;
}

-int lchown(const char *path, uid_t owner, gid_t group)
+OSV_LIBC_API int lchown(const char *path, uid_t owner, gid_t group)
{
WARN_STUBBED();
return 0;
}


-ssize_t sendfile(int out_fd, int in_fd, off_t *_offset, size_t count)
+OSV_LIBC_API ssize_t sendfile(int out_fd, int in_fd, off_t *_offset, size_t count)
{
struct file *in_fp;
struct file *out_fp;
@@ -2236,9 +2237,9 @@ ssize_t sendfile(int out_fd, int in_fd, off_t *_offset, size_t count)
#undef sendfile64
LFS64(sendfile);

-NO_SYS(int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags));
+NO_SYS(OSV_LIBC_API int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags));

-mode_t umask(mode_t newmask)
+OSV_LIBC_API mode_t umask(mode_t newmask)
{
return global_umask.exchange(newmask, std::memory_order_relaxed);
}
@@ -2249,7 +2250,7 @@ fs_noop(void)
return 0;
}

-int chroot(const char *path)
+OSV_LIBC_API int chroot(const char *path)
{
WARN_STUBBED();
errno = ENOSYS;
diff --git a/include/api/__fenv.h b/include/api/__fenv.h
index b0b67fb6..3726504d 100644
--- a/include/api/__fenv.h
+++ b/include/api/__fenv.h
@@ -5,9 +5,11 @@
extern "C" {
#endif

-int feenableexcept(int);
-int fedisableexcept(int);
-int fegetexcept(void);
+#include <osv/export.h>
+
+OSV_LIBM_API int feenableexcept(int);
+OSV_LIBM_API int fedisableexcept(int);
+OSV_LIBM_API int fegetexcept(void);

#ifdef __cplusplus
}
diff --git a/include/osv/sched.hh b/include/osv/sched.hh
index 27950ac3..2180fa62 100644
--- a/include/osv/sched.hh
+++ b/include/osv/sched.hh
@@ -25,6 +25,7 @@
#include <osv/rcu.hh>
#include <osv/clock.hh>
#include <osv/timer-set.hh>
+#include <osv/export.h>
#include <string.h>

typedef float runtime_t;
diff --git a/libc/eventfd.cc b/libc/eventfd.cc
index 3cfc86e1..60e08dd1 100644
--- a/libc/eventfd.cc
+++ b/libc/eventfd.cc
@@ -178,7 +178,7 @@ int event_fd::poll(int events)
return rc;
}

-int eventfd(unsigned int initval, int flags)
+OSV_LIBC_API int eventfd(unsigned int initval, int flags)
{
if (flags & (~(EFD_CLOEXEC | EFD_NONBLOCK | EFD_SEMAPHORE))) {
return libc_error(EINVAL);
@@ -209,7 +209,7 @@ int eventfd(unsigned int initval, int flags)
}
weak_alias(eventfd, eventfd2);

-int eventfd_read(int fd, eventfd_t *value)
+OSV_LIBC_API int eventfd_read(int fd, eventfd_t *value)
{
fileref f(fileref_from_fd(fd));
if (!f) {
@@ -231,7 +231,7 @@ int eventfd_read(int fd, eventfd_t *value)
return 0;
}

-int eventfd_write(int fd, eventfd_t value)
+OSV_LIBC_API int eventfd_write(int fd, eventfd_t value)
{
fileref f(fileref_from_fd(fd));
if (!f) {
diff --git a/libc/internal/libc.h b/libc/internal/libc.h
index bb2d7f6b..aa07ef48 100644
--- a/libc/internal/libc.h
+++ b/libc/internal/libc.h
@@ -3,6 +3,7 @@

#include <stdlib.h>
#include <osv/mutex.h>
+#include <osv/export.h>
#include "stdio.h"

__BEGIN_DECLS
@@ -49,7 +50,7 @@ extern char **__environ;
#endif

#undef LFS64_2
-#define LFS64_2(x, y) weak_alias(x, y)
+#define LFS64_2(x, y) weak_alias(x, y) OSV_LIBC_API

#undef LFS64
#define LFS64(x) LFS64_2(x, x##64)
diff --git a/libc/misc/getopt.cc b/libc/misc/getopt.cc
index 391fcd52..d6f046cd 100644
--- a/libc/misc/getopt.cc
+++ b/libc/misc/getopt.cc
@@ -8,11 +8,11 @@

extern "C" {

-char *optarg;
-int optind=1, opterr=1, optopt, __optpos, __optreset=0;
+OSV_LIBC_API char *optarg;
+OSV_LIBC_API int optind=1, opterr=1, optopt, __optpos, __optreset=0;

#define optpos __optpos
-weak_alias(__optreset, optreset);
+weak_alias(__optreset, optreset) OSV_LIBC_API;

int __getopt(int argc, char * const argv[], const char *optstring)
{
@@ -74,11 +74,11 @@ int __getopt(int argc, char * const argv[], const char *optstring)
return c;
}

-int getopt(int argc, char * const argv[], const char *optstring)
+OSV_LIBC_API int getopt(int argc, char * const argv[], const char *optstring)
{
getopt_caller_vars_copier guard;
return __getopt(argc, argv, optstring);
}

-weak_alias(getopt, __posix_getopt);
+weak_alias(getopt, __posix_getopt) OSV_LIBC_API;
}
diff --git a/libc/misc/getopt_long.cc b/libc/misc/getopt_long.cc
index cb124734..3bf67fdd 100644
--- a/libc/misc/getopt_long.cc
+++ b/libc/misc/getopt_long.cc
@@ -1,6 +1,7 @@
#include <stddef.h>
#include <getopt.h>
#include <stdio.h>
+#include <osv/export.h>
#include "getopt.hh"

extern "C" {
@@ -52,12 +53,12 @@ static int __getopt_long(int argc, char *const *argv, const char *optstring, con
return __getopt(argc, argv, optstring);
}

-int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
+OSV_LIBC_API int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
{
return __getopt_long(argc, argv, optstring, longopts, idx, 0);
}

-int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
+OSV_LIBC_API int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
{
return __getopt_long(argc, argv, optstring, longopts, idx, 1);
}
diff --git a/libc/misc/mntent.cc b/libc/misc/mntent.cc
index 6accaeac..8c52d734 100644
--- a/libc/misc/mntent.cc
+++ b/libc/misc/mntent.cc
@@ -76,7 +76,7 @@ int mtab_file::read(struct uio *uio, int flags)
return 0;
}

-FILE *setmntent(const char *name, const char *mode)
+OSV_LIBC_API FILE *setmntent(const char *name, const char *mode)
{
if (!strcmp(name, "/proc/mounts") || !strcmp(name, "/etc/mnttab") || !strcmp(name, "/etc/mtab")) {
if (strcmp("r", mode)) {
@@ -103,13 +103,13 @@ FILE *setmntent(const char *name, const char *mode)
return fopen(name, mode);
}

-int endmntent(FILE *f)
+OSV_LIBC_API int endmntent(FILE *f)
{
fclose(f);
return 1;
}

-struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen)
+OSV_LIBC_API struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen)
{
int cnt, n[8];

@@ -145,7 +145,7 @@ struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int bufle
return mnt;
}

-struct mntent *getmntent(FILE *f)
+OSV_LIBC_API struct mntent *getmntent(FILE *f)
{
static char linebuf[256];
static struct mntent mnt;
@@ -167,7 +167,7 @@ bool is_mtab_file(FILE *fp)
return true;
}

-int addmntent(FILE *f, const struct mntent *mnt)
+OSV_LIBC_API int addmntent(FILE *f, const struct mntent *mnt)
{
if (is_mtab_file(f)) {
return 1;
@@ -179,7 +179,7 @@ int addmntent(FILE *f, const struct mntent *mnt)
mnt->mnt_freq, mnt->mnt_passno) < 0;
}

-char *hasmntopt(const struct mntent *mnt, const char *opt)
+OSV_LIBC_API char *hasmntopt(const struct mntent *mnt, const char *opt)
{
return strstr(mnt->mnt_opts, opt);
}
diff --git a/libc/mman.cc b/libc/mman.cc
index 895b9b28..274d4dab 100644
--- a/libc/mman.cc
+++ b/libc/mman.cc
@@ -84,7 +84,7 @@ unsigned libc_madvise_to_advise(int advice)
return 0;
}

-int mprotect(void *addr, size_t len, int prot)
+OSV_LIBC_API int mprotect(void *addr, size_t len, int prot)
{
// we don't support mprotecting() the linear map (e.g.., malloc() memory)
// because that could leave the linear map a mess.
@@ -115,7 +115,7 @@ int mmap_validate(void *addr, size_t length, int flags, off_t offset)
return 0;
}

-void *mmap(void *addr, size_t length, int prot, int flags,
+OSV_LIBC_API void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset)
{
trace_memory_mmap(addr, length, prot, flags, fd, offset);
@@ -199,7 +199,7 @@ int munmap_validate(void *addr, size_t length)
return 0;
}

-int munmap(void *addr, size_t length)
+OSV_LIBC_API int munmap(void *addr, size_t length)
{
trace_memory_munmap(addr, length);
int error = munmap_validate(addr, length);
@@ -216,12 +216,12 @@ int munmap(void *addr, size_t length)
return ret;
}

-int msync(void *addr, size_t length, int flags)
+OSV_LIBC_API int msync(void *addr, size_t length, int flags)
{
return mmu::msync(addr, length, flags).to_libc();
}

-int mincore(void *addr, size_t length, unsigned char *vec)
+OSV_LIBC_API int mincore(void *addr, size_t length, unsigned char *vec)
{
if (!mmu::is_page_aligned(addr)) {
return libc_error(EINVAL);
@@ -230,20 +230,20 @@ int mincore(void *addr, size_t length, unsigned char *vec)
return mmu::mincore(addr, length, vec).to_libc();
}

-int madvise(void *addr, size_t length, int advice)
+OSV_LIBC_API int madvise(void *addr, size_t length, int advice)
{
auto err = mmu::advise(addr, length, libc_madvise_to_advise(advice));
return err.to_libc();
}

-int brk(void *addr)
+OSV_LIBC_API int brk(void *addr)
{
WARN_STUBBED();
errno = ENOMEM;
return -1;
}

-void *sbrk(intptr_t increment)
+OSV_LIBC_API void *sbrk(intptr_t increment)
{
WARN_STUBBED();
errno = ENOMEM;
diff --git a/libc/pipe.cc b/libc/pipe.cc
index ef10d9e7..bcda8bb7 100644
--- a/libc/pipe.cc
+++ b/libc/pipe.cc
@@ -86,7 +86,7 @@ int pipe_file::close()
return 0;
}

-int pipe2(int pipefd[2], int flags) {
+OSV_LIBC_API int pipe2(int pipefd[2], int flags) {
if (flags & ~(O_NONBLOCK | O_CLOEXEC)) {
return libc_error(EINVAL);
}
@@ -115,7 +115,7 @@ int pipe2(int pipefd[2], int flags) {
}
}

-int pipe(int pipefd[2])
+OSV_LIBC_API int pipe(int pipefd[2])
{
return pipe2(pipefd, 0);
}
diff --git a/libc/pthread.cc b/libc/pthread.cc
index 4e44082c..c75eaa39 100644
--- a/libc/pthread.cc
+++ b/libc/pthread.cc
@@ -29,6 +29,7 @@

#include <api/time.h>
#include <osv/rwlock.h>
+#include <osv/export.h>

#include "pthread.hh"

@@ -275,9 +276,9 @@ extern "C" int register_atfork(void (*prepare)(void), void (*parent)(void),

extern "C" {
int __register_atfork(void (*prepare)(void), void (*parent)(void),
- void (*child)(void), void *__dso_handle) __attribute__((alias("register_atfork")));
+ void (*child)(void), void *__dso_handle) __attribute__((alias("register_atfork"))) OSV_LIBC_API;
int __pthread_key_create(pthread_key_t* key, void (*dtor)(void*))
- __attribute__((alias("pthread_key_create")));
+ __attribute__((alias("pthread_key_create"))) OSV_LIBPTHREAD_API;
}


@@ -457,7 +458,7 @@ int pthread_mutex_unlock(pthread_mutex_t *m)
return 0;
}

-extern "C" int pthread_yield()
+extern "C" OSV_LIBPTHREAD_API int pthread_yield()
{
sched::thread::yield();
return 0;
@@ -528,7 +529,7 @@ int pthread_rwlock_unlock(pthread_rwlock_t *rw)
return 0;
}

-int pthread_sigmask(int how, const sigset_t* set, sigset_t* oldset)
+OSV_LIBC_API int pthread_sigmask(int how, const sigset_t* set, sigset_t* oldset)
{
return sigprocmask(how, set, oldset);
}
@@ -993,7 +994,7 @@ int pthread_getschedparam(pthread_t thread, int *policy,
return 0;
}

-int pthread_kill(pthread_t thread, int sig)
+OSV_LIBPTHREAD_API int pthread_kill(pthread_t thread, int sig)
{
// We are assuming that if pthread_kill() is called with thread
// equal to pthread_self(), then most likely it was called by
@@ -1011,7 +1012,7 @@ int pthread_kill(pthread_t thread, int sig)
return EINVAL;
}

-int raise(int sig)
+OSV_LIBPTHREAD_API int raise(int sig)
{
return pthread_kill(pthread_self(), sig);
}
diff --git a/libc/resource.cc b/libc/resource.cc
index b24a4ee1..d5f9470c 100644
--- a/libc/resource.cc
+++ b/libc/resource.cc
@@ -34,4 +34,3 @@ int getrusage(int who, struct rusage *usage)
}
return 0;
}
-LFS64(getrusage);
diff --git a/libc/sem.cc b/libc/sem.cc
index 9277d230..4e2fedc0 100644
--- a/libc/sem.cc
+++ b/libc/sem.cc
@@ -23,32 +23,32 @@ indirect_semaphore& from_libc(sem_t* p)
return *reinterpret_cast<indirect_semaphore*>(p);
}

-int sem_init(sem_t* s, int pshared, unsigned val)
+OSV_LIBC_API int sem_init(sem_t* s, int pshared, unsigned val)
{
static_assert(sizeof(indirect_semaphore) <= sizeof(*s), "sem_t overflow");
new (s) indirect_semaphore(val);
return 0;
}

-int sem_destroy(sem_t *s)
+OSV_LIBC_API int sem_destroy(sem_t *s)
{
from_libc(s).~indirect_semaphore();
return 0;
}

-int sem_post(sem_t* s)
+OSV_LIBC_API int sem_post(sem_t* s)
{
from_libc(s)->post();
return 0;
}

-int sem_wait(sem_t* s)
+OSV_LIBC_API int sem_wait(sem_t* s)
{
from_libc(s)->wait();
return 0;
}

-int sem_timedwait(sem_t* s, const struct timespec *abs_timeout)
+OSV_LIBC_API int sem_timedwait(sem_t* s, const struct timespec *abs_timeout)
{
if ((abs_timeout->tv_sec < 0) || (abs_timeout->tv_nsec < 0) || (abs_timeout->tv_nsec > 1000000000LL)) {
return libc_error(EINVAL);
@@ -64,7 +64,7 @@ int sem_timedwait(sem_t* s, const struct timespec *abs_timeout)
return 0;
}

-int sem_trywait(sem_t* s)
+OSV_LIBC_API int sem_trywait(sem_t* s)
{
if (!from_libc(s)->trywait())
return libc_error(EAGAIN);
diff --git a/libc/signal.cc b/libc/signal.cc
index f346552d..bf0940c4 100644
--- a/libc/signal.cc
+++ b/libc/signal.cc
@@ -19,6 +19,7 @@
#include <api/setjmp.h>
#include <osv/stubbing.hh>
#include <osv/pid.h>
+#include <osv/export.h>

using namespace osv::clock::literals;

@@ -148,36 +149,36 @@ void handle_mmap_fault(ulong addr, int sig, exception_frame* ef)

using namespace osv;

-int sigemptyset(sigset_t* sigset)
+OSV_LIBC_API int sigemptyset(sigset_t* sigset)
{
from_libc(sigset)->mask.reset();
return 0;
}

-int sigfillset(sigset_t *sigset)
+OSV_LIBC_API int sigfillset(sigset_t *sigset)
{
from_libc(sigset)->mask.set();
return 0;
}

-int sigaddset(sigset_t *sigset, int signum)
+OSV_LIBC_API int sigaddset(sigset_t *sigset, int signum)
{
from_libc(sigset)->mask.set(signum);
return 0;
}

-int sigdelset(sigset_t *sigset, int signum)
+OSV_LIBC_API int sigdelset(sigset_t *sigset, int signum)
{
from_libc(sigset)->mask.reset(signum);
return 0;
}

-int sigismember(const sigset_t *sigset, int signum)
+OSV_LIBC_API int sigismember(const sigset_t *sigset, int signum)
{
return from_libc(sigset)->mask.test(signum);
}

-int sigprocmask(int how, const sigset_t* _set, sigset_t* _oldset)
+OSV_LIBC_API int sigprocmask(int how, const sigset_t* _set, sigset_t* _oldset)
{
auto set = from_libc(_set);
auto oldset = from_libc(_oldset);
@@ -218,9 +219,9 @@ int sigprocmask(int how, const sigset_t* _set, sigset_t* _oldset)
return 0;
}

-UNIMPL(int sigsuspend(const sigset_t *mask));
+UNIMPL(OSV_LIBC_API int sigsuspend(const sigset_t *mask));

-int sigaction(int signum, const struct sigaction* act, struct sigaction* oldact)
+OSV_LIBC_API int sigaction(int signum, const struct sigaction* act, struct sigaction* oldact)
{
// FIXME: We do not support any sa_flags besides SA_SIGINFO.
if (signum < 0 || signum >= (int)nsignals) {
@@ -256,20 +257,20 @@ static sighandler_t signal(int signum, sighandler_t handler, int sa_flags)
}
}

-sighandler_t signal(int signum, sighandler_t handler)
+OSV_LIBC_API sighandler_t signal(int signum, sighandler_t handler)
{
return signal(signum, handler, SA_RESTART);
}

extern "C"
-sighandler_t __sysv_signal(int signum, sighandler_t handler)
+OSV_LIBC_API sighandler_t __sysv_signal(int signum, sighandler_t handler)
{
return signal(signum, handler, SA_RESETHAND | SA_NODEFER);
}

// using sigignore() and friends is not recommended as it is obsolete System V
// APIs. Nevertheless, some programs use it.
-int sigignore(int signum)
+OSV_LIBC_API int sigignore(int signum)
{
struct sigaction act;
act.sa_flags = 0;
@@ -278,7 +279,7 @@ int sigignore(int signum)
return sigaction(signum, &act, nullptr);
}

-int sigwait(const sigset_t *set, int *sig)
+OSV_LIBC_API int sigwait(const sigset_t *set, int *sig)
{
sched::thread::wait_until([sig] { return *sig = thread_pending_signal; });
thread_pending_signal = 0;
@@ -306,7 +307,7 @@ int sigwait(const sigset_t *set, int *sig)
// another handler thread. We should probably block this signal while
// handling it.

-int kill(pid_t pid, int sig)
+OSV_LIBC_API int kill(pid_t pid, int sig)
{
// OSv only implements one process, whose pid is getpid().
// Sending a signal to pid 0 or -1 is also fine, as it will also send a
@@ -368,7 +369,7 @@ int kill(pid_t pid, int sig)
return 0;
}

-int pause(void) {
+OSV_LIBC_API int pause(void) {
try
{
sched::thread::wait_until_interruptible([] {return false;});
@@ -561,7 +562,7 @@ void cancel_this_thread_alarm()
itimer_virt.cancel_this_thread();
}

-unsigned int alarm(unsigned int seconds)
+OSV_LIBC_API unsigned int alarm(unsigned int seconds)
{
unsigned int ret;
struct itimerval old_value{}, new_value{};
@@ -579,7 +580,7 @@ unsigned int alarm(unsigned int seconds)
return ret;
}

-extern "C" int setitimer(int which, const struct itimerval *new_value,
+extern "C" OSV_LIBC_API int setitimer(int which, const struct itimerval *new_value,
struct itimerval *old_value)
{
switch (which) {
@@ -592,7 +593,7 @@ extern "C" int setitimer(int which, const struct itimerval *new_value,
}
}

-extern "C" int getitimer(int which, struct itimerval *curr_value)
+extern "C" OSV_LIBC_API int getitimer(int which, struct itimerval *curr_value)
{
switch (which) {
case ITIMER_REAL:
@@ -617,7 +618,7 @@ extern "C" int getitimer(int which, struct itimerval *curr_value)
static __thread void* signal_stack_begin;
static __thread size_t signal_stack_size;

-int sigaltstack(const stack_t *ss, stack_t *oss)
+OSV_LIBC_API int sigaltstack(const stack_t *ss, stack_t *oss)
{
if (oss) {
if (signal_stack_begin) {
@@ -649,14 +650,14 @@ int sigaltstack(const stack_t *ss, stack_t *oss)
return 0;
}

-extern "C" int signalfd(int fd, const sigset_t *mask, int flags)
+extern "C" OSV_LIBC_API int signalfd(int fd, const sigset_t *mask, int flags)
{
WARN_STUBBED();
errno = ENOSYS;
return -1;
}

-extern "C" int sigwaitinfo(const sigset_t *__restrict mask,
+extern "C" OSV_LIBC_API int sigwaitinfo(const sigset_t *__restrict mask,
siginfo_t *__restrict si)
{
int signo;
diff --git a/libc/time.cc b/libc/time.cc
index 8aa11580..ef198f73 100644
--- a/libc/time.cc
+++ b/libc/time.cc
@@ -21,7 +21,7 @@ u64 convert(const timespec& ts)
}

extern "C"
-int gettimeofday(struct timeval* tv, struct timezone* tz)
+OSV_LIBC_API int gettimeofday(struct timeval* tv, struct timezone* tz)
{
if (!tv) {
return 0;
@@ -33,13 +33,13 @@ int gettimeofday(struct timeval* tv, struct timezone* tz)
return 0;
}

-int nanosleep(const struct timespec* req, struct timespec* rem)
+OSV_LIBC_API int nanosleep(const struct timespec* req, struct timespec* rem)
{
sched::thread::sleep(std::chrono::nanoseconds(convert(*req)));
return 0;
}

-int usleep(useconds_t usec)
+OSV_LIBC_API int usleep(useconds_t usec)
{
sched::thread::sleep(std::chrono::microseconds(usec));
return 0;
@@ -55,7 +55,7 @@ static inline void fill_ts(std::chrono::duration<Rep, Period> d, timespec *ts)
ts->tv_nsec = duration_cast<nanoseconds>(d).count() % 1000000000;
}

-int clock_gettime(clockid_t clk_id, struct timespec* ts)
+OSV_LIBC_API int clock_gettime(clockid_t clk_id, struct timespec* ts)
{
switch (clk_id) {
case CLOCK_BOOTTIME:
@@ -86,9 +86,9 @@ int clock_gettime(clockid_t clk_id, struct timespec* ts)
}

extern "C"
-int __clock_gettime(clockid_t clk_id, struct timespec* ts) __attribute__((alias("clock_gettime")));
+OSV_LIBC_API int __clock_gettime(clockid_t clk_id, struct timespec* ts) __attribute__((alias("clock_gettime")));

-int clock_getres(clockid_t clk_id, struct timespec* ts)
+OSV_LIBC_API int clock_getres(clockid_t clk_id, struct timespec* ts)
{
switch (clk_id) {
case CLOCK_REALTIME:
@@ -110,12 +110,12 @@ int clock_getres(clockid_t clk_id, struct timespec* ts)
return 0;
}

-int clock_getcpuclockid(pid_t pid, clockid_t* clock_id)
+OSV_LIBC_API int clock_getcpuclockid(pid_t pid, clockid_t* clock_id)
{
return CLOCK_PROCESS_CPUTIME_ID;
}

-clock_t clock(void)
+OSV_LIBC_API clock_t clock(void)
{
struct timespec ts;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
diff --git a/libc/timerfd.cc b/libc/timerfd.cc
index 70500dca..99939c17 100644
--- a/libc/timerfd.cc
+++ b/libc/timerfd.cc
@@ -229,7 +229,7 @@ int timerfd::poll(int events)
// After this long introduction, without further ado, let's implement Linux's
// three <sys/timerfd.h> functions:

-int timerfd_create(int clockid, int flags) {
+OSV_LIBC_API int timerfd_create(int clockid, int flags) {
switch (clockid) {
case CLOCK_REALTIME:
case CLOCK_MONOTONIC:
@@ -258,7 +258,7 @@ static bool check_nsec_validity(long nsec)
return (nsec >= 0 && nsec < second);
}

-int timerfd_settime(int fd, int flags, const itimerspec *newval,
+OSV_LIBC_API int timerfd_settime(int fd, int flags, const itimerspec *newval,
itimerspec *oldval)
{
fileref f(fileref_from_fd(fd));
@@ -301,7 +301,7 @@ int timerfd_settime(int fd, int flags, const itimerspec *newval,
return 0;
}

-int timerfd_gettime(int fd, itimerspec *val)
+OSV_LIBC_API int timerfd_gettime(int fd, itimerspec *val)
{
fileref f(fileref_from_fd(fd));
if (!f) {
diff --git a/linux.cc b/linux.cc
index adeb89f0..1c2eea24 100644
--- a/linux.cc
+++ b/linux.cc
@@ -13,6 +13,7 @@
#include <osv/mutex.h>
#include <osv/waitqueue.hh>
#include <osv/stubbing.hh>
+#include <osv/export.h>
#include <memory>

#include <syscall.h>
@@ -44,7 +45,7 @@

extern "C" int eventfd2(unsigned int, int);

-extern "C" long gettid()
+extern "C" OSV_LIBC_API long gettid()
{
return sched::thread::current()->id();
}
@@ -408,7 +409,7 @@ static int tgkill(int tgid, int tid, int sig)
return -1;
}

-long syscall(long number, ...)
+OSV_LIBC_API long syscall(long number, ...)
{
// Save FPU state and restore it at the end of this function
sched::fpu_lock fpu;
diff --git a/runtime.cc b/runtime.cc
index 3335552d..3f6c4ec8 100644
--- a/runtime.cc
+++ b/runtime.cc
@@ -33,6 +33,7 @@
#include <osv/debug.hh>
#include <boost/format.hpp>
#include <osv/mempool.hh>
+#include <osv/export.h>
#include <pwd.h>
#include <fcntl.h>
#include <osv/barrier.hh>
@@ -71,10 +72,6 @@

#define __LC_LAST 13

-#define __ALIAS(old, new) \
- __typeof(old) new __attribute__((alias(#old)))
-#define ALIAS(old, new) extern "C" __ALIAS(old, new)
-
void *__dso_handle;

static void print_backtrace(void)
@@ -142,7 +139,7 @@ void abort(const char *fmt, ...)
}

// __assert_fail() is used by the assert() macros
-void __assert_fail(const char *expr, const char *file, unsigned int line, const char *func)
+OSV_LIBC_API void __assert_fail(const char *expr, const char *file, unsigned int line, const char *func)
{
abort("Assertion failed: %s (%s: %s: %d)\n", expr, file, func, line);
}
@@ -194,60 +191,59 @@ void __cxa_finalize(void *dso)
}
}

-int getpagesize()
+OSV_LIBC_API int getpagesize()
{
return 4096;
}
-ALIAS(getpagesize, __getpagesize);

-int vfork()
+OSV_LIBC_API int vfork()
{
WARN_STUBBED();
return -1;
}

-int fork()
+OSV_LIBC_API int fork()
{
WARN_STUBBED();
return -1;
}

-pid_t setsid(void)
+OSV_LIBC_API pid_t setsid(void)
{
WARN_STUBBED();
return -1;
}

-NO_SYS(int execvp(const char *, char *const []));
+NO_SYS(OSV_LIBC_API int execvp(const char *, char *const []));

-int mlockall(int flags)
+OSV_LIBC_API int mlockall(int flags)
{
WARN_STUBBED();
return 0;
}

-int munlockall(void)
+OSV_LIBC_API int munlockall(void)
{
WARN_STUBBED();
return 0;
}

-int mlock(const void*, size_t)
+OSV_LIBC_API int mlock(const void*, size_t)
{
WARN_STUBBED();
return 0;
}

-int munlock(const void*, size_t)
+OSV_LIBC_API int munlock(const void*, size_t)
{
WARN_STUBBED();
return 0;
}

-NO_SYS(int mkfifo(const char*, mode_t));
-NO_SYS(int mkfifoat(int, const char *, mode_t));
+NO_SYS(OSV_LIBC_API int mkfifo(const char*, mode_t));
+NO_SYS(OSV_LIBC_API int mkfifoat(int, const char *, mode_t));

-int posix_fadvise(int fd, off_t offset, off_t len, int advice)
+OSV_LIBC_API int posix_fadvise(int fd, off_t offset, off_t len, int advice)
{
switch (advice) {
case POSIX_FADV_NORMAL:
@@ -261,15 +257,15 @@ int posix_fadvise(int fd, off_t offset, off_t len, int advice)
return EINVAL;
}
}
-LFS64(posix_fadvise);
+LFS64(posix_fadvise) __attribute__((nothrow));

-int posix_fallocate(int fd, off_t offset, off_t len)
+OSV_LIBC_API int posix_fallocate(int fd, off_t offset, off_t len)
{
return ENOSYS;
}
-LFS64(posix_fallocate);
+LFS64(posix_fallocate) __attribute__((nothrow));

-int getpid()
+OSV_LIBC_API int getpid()
{
return OSV_PID;
}
@@ -290,8 +286,8 @@ static struct __locale_struct c_locale = {

locale_t __c_locale_ptr = &c_locale;

-void* __stack_chk_guard = reinterpret_cast<void*>(0x12345678abcdefull);
-extern "C" void __stack_chk_fail(void) {
+OSV_LIBC_API void* __stack_chk_guard = reinterpret_cast<void*>(0x12345678abcdefull);
+extern "C" OSV_LIBC_API void __stack_chk_fail(void) {
abort("__stack_chk_fail(): Stack overflow detected. Aborting.\n");
}

@@ -315,7 +311,7 @@ struct __locale_data {
#define _NL_CTYPE_TOLOWER 3

extern "C"
-__locale_t __newlocale(int category_mask, const char *locale, locale_t base)
+OSV_LIBC_API __locale_t __newlocale(int category_mask, const char *locale, locale_t base)
__THROW
{
if (category_mask == 1 << LC_ALL) {
@@ -346,9 +342,7 @@ __locale_t __newlocale(int category_mask, const char *locale, locale_t base)
return nullptr;
}

-ALIAS(__newlocale, newlocale);
-
-long sysconf(int name)
+OSV_LIBC_API long sysconf(int name)
{
switch (name) {
case _SC_CLK_TCK: return CLOCKS_PER_SEC;
@@ -370,18 +364,18 @@ long sysconf(int name)
}
}

-long pathconf(const char *, int name)
+OSV_LIBC_API long pathconf(const char *, int name)
{
return fpathconf(-1, name);
}

-long fpathconf(int, int)
+OSV_LIBC_API long fpathconf(int, int)
{
WARN_STUBBED();
return -1;
}

-size_t confstr(int name, char* buf, size_t len)
+OSV_LIBC_API size_t confstr(int name, char* buf, size_t len)
{
const char* v = nullptr;
switch (name) {
@@ -403,13 +397,13 @@ size_t confstr(int name, char* buf, size_t len)
}
}

-FILE *popen(const char *command, const char *type)
+OSV_LIBC_API FILE *popen(const char *command, const char *type)
{
WARN_STUBBED();
return NULL;
}

-int pclose(FILE *stream)
+OSV_LIBC_API int pclose(FILE *stream)
{
return 0;
}
@@ -423,22 +417,19 @@ void exit(int status)
// "The function _exit() is like exit(3), but does not call any functions
// registered with atexit(3) or on_exit(3)."
//
-// Since we do nothing for those anyway, they are equal.
-ALIAS(exit, _exit);
-ALIAS(exit, _Exit);

-int atexit(void (*func)())
+OSV_LIBC_API int atexit(void (*func)())
{
// nothing to do
return 0;
}

-int get_nprocs()
+OSV_LIBC_API int get_nprocs()
{
return sysconf(_SC_NPROCESSORS_ONLN);
}

-clock_t times(struct tms *buffer)
+OSV_LIBC_API clock_t times(struct tms *buffer)
{
using namespace std::chrono;
struct timespec ts;
@@ -503,7 +494,7 @@ static int prio_find_thread(sched::thread **th, int which, int id)
//
static constexpr float prio_k = log(86) / 20;

-int getpriority(int which, int id)
+OSV_LIBC_API int getpriority(int which, int id)
{
sched::thread *th;
int ret = prio_find_thread(&th, which, id);
@@ -530,7 +521,7 @@ int getpriority(int which, int id)
return prio;
}

-int setpriority(int which, int id, int prio)
+OSV_LIBC_API int setpriority(int which, int id, int prio)
{
sched::thread *th;
int ret = prio_find_thread(&th, which, id);
@@ -546,13 +537,13 @@ int setpriority(int which, int id, int prio)
return 0;
}

-int initgroups(const char *user, gid_t group)
+OSV_LIBC_API int initgroups(const char *user, gid_t group)
{
WARN_STUBBED();
return -1;
}

-int prctl(int option, ...)
+OSV_LIBC_API int prctl(int option, ...)
{
switch (option) {
case PR_SET_DUMPABLE:
@@ -562,14 +553,14 @@ int prctl(int option, ...)
return -1;
}

-int daemon(int nochdir, int noclose)
+OSV_LIBC_API int daemon(int nochdir, int noclose)
{
WARN_STUBBED();
return -1;
}

extern "C"
-int sysctl(int *, int, void *, size_t *, void *, size_t)
+OSV_LIBC_API int sysctl(int *, int, void *, size_t *, void *, size_t)
{
WARN_STUBBED();
errno = ENOTDIR;
@@ -577,40 +568,40 @@ int sysctl(int *, int, void *, size_t *, void *, size_t)
}

extern "C"
-char *tmpnam_r(char *s)
+OSV_LIBC_API char *tmpnam_r(char *s)
{
return s ? tmpnam(s) : NULL;
}

-pid_t wait3(int *status, int options, struct rusage *usage)
+OSV_LIBC_API pid_t wait3(int *status, int options, struct rusage *usage)
{
WARN_STUBBED();
errno = ECHILD;
return -1;
}

-pid_t wait4(pid_t pid, int *status, int options, struct rusage *usage)
+OSV_LIBC_API pid_t wait4(pid_t pid, int *status, int options, struct rusage *usage)
{
WARN_STUBBED();
errno = ECHILD;
return -1;
}

-int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
+OSV_LIBC_API int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
{
WARN_STUBBED();
errno = ENOSYS;
return -1;
}

-int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
+OSV_LIBC_API int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
{
WARN_STUBBED();
errno = ENOSYS;
return -1;
}

-int openpty(int *amaster, int *aslave, char *name,
+OSV_LIBUTIL_API int openpty(int *amaster, int *aslave, char *name,
const struct termios *termp,
const struct winsize *winp)
{
@@ -619,7 +610,7 @@ int openpty(int *amaster, int *aslave, char *name,
return -1;
}

-pid_t forkpty(int *amaster, char *name,
+OSV_LIBUTIL_API pid_t forkpty(int *amaster, char *name,
const struct termios *termp,
const struct winsize *winp)
{
@@ -628,12 +619,12 @@ pid_t forkpty(int *amaster, char *name,
return -1;
}

-int nice(int inc)
+OSV_LIBC_API int nice(int inc)
{
return setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS, 0)+inc);
}

-char *ctermid(char *s)
+OSV_LIBC_API char *ctermid(char *s)
{
static char s2[L_ctermid];
WARN_STUBBED();
@@ -643,4 +634,4 @@ char *ctermid(char *s)
}

// OSv is always multi-threaded.
-char __libc_single_threaded = 0;
+OSV_LIBC_API char __libc_single_threaded = 0;
--
2.31.1

Waldemar Kozaczuk

unread,
Nov 21, 2021, 4:09:48 AM11/21/21
to osv...@googlegroups.com, Waldemar Kozaczuk
This last patch in the series annotates some symbols in few
files that need to be hidden regardless if we compile kernel with
non-glibc symbols hidden or not. For that we use OSV_HIDDEN_API macro.

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
---
libc/libc.cc | 2 +-
libc/libc.hh | 3 ++-
libc/locale/uselocale.c | 2 +-
libc/misc/uname.c | 3 ++-
4 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/libc/libc.cc b/libc/libc.cc
index b75b3867..4fb7d574 100644
--- a/libc/libc.cc
+++ b/libc/libc.cc
@@ -43,7 +43,7 @@ int libc_error(int err)

#undef errno

-int __thread errno;
+OSV_HIDDEN int __thread errno;

int* __errno_location()
{
diff --git a/libc/libc.hh b/libc/libc.hh
index cf345ce8..bba4a0a6 100644
--- a/libc/libc.hh
+++ b/libc/libc.hh
@@ -10,8 +10,9 @@

#include <errno.h>
#include "internal/libc.h" // for the macros
+#include <osv/export.h>

-int libc_error(int err);
+OSV_HIDDEN int libc_error(int err);

template <typename T>
T* libc_error_ptr(int err);
diff --git a/libc/locale/uselocale.c b/libc/locale/uselocale.c
index 93e65e21..bbdae028 100644
--- a/libc/locale/uselocale.c
+++ b/libc/locale/uselocale.c
@@ -1,7 +1,7 @@
#include "locale_impl.h"
#include "libc.h"

-__thread locale_t __current_locale;
+OSV_HIDDEN __thread locale_t __current_locale;

locale_t __uselocale(locale_t l)
{
diff --git a/libc/misc/uname.c b/libc/misc/uname.c
index f7770ddf..3f1bf754 100644
--- a/libc/misc/uname.c
+++ b/libc/misc/uname.c
@@ -7,6 +7,7 @@

#include <sys/utsname.h>
#include <string.h>
+#include "osv/export.h"

// The Linux version we're pretending to be
#define LINUX_MAJOR 3
@@ -23,7 +24,7 @@ _Static_assert(KERNEL_VERSION(LINUX_MAJOR, LINUX_MINOR, LINUX_PATCH)
#define str(s) #s
#define str2(s) str(s)

-struct utsname utsname = {
+struct utsname utsname OSV_HIDDEN = {
.sysname = "Linux", /* lie, to avoid confusing the payload. */
.nodename = "osv.local",
.release = str2(LINUX_MAJOR) "." str2(LINUX_MINOR) "." str2(LINUX_PATCH),
--
2.31.1

Nadav Har'El

unread,
Nov 22, 2021, 9:48:04 AM11/22/21
to Waldemar Kozaczuk, Osv Dev
You refer to "compatibility flag" a few times in this comment, and I didn't understand
what it means. Compatibility with what?
 
+// as all symbols in this case are exposed as public. So either way, the symbols
+// annotated with these macros yield desired effect.
+// We do not really need to define a macro for each Linux glibc library and we could
+// have had single OSV_GLIBC_API macro instead of eight ones below. However by
+// having a macro for each library shared file where a symbol is part of,
+// we automatically self-document the code and in future could auto-generate some
+// docs.
+#define OSV_LIBAIO_API __attribute__((__visibility__("default")))
+#define OSV_LIBC_API __attribute__((__visibility__("default")))
+#define OSV_LIBM_API __attribute__((__visibility__("default")))
+#define OSV_LIBBSD_API __attribute__((__visibility__("default")))
+#define OSV_LIBPTHREAD_API __attribute__((__visibility__("default")))
+#define OSV_LIBUTIL_API __attribute__((__visibility__("default")))
+#define OSV_LIBXENSTORE_API __attribute__((__visibility__("default")))
+#define OSV_LD_LINUX_x86_64_API __attribute__((__visibility__("default")))
+
+// In some very few cases, when source files are compiled without compatibility
+// flag in order to expose most symbols in the corresponding file, there are some specific
+// symbols in the same file that we want to hide and this is where we use this macro.
+// Regardless if we hide most symbols in the kernel or not, the annotated symbols would
+// be always hidden.
+#define OSV_HIDDEN __attribute__((__visibility__("hidden")))

In commit 815398537f665fca72b4c2040a6f70262d597ac5 you added, following musl,
the macro "hidden", in lowercase. Maybe we should use that instead of the uglier OSV_HIDDEN?
Or maybe "hidden" is too short/lowercase? But then again, we already have it...

+
+#endif /* EXPORT_H */
--
2.31.1

--
You received this message because you are subscribed to the Google Groups "OSv Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/osv-dev/20211121090925.22630-1-jwkozaczuk%40gmail.com.

Nadav Har'El

unread,
Nov 22, 2021, 10:27:20 AM11/22/21
to Waldemar Kozaczuk, Osv Dev
On Sun, Nov 21, 2021 at 11:09 AM Waldemar Kozaczuk <jwkoz...@gmail.com> wrote:
This last patch in the series annotates some symbols in few
files that need to be hidden regardless if we compile kernel with
non-glibc symbols hidden or not.

I see only a couple of these cases. Why did you need to do those specific cases?

 
For that we use OSV_HIDDEN_API macro.

OSV_HIDDEN.

--
You received this message because you are subscribed to the Google Groups "OSv Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+u...@googlegroups.com.

Waldek Kozaczuk

unread,
Nov 25, 2021, 6:57:29 AM11/25/21
to OSv Development
I meant the "visibility" instead. I will update the comments in the new version of the patch. 
 
+// as all symbols in this case are exposed as public. So either way, the symbols
+// annotated with these macros yield desired effect.
+// We do not really need to define a macro for each Linux glibc library and we could
+// have had single OSV_GLIBC_API macro instead of eight ones below. However by
+// having a macro for each library shared file where a symbol is part of,
+// we automatically self-document the code and in future could auto-generate some
+// docs.
+#define OSV_LIBAIO_API __attribute__((__visibility__("default")))
+#define OSV_LIBC_API __attribute__((__visibility__("default")))
+#define OSV_LIBM_API __attribute__((__visibility__("default")))
+#define OSV_LIBBSD_API __attribute__((__visibility__("default")))
+#define OSV_LIBPTHREAD_API __attribute__((__visibility__("default")))
+#define OSV_LIBUTIL_API __attribute__((__visibility__("default")))
+#define OSV_LIBXENSTORE_API __attribute__((__visibility__("default")))
+#define OSV_LD_LINUX_x86_64_API __attribute__((__visibility__("default")))

I think I should have explained more explicitly what really each of those above is. Each macro above does the same thing but by putting a specific one next to a given symbol, we mean that this symbol is defined in one of the Linux library files which are advertised in core/elf.cc:

          "libresolv.so.2"
          "libc.so.6"
          "libm.so.6"
          "ld-linux-x86-64.so.2" // or ld-linux-aarch64.so.1"
          "libc.musl-x86_64.so.1"
          "libboost_system.so.1.55.0"
          "libpthread.so.0"
          "libdl.so.2"
          "librt.so.1"
          "libstdc++.so.6"
          "libaio.so.1"
          "libxenstore.so.3.0"
          "libcrypt.so.1"

So symbol annotated with OSV_LIBXENSTORE_API is physically located in "libxenstore.so.3.0",  OSV_LIBC_AP in  "libc.so.6" shared library on Linux, etc. I hope this will address some of your questions/concerns in other related patches.
 
+
+// In some very few cases, when source files are compiled without compatibility
+// flag in order to expose most symbols in the corresponding file, there are some specific
+// symbols in the same file that we want to hide and this is where we use this macro.
+// Regardless if we hide most symbols in the kernel or not, the annotated symbols would
+// be always hidden.
+#define OSV_HIDDEN __attribute__((__visibility__("hidden")))

In commit 815398537f665fca72b4c2040a6f70262d597ac5 you added, following musl,
the macro "hidden", in lowercase. Maybe we should use that instead of the uglier OSV_HIDDEN?
Or maybe "hidden" is too short/lowercase? But then again, we already have it...
You are correct that I added "hidden" macro in that commit. But this is really a musl macro defined in mush src/include/features.h:

#define hidden __attribute__((__visibility__("hidden")))

which I copied into OSv include/glibc-compat/features.h as such.

So the "hidden" is used in musl sources (typically headers) or under our libc/ folder where we still have some versions of original musl files.

I thought it would be wise not to use musl "hidden" macro and instead define OSv one (OSV_HIDDEN) and use it in truly OSv files. What if "hidden" changes what it means in the future version of musl?

Waldek Kozaczuk

unread,
Nov 25, 2021, 6:58:54 AM11/25/21
to OSv Development
On Monday, November 22, 2021 at 10:27:20 AM UTC-5 Nadav Har'El wrote:
On Sun, Nov 21, 2021 at 11:09 AM Waldemar Kozaczuk <jwkoz...@gmail.com> wrote:
This last patch in the series annotates some symbols in few
files that need to be hidden regardless if we compile kernel with
non-glibc symbols hidden or not.

I see only a couple of these cases. Why did you need to do those specific cases?
To hide those specific symbols as they should not be visible to the apps. 

 
For that we use OSV_HIDDEN_API macro.

OSV_HIDDEN.
Right. 

Waldek Kozaczuk

unread,
Nov 25, 2021, 7:25:01 AM11/25/21
to Nadav Har'El, OSv Development
On Mon, Nov 22, 2021 at 10:25 AM Nadav Har'El <n...@scylladb.com> wrote:
On Sun, Nov 21, 2021 at 11:09 AM Waldemar Kozaczuk <jwkoz...@gmail.com> wrote:
I'm not familiar with those "visibility" things, is it customary to put them in the header file (like you did here), or the source file?

Musl does it mostly in header files but also in some *c files. I think whatever is more convenient.

It seems to me that we won't want to change most header files, so it will make more sense to put the visibility flag in the source file, not header file.
I think it is debatable. 

But I have a more important question about this mtx_* stuff:

As far as I know, mtx_lock is NOT a part of posix threads library as you seem to suggest with the OSV_LIBPTHREAD_API macro.
Instead, it is part of C11 (not C++11, but C11! see https://en.cppreference.com/w/c/thread/mtx_lock).

But, did you verify that specific implementation actually fits C11's requirements? We added it to port BSD code, which predated C11 by many years. We should verify that it actually fits the needs of C11 before advertising that we support it.

This is interesting. As I noted in my 1st patch reply, the OSV_LIBPTHREAD_API means only that the mtx_* symbols are found in the libpthread.so.0 shared library (in my case on Fedora in /usr/lib64/libpthread.so.0). Whether it is "logically" part of pthread library that I do not know:

nm -CD /usr/lib64/libpthread.so.0 | grep mtx_lock
00000000000158f0 T mtx_lock@@GLIBC_2.28

But I think you are right, that our (OSv) version of mtx_* may not be the same as the C11 ones. They are intended and used in freebsd code of OSv (https://www.freebsd.org/cgi/man.cgi?query=mtx_lock&apropos=0&sektion=9&manpath=FreeBSD+9.3-RELEASE+and+Ports&format=html).

But having said all that those symbols are ALREADY exposed anyway now. So if some app really depends and uses the C11 mtx_lock and runs on OSv, it will end up using OSv freebsd version anyway which mught be wrong as you indicated. But my patch does not make it any worse. Maybe it exposes it as a problem and you are right we should investigate it.

Should we hide those symbols?

 
 void mtx_assert(struct mtx *mp, int flag);

 void sx_init(struct sx *m, const char *name);
diff --git a/bsd/sys/kern/uipc_syscalls_wrap.cc b/bsd/sys/kern/uipc_syscalls_wrap.cc
index ca666ca2..720cab35 100644
--- a/bsd/sys/kern/uipc_syscalls_wrap.cc
+++ b/bsd/sys/kern/uipc_syscalls_wrap.cc
@@ -5,6 +5,7 @@

 #include <bsd/uipc_syscalls.h>
 #include <osv/debug.h>
+#include <osv/export.h>
 #include "libc/af_local.h"

 #include "libc/internal/libc.h"
@@ -12,7 +13,7 @@
 #define sock_d(...)            tprintf_d("socket-api", __VA_ARGS__);

 extern "C"
-int socketpair(int domain, int type, int protocol, int sv[2])
+OSV_LIBC_API int socketpair(int domain, int type, int protocol, int sv[2])

nitpick (but feel free to disagree) -
wouldn't it be less "ugly" if the OSV_LIBC_API string appeared on the extern "C" line, so the function begins with "int socketpair" and easier to read?
I think you are right, but I might need to change it in all 300 places so I am not sure how I feel about tweaking it. 

 {

Again, I wonder if it's not better to put these OSV_LIBC_API where the functions are defined, in the
source file - not here where they are declared.
I have the same question again below, but I won't repeat it.
I think I have addressed it in one of my replies. 
Why do we want to export a "libbsd api"?
Maybe we shouldn't, considering we are probably missing a lot of BSD stuff and never intended to supply them?
Even more importantly, whenever BSD and Linux differ in APIs, OSv took the Linux approach. So it is unlikely we'll ever want to run unmodify BSD applications on Scylla.

Again this means that arc4random() is located in the "libbsd.so.0" (see https://libbsd.freedesktop.org/wiki/ and https://gitlab.freedesktop.org/libbsd/libbsd). This is a library that is intended to exist on the Linux side to help run bsd ports. We should also add it to core/elf.cc.

So I think your concern does not apply here, does it?

I have the same question again below, but won't repeat it.
What is "libxenstore" and why do we want to export anything from it?
The symbol is located in the libxenstore.so.3.0 file on Linux host. See core/elf.cc
Wow, I never noticed this libutil.so before.
Looking at it now, I see it has forkpty(), login(), login_tty(), logout(), logwtmp(), openpty().

I see we have openpty() and forkpty() stub, but it seems to be missing the "extern C" so it won't work :-(
Curiously they did have "extern C" when they were added e15edaa5f7f2b663aea953b19acc114e26f9b770 - so how did we lose them?
As far as I can tell, we don't have any of the other functions.
I have to check it. 

     };

     auto ml = new modules_list();
     ml->objects.push_back(_core.get());
@@ -1877,7 +1879,7 @@ char *object::setup_tls()
 }

 extern "C"
-void* __tls_get_addr(module_and_offset* mao)
+OSV_LD_LINUX_x86_64_API void* __tls_get_addr(module_and_offset* mao)

Nice, I never noticed this came from /lib64/ld-linux-x86-64.so.2

 
 {
Maybe we should use this opportunity to move such aliases to aliases.ld.
We could also make the normal function called statfs and the __statfs be its alias.
But we don't have to do it now.
Maybe later. But you are right. The aliases.ld is so much better. 
Good, I suggested to remove these in my review of the previous patch :-)
Why did you remove or move the alias but not the comment that went a long with it?
My bad. 

--
You received this message because you are subscribed to the Google Groups "OSv Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+u...@googlegroups.com.

Nadav Har'El

unread,
Nov 25, 2021, 8:13:16 AM11/25/21
to Waldek Kozaczuk, OSv Development
On Thu, Nov 25, 2021 at 2:24 PM Waldek Kozaczuk <jwkoz...@gmail.com> wrote:


On Mon, Nov 22, 2021 at 10:25 AM Nadav Har'El <n...@scylladb.com> wrote:


I'm not familiar with those "visibility" things, is it customary to put them in the header file (like you did here), or the source file?

Musl does it mostly in header files but also in some *c files. I think whatever is more convenient.

It seems to me that we won't want to change most header files, so it will make more sense to put the visibility flag in the source file, not header file.
I think it is debatable. 

I think that ideally, we would have liked to take unmodified header files from someone defining the API, such as musl, so we wouldn't want to modify the header files to includes various OSV_LIB_SOMETING macros - but the source files are completely under our own control.
Maybe it also depends on which header is being discussed - some we already modified a lot, and some we didn't.

But I think it will be confusing if in *some cases* the OSV_LIB_SOMETHING will appear in the header file, and sometimes in the source file. A reader who wants to know if something is exported won't know where to look.

 

But I have a more important question about this mtx_* stuff:

As far as I know, mtx_lock is NOT a part of posix threads library as you seem to suggest with the OSV_LIBPTHREAD_API macro.
Instead, it is part of C11 (not C++11, but C11! see https://en.cppreference.com/w/c/thread/mtx_lock).

But, did you verify that specific implementation actually fits C11's requirements? We added it to port BSD code, which predated C11 by many years. We should verify that it actually fits the needs of C11 before advertising that we support it.

This is interesting. As I noted in my 1st patch reply, the OSV_LIBPTHREAD_API means only that the mtx_* symbols are found in the libpthread.so.0 shared library (in my case on Fedora in /usr/lib64/libpthread.so.0). Whether it is "logically" part of pthread library that I do not know:

nm -CD /usr/lib64/libpthread.so.0 | grep mtx_lock
00000000000158f0 T mtx_lock@@GLIBC_2.28

But I think you are right, that our (OSv) version of mtx_* may not be the same as the C11 ones. They are intended and used in freebsd code of OSv (https://www.freebsd.org/cgi/man.cgi?query=mtx_lock&apropos=0&sektion=9&manpath=FreeBSD+9.3-RELEASE+and+Ports&format=html).

But having said all that those symbols are ALREADY exposed anyway now. So if some app really depends and uses the C11 mtx_lock and runs on OSv, it will end up using OSv freebsd version anyway which mught be wrong as you indicated. But my patch does not make it any worse. Maybe it exposes it as a problem and you are right we should investigate it.

Should we hide those symbols?

I think that symbols that don't have a manual page on Linux are a good candidate to be hidden - at least until someone wants them. But your call.

Waldemar Kozaczuk

unread,
Nov 27, 2021, 8:34:06 PM11/27/21
to osv...@googlegroups.com, Waldemar Kozaczuk
This 2nd patch in the series annotates number of standard glibc symbols
across number of source files, mostly under bsd, core, fs and libc
folders. This does not have any effect until we introduce the changes to
the makefile to support compiling kernel with most symbols hidden.

We choose to annotate the symbols that need to be exposed because the relevant files
will be compiled with the flag '-fvisibility=hidden' which would hide
all symbols unless annotated otherwise which takes precedence. This
approach helps to minimize the number of symbols that need to be annotated.
certain files

Comparing to the version 1 of this patch, this one differs in the following
ways:
- removes changes made to bsd/sys/netinet/in.n, bsd/sys/rpc/xdr.h,
bsd/sys/sys/md5.h and bsd/sys/sys/libkern.h to avoid exposing symbols
originating from FreeBSD kernel that may not be completely compatible
with Linux
- moves some of the OSV_*API annotation from header files to the source
files

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
---
arch/aarch64/feexcept.cc | 7 +-
arch/x64/feexcept.cc | 4 +
bsd/sys/kern/uipc_syscalls_wrap.cc | 37 ++++-----
bsd/sys/xen/xenstore/xenstore.cc | 10 ++-
core/app.cc | 5 +-
core/elf.cc | 6 +-
core/epoll.cc | 6 ++
core/libaio.cc | 10 ++-
core/math.cc | 13 ++--
core/mempool.cc | 7 +-
core/poll.cc | 5 +-
core/power.cc | 2 +
core/select.cc | 6 +-
fs/vfs/kern_descrip.cc | 3 +-
fs/vfs/main.cc | 118 +++++++++++++++++++++++------
include/osv/export.h | 1 -
include/osv/sched.hh | 1 +
libc/eventfd.cc | 3 +
libc/internal/libc.h | 3 +-
libc/misc/getopt.cc | 7 +-
libc/misc/getopt_long.cc | 3 +
libc/misc/mntent.cc | 6 ++
libc/mman.cc | 8 ++
libc/pipe.cc | 2 +
libc/pthread.cc | 11 ++-
libc/resource.cc | 1 -
libc/sem.cc | 6 ++
libc/signal.cc | 30 ++++++--
libc/time.cc | 10 ++-
libc/timerfd.cc | 3 +
linux.cc | 5 +-
runtime.cc | 56 +++++++++++---
32 files changed, 305 insertions(+), 90 deletions(-)

diff --git a/arch/aarch64/feexcept.cc b/arch/aarch64/feexcept.cc
index 9b0e9eec..31f87101 100644
--- a/arch/aarch64/feexcept.cc
+++ b/arch/aarch64/feexcept.cc
@@ -36,6 +36,7 @@
#include <sys/types.h>
#include <fenv.h>
#include <__fenv.h>
+#include <osv/export.h>
// Note that musl's fenv.h does not define feenableexcept and friends, so
// we need to 'extern "C"' them here, as no header file does this.

@@ -55,7 +56,7 @@ typedef __uint64_t _fenv_t;
#define __mrs_fpsr(__r) __asm __volatile("mrs %0, fpsr" : "=r" (__r))
#define __msr_fpsr(__r) __asm __volatile("msr fpsr, %0" : : "r" (__r))

-extern "C"
+extern "C" OSV_LIBM_API
int feenableexcept(int mask)
{
_fenv_t __old_r, __new_r;
@@ -66,7 +67,7 @@ int feenableexcept(int mask)
return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
}

-extern "C"
+extern "C" OSV_LIBM_API
int fedisableexcept(int mask)
{
_fenv_t __old_r, __new_r;
@@ -77,7 +78,7 @@ int fedisableexcept(int mask)
return ((__old_r >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
}

-extern "C"
+extern "C" OSV_LIBM_API
int fegetexcept()
{
_fenv_t __r;
diff --git a/arch/x64/feexcept.cc b/arch/x64/feexcept.cc
index fd07ad2a..68c098cd 100644
--- a/arch/x64/feexcept.cc
+++ b/arch/x64/feexcept.cc
@@ -8,7 +8,9 @@
#include <osv/types.h>
#include <fenv.h>
#include <__fenv.h>
+#include <osv/export.h>

+OSV_LIBM_API
int feenableexcept(int mask)
{
// The feenableexcept() manual page suggests that -1 should be returned
@@ -38,6 +40,7 @@ int feenableexcept(int mask)
return ret;
}

+OSV_LIBM_API
int fedisableexcept(int mask)
{
mask &= FE_ALL_EXCEPT;
@@ -56,6 +59,7 @@ int fedisableexcept(int mask)
return ret;
}

+OSV_LIBM_API
int fegetexcept()
{
u16 cw;
diff --git a/bsd/sys/kern/uipc_syscalls_wrap.cc b/bsd/sys/kern/uipc_syscalls_wrap.cc
index ca666ca2..d7a9bd82 100644
--- a/bsd/sys/kern/uipc_syscalls_wrap.cc
+++ b/bsd/sys/kern/uipc_syscalls_wrap.cc
@@ -5,13 +5,14 @@

#include <bsd/uipc_syscalls.h>
#include <osv/debug.h>
+#include <osv/export.h>
#include "libc/af_local.h"

#include "libc/internal/libc.h"

#define sock_d(...) tprintf_d("socket-api", __VA_ARGS__);

-extern "C"
+extern "C" OSV_LIBC_API
int socketpair(int domain, int type, int protocol, int sv[2])
{
int error;
@@ -32,7 +33,7 @@ int socketpair(int domain, int type, int protocol, int sv[2])
return 0;
}

-extern "C"
+extern "C" OSV_LIBC_API
int getsockname(int sockfd, struct bsd_sockaddr *addr, socklen_t *addrlen)
{
int error;
@@ -49,7 +50,7 @@ int getsockname(int sockfd, struct bsd_sockaddr *addr, socklen_t *addrlen)
return 0;
}

-extern "C"
+extern "C" OSV_LIBC_API
int getpeername(int sockfd, struct bsd_sockaddr *addr, socklen_t *addrlen)
{
int error;
@@ -66,7 +67,7 @@ int getpeername(int sockfd, struct bsd_sockaddr *addr, socklen_t *addrlen)
return 0;
}

-extern "C"
+extern "C" OSV_LIBC_API
int accept4(int fd, struct bsd_sockaddr *__restrict addr, socklen_t *__restrict len, int flg)
{
int fd2, error;
@@ -83,7 +84,7 @@ int accept4(int fd, struct bsd_sockaddr *__restrict addr, socklen_t *__restrict
return fd2;
}

-extern "C"
+extern "C" OSV_LIBC_API
int accept(int fd, struct bsd_sockaddr *__restrict addr, socklen_t *__restrict len)
{
int fd2, error;
@@ -100,7 +101,7 @@ int accept(int fd, struct bsd_sockaddr *__restrict addr, socklen_t *__restrict l
return fd2;
}

-extern "C"
+extern "C" OSV_LIBC_API
int bind(int fd, const struct bsd_sockaddr *addr, socklen_t len)
{
int error;
@@ -117,7 +118,7 @@ int bind(int fd, const struct bsd_sockaddr *addr, socklen_t len)
return 0;
}

-extern "C"
+extern "C" OSV_LIBC_API
int connect(int fd, const struct bsd_sockaddr *addr, socklen_t len)
{
int error;
@@ -134,7 +135,7 @@ int connect(int fd, const struct bsd_sockaddr *addr, socklen_t len)
return 0;
}

-extern "C"
+extern "C" OSV_LIBC_API
int listen(int fd, int backlog)
{
int error;
@@ -151,7 +152,7 @@ int listen(int fd, int backlog)
return 0;
}

-extern "C"
+extern "C" OSV_LIBC_API
ssize_t recvfrom(int fd, void *__restrict buf, size_t len, int flags,
struct bsd_sockaddr *__restrict addr, socklen_t *__restrict alen)
{
@@ -171,7 +172,7 @@ ssize_t recvfrom(int fd, void *__restrict buf, size_t len, int flags,
return bytes;
}

-extern "C"
+extern "C" OSV_LIBC_API
ssize_t recv(int fd, void *buf, size_t len, int flags)
{
int error;
@@ -189,7 +190,7 @@ ssize_t recv(int fd, void *buf, size_t len, int flags)
return bytes;
}

-extern "C"
+extern "C" OSV_LIBC_API
ssize_t recvmsg(int fd, struct msghdr *msg, int flags)
{
ssize_t bytes;
@@ -207,7 +208,7 @@ ssize_t recvmsg(int fd, struct msghdr *msg, int flags)
return bytes;
}

-extern "C"
+extern "C" OSV_LIBC_API
ssize_t sendto(int fd, const void *buf, size_t len, int flags,
const struct bsd_sockaddr *addr, socklen_t alen)
{
@@ -227,7 +228,7 @@ ssize_t sendto(int fd, const void *buf, size_t len, int flags,
return bytes;
}

-extern "C"
+extern "C" OSV_LIBC_API
ssize_t send(int fd, const void *buf, size_t len, int flags)
{
int error;
@@ -245,7 +246,7 @@ ssize_t send(int fd, const void *buf, size_t len, int flags)
return bytes;
}

-extern "C"
+extern "C" OSV_LIBC_API
ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)
{
ssize_t bytes;
@@ -263,7 +264,7 @@ ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)
return bytes;
}

-extern "C"
+extern "C" OSV_LIBC_API
int getsockopt(int fd, int level, int optname, void *__restrict optval,
socklen_t *__restrict optlen)
{
@@ -281,7 +282,7 @@ int getsockopt(int fd, int level, int optname, void *__restrict optval,
return 0;
}

-extern "C"
+extern "C" OSV_LIBC_API
int setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)
{
int error;
@@ -299,7 +300,7 @@ int setsockopt(int fd, int level, int optname, const void *optval, socklen_t opt
return 0;
}

-extern "C"
+extern "C" OSV_LIBC_API
int shutdown(int fd, int how)
{
int error;
@@ -322,7 +323,7 @@ int shutdown(int fd, int how)
return 0;
}

-extern "C"
+extern "C" OSV_LIBC_API
int socket(int domain, int type, int protocol)
{
int s, error;
diff --git a/bsd/sys/xen/xenstore/xenstore.cc b/bsd/sys/xen/xenstore/xenstore.cc
index e345f218..5cdd2cc2 100644
--- a/bsd/sys/xen/xenstore/xenstore.cc
+++ b/bsd/sys/xen/xenstore/xenstore.cc
@@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$");

#include <xen/xenstore/xenstorevar.h>
#include <xen/xenstore/xenstore_internal.h>
+#include <osv/export.h>

#include <vm/vm.h>
#include <vm/pmap.h>
@@ -1316,6 +1317,7 @@ public:

/*-------------------------------- Public API --------------------------------*/
/*------- API comments for these methods can be found in xenstorevar.h -------*/
+OSV_LIBXENSTORE_API
const char **
xs_directory(void *op, struct xs_transaction t, const char *path, u_int *num)
{
@@ -1360,6 +1362,7 @@ xs_exists(struct xs_transaction t, const char *dir, const char *node)
return (1);
}

+OSV_LIBXENSTORE_API
char *
xs_read(void *op, struct xs_transaction t, const char *path, u_int *len)
{
@@ -1387,6 +1390,7 @@ xs_read(struct xs_transaction t, const char *dir, const char *node,
return 0;
}

+OSV_LIBXENSTORE_API
int
xs_write(void *op, struct xs_transaction t, const char *path, const char *string)
{
@@ -1403,11 +1407,13 @@ xs_write(void *op, struct xs_transaction t, const char *path, const char *string
return (error);
}

+OSV_LIBXENSTORE_API
void *xs_daemon_open()
{
return (void *)-1;
}

+OSV_LIBXENSTORE_API
void xs_close(void *h)
{
}
@@ -1433,7 +1439,7 @@ xs_mkdir(struct xs_transaction t, const char *dir, const char *node)
return (ret);
}

-
+OSV_LIBXENSTORE_API
int
xs_rm(void *op, struct xs_transaction t, const char *path)
{
@@ -1562,6 +1568,7 @@ xs_transaction_start(struct xs_transaction *t)
return (error);
}

+OSV_LIBXENSTORE_API
int
xs_transaction_start(void *h)
{
@@ -1583,6 +1590,7 @@ xs_transaction_end(struct xs_transaction t, int abort)
return (xs_single(t, XS_TRANSACTION_END, abortstr, NULL, NULL));
}

+OSV_LIBXENSTORE_API
int
xs_transaction_end(void *h, struct xs_transaction t, int abort)
{
diff --git a/core/app.cc b/core/app.cc
index e124353d..fe018e09 100644
--- a/core/app.cc
+++ b/core/app.cc
@@ -11,6 +11,7 @@
#include <osv/run.hh>
#include <osv/power.hh>
#include <osv/trace.hh>
+#include <osv/export.h>
#include <functional>
#include <thread>
#include <libgen.h>
@@ -26,9 +27,11 @@ extern int optind;

// Java uses this global variable (supplied by Glibc) to figure out
// aproximatively where the initial thread's stack end.
+OSV_LD_LINUX_x86_64_API
void *__libc_stack_end;

-extern "C" void __libc_start_main(int (*main)(int, char**), int, char**,
+extern "C" OSV_LIBC_API
+void __libc_start_main(int (*main)(int, char**), int, char**,
void(*)(), void(*)(), void(*)(), void*)
{
auto app = osv::application::get_current();
diff --git a/core/elf.cc b/core/elf.cc
index ad2fcf5a..80bfd841 100644
--- a/core/elf.cc
+++ b/core/elf.cc
@@ -26,6 +26,7 @@
#include <osv/stubbing.hh>
#include <sys/utsname.h>
#include <osv/demangle.hh>
+#include <osv/export.h>
#include <boost/version.hpp>
#include <deque>

@@ -1325,6 +1326,7 @@ program::program(void* addr)
"libaio.so.1",
"libxenstore.so.3.0",
"libcrypt.so.1",
+ "libutil.so",
};
auto ml = new modules_list();
ml->objects.push_back(_core.get());
@@ -1876,7 +1878,7 @@ char *object::setup_tls()
_module_index, _tls_segment, _tls_init_size, _tls_uninit_size);
}

-extern "C"
+extern "C" OSV_LD_LINUX_x86_64_API
void* __tls_get_addr(module_and_offset* mao)
{
#ifdef AARCH64_PORT_STUB
@@ -1901,7 +1903,7 @@ void* __tls_get_addr(module_and_offset* mao)
// also uses a static area for uname, we can just return that.
extern utsname utsname;

-extern "C"
+extern "C" OSV_LIBC_API
unsigned long getauxval(unsigned long type)
{
switch (type) {
diff --git a/core/epoll.cc b/core/epoll.cc
index 3978d19d..f22ff449 100644
--- a/core/epoll.cc
+++ b/core/epoll.cc
@@ -21,6 +21,7 @@
#include <boost/lockfree/policies.hpp>

#include <osv/debug.hh>
+#include <osv/export.h>
#include <unordered_map>
#include <boost/range/algorithm/find.hpp>
#include <algorithm>
@@ -248,6 +249,7 @@ public:
}
};

+OSV_LIBC_API
int epoll_create(int size)
{
// Note we ignore the size parameter. There's no point in checking it's
@@ -256,6 +258,7 @@ int epoll_create(int size)
return epoll_create1(0);
}

+OSV_LIBC_API
int epoll_create1(int flags)
{
flags &= ~EPOLL_CLOEXEC;
@@ -272,6 +275,7 @@ int epoll_create1(int flags)
}
}

+OSV_LIBC_API
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
{
trace_epoll_ctl(epfd, fd,
@@ -321,6 +325,7 @@ int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
}
}

+OSV_LIBC_API
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout_ms)
{
trace_epoll_wait(epfd, maxevents, timeout_ms);
@@ -339,6 +344,7 @@ int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout_
return epo->wait(events, maxevents, timeout_ms);
}

+OSV_LIBC_API
int epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout_ms,
const sigset_t *sigmask)
{
diff --git a/core/libaio.cc b/core/libaio.cc
index 34d7bfa7..700309a4 100644
--- a/core/libaio.cc
+++ b/core/libaio.cc
@@ -11,7 +11,9 @@
#include <api/libaio.h>

#include <osv/stubbing.hh>
+#include <osv/export.h>

+OSV_LIBAIO_API
int io_setup(int nr_events, io_context_t *ctxp_idp) {
// This is a stub that doesn't actually do anything. If the caller tries
// to follow the io_setup() call with any other libaio call, those will
@@ -23,8 +25,8 @@ int io_setup(int nr_events, io_context_t *ctxp_idp) {
return 0;
}

-UNIMPL(int io_submit(io_context_t ctx, long nr, struct iocb *ios[]))
-UNIMPL(int io_getevents(io_context_t ctx_id, long min_nr, long nr,
+UNIMPL(OSV_LIBAIO_API int io_submit(io_context_t ctx, long nr, struct iocb *ios[]))
+UNIMPL(OSV_LIBAIO_API int io_getevents(io_context_t ctx_id, long min_nr, long nr,
struct io_event *events, struct timespec *timeout))
-UNIMPL(int io_destroy(io_context_t ctx))
-UNIMPL(int io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt))
+UNIMPL(OSV_LIBAIO_API int io_destroy(io_context_t ctx))
+UNIMPL(OSV_LIBAIO_API int io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt))
diff --git a/core/math.cc b/core/math.cc
index 3abce08e..08a7aee5 100644
--- a/core/math.cc
+++ b/core/math.cc
@@ -7,40 +7,41 @@

#include <math.h>
#include <osv/types.h>
+#include <osv/export.h>
#include <cmath>
#include <ctgmath>

-extern "C"
+extern "C" OSV_LIBC_API
int __isnan(double v)
{
return std::isnan(v);
}

-extern "C"
+extern "C" OSV_LIBC_API
int __isnanf(float v)
{
return std::isnan(v);
}

-extern "C"
+extern "C" OSV_LIBC_API
int __isnanl(long double v)
{
return std::isnan(v);
}

-extern "C"
+extern "C" OSV_LIBC_API
int __isinf(double v)
{
return std::isinf(v);
}

-extern "C"
+extern "C" OSV_LIBC_API
int __isinff(float v)
{
return std::isinf(v);
}

-extern "C"
+extern "C" OSV_LIBC_API
int __isinfl(double v)
{
return std::isinf(v);
diff --git a/core/mempool.cc b/core/mempool.cc
index c85bc2be..22918193 100644
--- a/core/mempool.cc
+++ b/core/mempool.cc
@@ -35,6 +35,7 @@
#include <boost/lockfree/stack.hpp>
#include <boost/lockfree/policies.hpp>
#include <osv/migration-lock.hh>
+#include <osv/export.h>

TRACEPOINT(trace_memory_malloc, "buf=%p, len=%d, align=%d", void *, size_t,
size_t);
@@ -2010,6 +2011,7 @@ void* malloc(size_t size)
return buf;
}

+OSV_LIBC_API
void* realloc(void* obj, size_t size)
{
void* buf = std_realloc(obj, size);
@@ -2017,7 +2019,8 @@ void* realloc(void* obj, size_t size)
return buf;
}

-extern "C" void *reallocarray(void *ptr, size_t nmemb, size_t elem_size)
+extern "C" OSV_LIBC_API
+void *reallocarray(void *ptr, size_t nmemb, size_t elem_size)
{
size_t bytes;
if (__builtin_mul_overflow(nmemb, elem_size, &bytes)) {
@@ -2027,6 +2030,7 @@ extern "C" void *reallocarray(void *ptr, size_t nmemb, size_t elem_size)
return realloc(ptr, nmemb * elem_size);
}

+OSV_LIBC_API
size_t malloc_usable_size(void* obj)
{
if ( obj == nullptr ) {
@@ -2079,6 +2083,7 @@ void *aligned_alloc(size_t alignment, size_t size)
// that size be a multiple of alignment.
// memalign() is considered to be an obsolete SunOS-ism, but Linux's glibc
// supports it, and some applications still use it.
+OSV_LIBC_API
void *memalign(size_t alignment, size_t size)
{
return aligned_alloc(alignment, size);
diff --git a/core/poll.cc b/core/poll.cc
index cd968e4f..48b45677 100644
--- a/core/poll.cc
+++ b/core/poll.cc
@@ -48,6 +48,7 @@

#include <osv/file.h>
#include <osv/poll.h>
+#include <osv/export.h>
#include <sys/epoll.h>

#include <bsd/porting/netport.h>
@@ -334,6 +335,7 @@ static int poll_one(struct pollfd& pfd, file::timeout_t timeout)
return fref->poll_sync(pfd, timeout);
}

+OSV_LIBC_API
int poll(struct pollfd _pfd[], nfds_t _nfds, int _timeout)
{
trace_poll(_pfd, _nfds, _timeout);
@@ -357,6 +359,7 @@ int poll(struct pollfd _pfd[], nfds_t _nfds, int _timeout)
return ret;
}

+OSV_LIBC_API
int ppoll(struct pollfd *fds, nfds_t nfds,
const struct timespec *timeout_ts, const sigset_t *sigmask)
{
@@ -371,7 +374,7 @@ int ppoll(struct pollfd *fds, nfds_t nfds,
return ret;
}
/* Used by code compiled on Linux with -D_FORTIFY_SOURCE */
-extern "C"
+extern "C" OSV_LIBC_API
int __poll_chk (struct pollfd _pfd[], nfds_t _nfds, int _timeout, size_t pdflen)
{
assert(pdflen / sizeof (_pfd[0]) >= _nfds);
diff --git a/core/power.cc b/core/power.cc
index a228e771..3e230aa3 100644
--- a/core/power.cc
+++ b/core/power.cc
@@ -7,6 +7,7 @@

#include <osv/power.hh>
#include <osv/debug.hh>
+#include <osv/export.h>
#include <smp.hh>
#include <processor.hh>
#include <arch.hh>
@@ -20,6 +21,7 @@
// is questionable (e.g., abort()) so a debug() call might call further
// problems.

+OSV_LIBC_API
int reboot(int cmd)
{
switch (cmd) {
diff --git a/core/select.cc b/core/select.cc
index b40904e2..043a96cd 100644
--- a/core/select.cc
+++ b/core/select.cc
@@ -10,6 +10,7 @@
#include <errno.h>
#include <signal.h>
#include <osv/poll.h>
+#include <osv/export.h>
#include <osv/debug.h>
#include <api/sys/select.h>
#include <bsd/porting/synch.h>
@@ -17,6 +18,7 @@
#define select_d(...) tprintf_d("select", __VA_ARGS__)

/* Basic select() implementation on top of poll() */
+OSV_LIBC_API
int select (int nfds,
fd_set * readfds,
fd_set * writefds,
@@ -184,6 +186,7 @@ int select (int nfds,
}

/* Basic pselect() on top of select() */
+OSV_LIBC_API
int pselect(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, const struct timespec *timeout_ts,
const sigset_t *sigmask)
@@ -203,7 +206,8 @@ int pselect(int nfds, fd_set *readfds, fd_set *writefds,
return ret;
}

-extern "C" unsigned long int
+extern "C" OSV_LIBC_API
+unsigned long int
__fdelt_chk (unsigned long int d)
{
if (d >= FD_SETSIZE)
diff --git a/fs/vfs/kern_descrip.cc b/fs/vfs/kern_descrip.cc
index cd8dc771..b1206719 100644
--- a/fs/vfs/kern_descrip.cc
+++ b/fs/vfs/kern_descrip.cc
@@ -14,6 +14,7 @@
#include <osv/debug.h>
#include <osv/mutex.h>
#include <osv/rcu.hh>
+#include <osv/export.h>
#include <boost/range/algorithm/find.hpp>

#include <bsd/sys/sys/queue.h>
@@ -61,7 +62,7 @@ int _fdalloc(struct file *fp, int *newfd, int min_fd)
return EMFILE;
}

-extern "C"
+extern "C" OSV_LIBC_API
int getdtablesize(void)
{
return FDMAX;
diff --git a/fs/vfs/main.cc b/fs/vfs/main.cc
index 116c3f20..ca357cc8 100644
--- a/fs/vfs/main.cc
+++ b/fs/vfs/main.cc
@@ -56,6 +56,7 @@
#include <dlfcn.h>

#include <osv/prex.h>
+#include <osv/export.h>
#include <osv/vnode.h>
#include <osv/stubbing.hh>
#include <osv/ioctl.h>
@@ -102,7 +103,7 @@ TRACEPOINT(trace_vfs_open_err, "%d", int);

struct task *main_task; /* we only have a single process */

-extern "C"
+extern "C" OSV_LIBC_API
int open(const char *pathname, int flags, ...)
{
mode_t mode = 0;
@@ -159,6 +160,7 @@ int open(const char *pathname, int flags, ...)

LFS64(open);

+OSV_LIBC_API
int openat(int dirfd, const char *pathname, int flags, ...)
{
mode_t mode = 0;
@@ -205,13 +207,15 @@ LFS64(openat);
// some cases (when the O_CREAT mode is used). As a safety feature, recent
// versions of Glibc add a feature where open() with two arguments is replaced
// by a call to __open_2(), which verifies it isn't called with O_CREATE.
-extern "C" int __open_2(const char *pathname, int flags)
+extern "C" OSV_LIBC_API
+int __open_2(const char *pathname, int flags)
{
assert(!(flags & O_CREAT));
return open(pathname, flags, 0);
}

-extern "C" int __open64_2(const char *file, int flags)
+extern "C" OSV_LIBC_API
+int __open64_2(const char *file, int flags)
{
if (flags & O_CREAT) {
errno = EINVAL;
@@ -221,6 +225,7 @@ extern "C" int __open64_2(const char *file, int flags)
return open64(file, flags);
}

+OSV_LIBC_API
int creat(const char *pathname, mode_t mode)
{
return open(pathname, O_CREAT|O_WRONLY|O_TRUNC, mode);
@@ -231,6 +236,7 @@ TRACEPOINT(trace_vfs_close, "%d", int);
TRACEPOINT(trace_vfs_close_ret, "");
TRACEPOINT(trace_vfs_close_err, "%d", int);

+OSV_LIBC_API
int close(int fd)
{
int error;
@@ -254,7 +260,7 @@ TRACEPOINT(trace_vfs_mknod_ret, "");
TRACEPOINT(trace_vfs_mknod_err, "%d", int);


-extern "C"
+extern "C" OSV_LIBC_API
int __xmknod(int ver, const char *pathname, mode_t mode, dev_t *dev)
{
assert(ver == 0); // On x86-64 Linux, _MKNOD_VER_LINUX is 0.
@@ -279,6 +285,7 @@ int __xmknod(int ver, const char *pathname, mode_t mode, dev_t *dev)
return -1;
}

+OSV_LIBC_API
int mknod(const char *pathname, mode_t mode, dev_t dev)
{
return __xmknod(0, pathname, mode, &dev);
@@ -289,6 +296,7 @@ TRACEPOINT(trace_vfs_lseek, "%d 0x%x %d", int, off_t, int);
TRACEPOINT(trace_vfs_lseek_ret, "0x%x", off_t);
TRACEPOINT(trace_vfs_lseek_err, "%d", int);

+OSV_LIBC_API
off_t lseek(int fd, off_t offset, int whence)
{
struct file *fp;
@@ -333,6 +341,7 @@ static inline bool has_error(int error, int bytes)
}


+OSV_LIBC_API
ssize_t pread(int fd, void *buf, size_t count, off_t offset)
{
trace_vfs_pread(fd, buf, count, offset);
@@ -364,6 +373,7 @@ ssize_t pread(int fd, void *buf, size_t count, off_t offset)

LFS64(pread);

+OSV_LIBC_API
ssize_t read(int fd, void *buf, size_t count)
{
return pread(fd, buf, count, -1);
@@ -373,6 +383,7 @@ TRACEPOINT(trace_vfs_pwrite, "%d %p 0x%x 0x%x", int, const void*, size_t, off_t)
TRACEPOINT(trace_vfs_pwrite_ret, "0x%x", ssize_t);
TRACEPOINT(trace_vfs_pwrite_err, "%d", int);

+OSV_LIBC_API
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
{
trace_vfs_pwrite(fd, buf, count, offset);
@@ -404,11 +415,13 @@ ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)

LFS64(pwrite);

+OSV_LIBC_API
ssize_t write(int fd, const void *buf, size_t count)
{
return pwrite(fd, buf, count, -1);
}

+OSV_LIBC_API
ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
{
struct file *fp;
@@ -431,6 +444,7 @@ ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
return -1;
}

+OSV_LIBC_API
ssize_t readv(int fd, const struct iovec *iov, int iovcnt)
{
return preadv(fd, iov, iovcnt, -1);
@@ -440,6 +454,7 @@ TRACEPOINT(trace_vfs_pwritev, "%d %p 0x%x 0x%x", int, const struct iovec*, int,
TRACEPOINT(trace_vfs_pwritev_ret, "0x%x", ssize_t);
TRACEPOINT(trace_vfs_pwritev_err, "%d", int);

+OSV_LIBC_API
ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
{
struct file *fp;
@@ -465,6 +480,7 @@ ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
return -1;
}

+OSV_LIBC_API
ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
{
return pwritev(fd, iov, iovcnt, -1);
@@ -474,6 +490,7 @@ TRACEPOINT(trace_vfs_ioctl, "%d 0x%x", int, unsigned long);
TRACEPOINT(trace_vfs_ioctl_ret, "");
TRACEPOINT(trace_vfs_ioctl_err, "%d", int);

+OSV_LIBC_API
int ioctl(int fd, unsigned long int request, ...)
{
struct file *fp;
@@ -511,6 +528,7 @@ TRACEPOINT(trace_vfs_fsync, "%d", int);
TRACEPOINT(trace_vfs_fsync_ret, "");
TRACEPOINT(trace_vfs_fsync_err, "%d", int);

+OSV_LIBC_API
int fsync(int fd)
{
struct file *fp;
@@ -535,6 +553,7 @@ int fsync(int fd)
return -1;
}

+OSV_LIBC_API
int fdatasync(int fd)
{
// TODO: See if we can do less than fsync().
@@ -545,7 +564,7 @@ TRACEPOINT(trace_vfs_fstat, "%d %p", int, struct stat*);
TRACEPOINT(trace_vfs_fstat_ret, "");
TRACEPOINT(trace_vfs_fstat_err, "%d", int);

-extern "C"
+extern "C" OSV_LIBC_API
int __fxstat(int ver, int fd, struct stat *st)
{
struct file *fp;
@@ -573,13 +592,13 @@ int __fxstat(int ver, int fd, struct stat *st)

LFS64(__fxstat);

-extern "C"
+extern "C" OSV_LIBC_API
int fstat(int fd, struct stat *st)
{
return __fxstat(1, fd, st);
}

-extern "C"
+extern "C" OSV_LIBC_API
int __fxstatat(int ver, int dirfd, const char *pathname, struct stat *st,
int flags)
{
@@ -625,13 +644,14 @@ int __fxstatat(int ver, int dirfd, const char *pathname, struct stat *st,

LFS64(__fxstatat);

-extern "C"
+extern "C" OSV_LIBC_API
int fstatat(int dirfd, const char *path, struct stat *st, int flags)
{
return __fxstatat(1, dirfd, path, st, flags);
}

-extern "C" int flock(int fd, int operation)
+extern "C" OSV_LIBC_API
+int flock(int fd, int operation)
{
if (!fileref_from_fd(fd)) {
return libc_error(EBADF);
@@ -660,6 +680,7 @@ struct __dirstream
int fd;
};

+OSV_LIBC_API
DIR *opendir(const char *path)
{
DIR *dir = new DIR;
@@ -675,6 +696,7 @@ DIR *opendir(const char *path)
return dir;
}

+OSV_LIBC_API
DIR *fdopendir(int fd)
{
DIR *dir;
@@ -692,6 +714,7 @@ DIR *fdopendir(int fd)

}

+OSV_LIBC_API
int dirfd(DIR *dirp)
{
if (!dirp) {
@@ -701,6 +724,7 @@ int dirfd(DIR *dirp)
return dirp->fd;
}

+OSV_LIBC_API
int closedir(DIR *dir)
{
close(dir->fd);
@@ -708,6 +732,7 @@ int closedir(DIR *dir)
return 0;
}

+OSV_LIBC_API
struct dirent *readdir(DIR *dir)
{
static __thread struct dirent entry, *result;
@@ -721,6 +746,7 @@ struct dirent *readdir(DIR *dir)
return result;
}

+OSV_LIBC_API
int readdir_r(DIR *dir, struct dirent *entry, struct dirent **result)
{
int error;
@@ -752,13 +778,16 @@ int readdir_r(DIR *dir, struct dirent *entry, struct dirent **result)

// FIXME: in 64bit dirent64 and dirent are identical, so it's safe to alias
#undef readdir64_r
-extern "C" int readdir64_r(DIR *dir, struct dirent64 *entry,
+extern "C" OSV_LIBC_API
+int readdir64_r(DIR *dir, struct dirent64 *entry,
struct dirent64 **result)
__attribute__((alias("readdir_r")));

#undef readdir64
-extern "C" struct dirent *readdir64(DIR *dir) __attribute__((alias("readdir")));
+extern "C" OSV_LIBC_API
+struct dirent *readdir64(DIR *dir) __attribute__((alias("readdir")));

+OSV_LIBC_API
void rewinddir(DIR *dirp)
{
struct file *fp;
@@ -775,6 +804,7 @@ void rewinddir(DIR *dirp)
fdrop(fp);
}

+OSV_LIBC_API
long telldir(DIR *dirp)
{
struct file *fp;
@@ -792,6 +822,7 @@ long telldir(DIR *dirp)
return loc;
}

+OSV_LIBC_API
void seekdir(DIR *dirp, long loc)
{
struct file *fp;
@@ -809,6 +840,7 @@ TRACEPOINT(trace_vfs_mkdir, "\"%s\" 0%0o", const char*, mode_t);
TRACEPOINT(trace_vfs_mkdir_ret, "");
TRACEPOINT(trace_vfs_mkdir_err, "%d", int);

+OSV_LIBC_API
int
mkdir(const char *pathname, mode_t mode)
{
@@ -833,6 +865,7 @@ mkdir(const char *pathname, mode_t mode)
return -1;
}

+OSV_LIBC_API
int mkdirat(int dirfd, const char *pathname, mode_t mode)
{
mode = apply_umask(mode);
@@ -874,6 +907,7 @@ TRACEPOINT(trace_vfs_rmdir, "\"%s\"", const char*);
TRACEPOINT(trace_vfs_rmdir_ret, "");
TRACEPOINT(trace_vfs_rmdir_err, "%d", int);

+OSV_LIBC_API
int rmdir(const char *pathname)
{
struct task *t = main_task;
@@ -927,6 +961,7 @@ TRACEPOINT(trace_vfs_rename, "\"%s\" \"%s\"", const char*, const char*);
TRACEPOINT(trace_vfs_rename_ret, "");
TRACEPOINT(trace_vfs_rename_err, "%d", int);

+OSV_LIBC_API
int rename(const char *oldpath, const char *newpath)
{
trace_vfs_rename(oldpath, newpath);
@@ -996,6 +1031,7 @@ static int replace_cwd(struct task *t, struct file *new_cwdfp,
return error;
}

+OSV_LIBC_API
int chdir(const char *pathname)
{
trace_vfs_chdir(pathname);
@@ -1031,6 +1067,7 @@ TRACEPOINT(trace_vfs_fchdir, "%d", int);
TRACEPOINT(trace_vfs_fchdir_ret, "");
TRACEPOINT(trace_vfs_fchdir_err, "%d", int);

+OSV_LIBC_API
int fchdir(int fd)
{
trace_vfs_fchdir(fd);
@@ -1061,6 +1098,7 @@ TRACEPOINT(trace_vfs_link, "\"%s\" \"%s\"", const char*, const char*);
TRACEPOINT(trace_vfs_link_ret, "");
TRACEPOINT(trace_vfs_link_err, "%d", int);

+OSV_LIBC_API
int link(const char *oldpath, const char *newpath)
{
struct task *t = main_task;
@@ -1094,6 +1132,7 @@ TRACEPOINT(trace_vfs_symlink, "oldpath=%s, newpath=%s", const char*, const char*
TRACEPOINT(trace_vfs_symlink_ret, "");
TRACEPOINT(trace_vfs_symlink_err, "errno=%d", int);

+OSV_LIBC_API
int symlink(const char *oldpath, const char *newpath)
{
int error;
@@ -1122,6 +1161,7 @@ TRACEPOINT(trace_vfs_unlink, "\"%s\"", const char*);
TRACEPOINT(trace_vfs_unlink_ret, "");
TRACEPOINT(trace_vfs_unlink_err, "%d", int);

+OSV_LIBC_API
int unlink(const char *pathname)
{
trace_vfs_unlink(pathname);
@@ -1146,6 +1186,7 @@ int unlink(const char *pathname)
return -1;
}

+OSV_LIBC_API
int unlinkat(int dirfd, const char *pathname, int flags)
{
//TODO: Really implement it
@@ -1159,7 +1200,7 @@ TRACEPOINT(trace_vfs_stat, "\"%s\" %p", const char*, struct stat*);
TRACEPOINT(trace_vfs_stat_ret, "");
TRACEPOINT(trace_vfs_stat_err, "%d", int);

-extern "C"
+extern "C" OSV_LIBC_API
int __xstat(int ver, const char *pathname, struct stat *st)
{
struct task *t = main_task;
@@ -1186,6 +1227,7 @@ int __xstat(int ver, const char *pathname, struct stat *st)

LFS64(__xstat);

+OSV_LIBC_API
int stat(const char *pathname, struct stat *st)
{
return __xstat(1, pathname, st);
@@ -1227,6 +1269,7 @@ struct statx {
extern "C" int statx(int dirfd, const char* pathname, int flags, unsigned int mask, struct statx *buf);
#define STATX_BASIC_STATS 0x000007ffU

+OSV_LIBC_API
int statx(int dirfd, const char* pathname, int flags, unsigned int mask,
struct statx *buf)
{
@@ -1271,7 +1314,7 @@ int statx(int dirfd, const char* pathname, int flags, unsigned int mask,
TRACEPOINT(trace_vfs_lstat, "pathname=%s, stat=%p", const char*, struct stat*);
TRACEPOINT(trace_vfs_lstat_ret, "");
TRACEPOINT(trace_vfs_lstat_err, "errno=%d", int);
-extern "C"
+extern "C" OSV_LIBC_API
int __lxstat(int ver, const char *pathname, struct stat *st)
{
struct task *t = main_task;
@@ -1300,6 +1343,7 @@ int __lxstat(int ver, const char *pathname, struct stat *st)

LFS64(__lxstat);

+OSV_LIBC_API
int lstat(const char *pathname, struct stat *st)
{
return __lxstat(1, pathname, st);
@@ -1309,7 +1353,7 @@ TRACEPOINT(trace_vfs_statfs, "\"%s\" %p", const char*, struct statfs*);
TRACEPOINT(trace_vfs_statfs_ret, "");
TRACEPOINT(trace_vfs_statfs_err, "%d", int);

-extern "C"
+extern "C" OSV_LIBC_API
int __statfs(const char *pathname, struct statfs *buf)
{
trace_vfs_statfs(pathname, buf);
@@ -1331,7 +1375,7 @@ int __statfs(const char *pathname, struct statfs *buf)
errno = error;
return -1;
}
-weak_alias(__statfs, statfs);
+weak_alias(__statfs, statfs) OSV_LIBC_API;

TRACEPOINT(trace_vfs_fstatfs, "\"%s\" %p", int, struct statfs*);
TRACEPOINT(trace_vfs_fstatfs_ret, "");
@@ -1361,7 +1405,7 @@ int __fstatfs(int fd, struct statfs *buf)
errno = error;
return -1;
}
-weak_alias(__fstatfs, fstatfs);
+weak_alias(__fstatfs, fstatfs) OSV_LIBC_API;

static int
statfs_to_statvfs(struct statvfs *dst, struct statfs *src)
@@ -1380,6 +1424,7 @@ statfs_to_statvfs(struct statvfs *dst, struct statfs *src)
return 0;
}

+OSV_LIBC_API
int
statvfs(const char *pathname, struct statvfs *buf)
{
@@ -1390,6 +1435,7 @@ statvfs(const char *pathname, struct statvfs *buf)
return statfs_to_statvfs(buf, &st);
}

+OSV_LIBC_API
int
fstatvfs(int fd, struct statvfs *buf)
{
@@ -1404,6 +1450,7 @@ TRACEPOINT(trace_vfs_getcwd, "%p %d", char*, size_t);
TRACEPOINT(trace_vfs_getcwd_ret, "\"%s\"", const char*);
TRACEPOINT(trace_vfs_getcwd_err, "%d", int);

+OSV_LIBC_API
char *getcwd(char *path, size_t size)
{
trace_vfs_getcwd(path, size);
@@ -1447,6 +1494,7 @@ TRACEPOINT(trace_vfs_dup_err, "%d", int);
/*
* Duplicate a file descriptor
*/
+OSV_LIBC_API
int dup(int oldfd)
{
struct file *fp;
@@ -1480,6 +1528,7 @@ TRACEPOINT(trace_vfs_dup3_err, "%d", int);
/*
* Duplicate a file descriptor to a particular value.
*/
+OSV_LIBC_API
int dup3(int oldfd, int newfd, int flags)
{
struct file *fp;
@@ -1520,6 +1569,7 @@ int dup3(int oldfd, int newfd, int flags)
return -1;
}

+OSV_LIBC_API
int dup2(int oldfd, int newfd)
{
if (oldfd == newfd)
@@ -1537,7 +1587,7 @@ TRACEPOINT(trace_vfs_fcntl, "%d %d 0x%x", int, int, int);
TRACEPOINT(trace_vfs_fcntl_ret, "\"%s\"", int);
TRACEPOINT(trace_vfs_fcntl_err, "%d", int);

-extern "C"
+extern "C" OSV_LIBC_API
int fcntl(int fd, int cmd, int arg)
{
struct file *fp;
@@ -1632,6 +1682,7 @@ TRACEPOINT(trace_vfs_access_err, "%d", int);
/*
* Check permission for file access
*/
+OSV_LIBC_API
int access(const char *pathname, int mode)
{
trace_vfs_access(pathname, mode);
@@ -1659,6 +1710,7 @@ int access(const char *pathname, int mode)
return -1;
}

+OSV_LIBC_API
int faccessat(int dirfd, const char *pathname, int mode, int flags)
{
if (flags & AT_SYMLINK_NOFOLLOW) {
@@ -1696,13 +1748,13 @@ int faccessat(int dirfd, const char *pathname, int mode, int flags)
return error;
}

-extern "C"
+extern "C" OSV_LIBC_API
int euidaccess(const char *pathname, int mode)
{
return access(pathname, mode);
}

-weak_alias(euidaccess,eaccess);
+weak_alias(euidaccess,eaccess) OSV_LIBC_API;

#if 0
static int
@@ -1756,6 +1808,7 @@ TRACEPOINT(trace_vfs_isatty_err, "%d", int);
/*
* Return if specified file is a tty
*/
+OSV_LIBC_API
int isatty(int fd)
{
struct file *fp;
@@ -1783,6 +1836,7 @@ TRACEPOINT(trace_vfs_truncate, "\"%s\" 0x%x", const char*, off_t);
TRACEPOINT(trace_vfs_truncate_ret, "");
TRACEPOINT(trace_vfs_truncate_err, "%d", int);

+OSV_LIBC_API
int truncate(const char *pathname, off_t length)
{
trace_vfs_truncate(pathname, length);
@@ -1813,6 +1867,7 @@ TRACEPOINT(trace_vfs_ftruncate, "%d 0x%x", int, off_t);
TRACEPOINT(trace_vfs_ftruncate_ret, "");
TRACEPOINT(trace_vfs_ftruncate_err, "%d", int);

+OSV_LIBC_API
int ftruncate(int fd, off_t length)
{
trace_vfs_ftruncate(fd, length);
@@ -1839,6 +1894,7 @@ int ftruncate(int fd, off_t length)

LFS64(ftruncate);

+OSV_LIBC_API
ssize_t readlink(const char *pathname, char *buf, size_t bufsize)
{
struct task *t = main_task;
@@ -1869,6 +1925,7 @@ ssize_t readlink(const char *pathname, char *buf, size_t bufsize)
return -1;
}

+OSV_LIBC_API
ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsize)
{
if (pathname[0] == '/' || dirfd == AT_FDCWD) {
@@ -1906,6 +1963,7 @@ TRACEPOINT(trace_vfs_fallocate, "%d %d 0x%x 0x%x", int, int, loff_t, loff_t);
TRACEPOINT(trace_vfs_fallocate_ret, "");
TRACEPOINT(trace_vfs_fallocate_err, "%d", int);

+OSV_LIBC_API
int fallocate(int fd, int mode, loff_t offset, loff_t len)
{
struct file *fp;
@@ -1936,11 +1994,13 @@ TRACEPOINT(trace_vfs_utimes, "\"%s\"", const char*);
TRACEPOINT(trace_vfs_utimes_ret, "");
TRACEPOINT(trace_vfs_utimes_err, "%d", int);

+OSV_LIBC_API
int futimes(int fd, const struct timeval times[2])
{
return futimesat(fd, nullptr, times);
}

+OSV_LIBC_API
int futimesat(int dirfd, const char *pathname, const struct timeval times[2])
{
struct stat st;
@@ -1998,7 +2058,7 @@ TRACEPOINT(trace_vfs_utimensat, "\"%s\"", const char*);
TRACEPOINT(trace_vfs_utimensat_ret, "");
TRACEPOINT(trace_vfs_utimensat_err, "%d", int);

-extern "C"
+extern "C" OSV_LIBC_API
int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags)
{
trace_vfs_utimensat(pathname);
@@ -2018,7 +2078,7 @@ TRACEPOINT(trace_vfs_futimens, "%d", int);
TRACEPOINT(trace_vfs_futimens_ret, "");
TRACEPOINT(trace_vfs_futimens_err, "%d", int);

-extern "C"
+extern "C" OSV_LIBC_API
int futimens(int fd, const struct timespec times[2])
{
trace_vfs_futimens(fd);
@@ -2058,19 +2118,19 @@ static int do_utimes(const char *pathname, const struct timeval times[2], int fl
return 0;
}

-extern "C"
+extern "C" OSV_LIBC_API
int utimes(const char *pathname, const struct timeval times[2])
{
return do_utimes(pathname, times, 0);
}

-extern "C"
+extern "C" OSV_LIBC_API
int lutimes(const char *pathname, const struct timeval times[2])
{
return do_utimes(pathname, times, AT_SYMLINK_NOFOLLOW);
}

-extern "C"
+extern "C" OSV_LIBC_API
int utime(const char *pathname, const struct utimbuf *t)
{
using namespace std::chrono;
@@ -2094,6 +2154,7 @@ TRACEPOINT(trace_vfs_chmod, "\"%s\" 0%0o", const char*, mode_t);
TRACEPOINT(trace_vfs_chmod_ret, "");
TRACEPOINT(trace_vfs_chmod_err, "%d", int);

+OSV_LIBC_API
int chmod(const char *pathname, mode_t mode)
{
trace_vfs_chmod(pathname, mode);
@@ -2118,6 +2179,7 @@ out_errno:
TRACEPOINT(trace_vfs_fchmod, "\"%d\" 0%0o", int, mode_t);
TRACEPOINT(trace_vfs_fchmod_ret, "");

+OSV_LIBC_API
int fchmod(int fd, mode_t mode)
{
trace_vfs_fchmod(fd, mode);
@@ -2134,6 +2196,7 @@ int fchmod(int fd, mode_t mode)
TRACEPOINT(trace_vfs_fchown, "\"%d\" %d %d", int, uid_t, gid_t);
TRACEPOINT(trace_vfs_fchown_ret, "");

+OSV_LIBC_API
int fchown(int fd, uid_t owner, gid_t group)
{
trace_vfs_fchown(fd, owner, group);
@@ -2142,12 +2205,14 @@ int fchown(int fd, uid_t owner, gid_t group)
return 0;
}

+OSV_LIBC_API
int chown(const char *path, uid_t owner, gid_t group)
{
WARN_STUBBED();
return 0;
}

+OSV_LIBC_API
int lchown(const char *path, uid_t owner, gid_t group)
{
WARN_STUBBED();
@@ -2155,6 +2220,7 @@ int lchown(const char *path, uid_t owner, gid_t group)
}


+OSV_LIBC_API
ssize_t sendfile(int out_fd, int in_fd, off_t *_offset, size_t count)
{
struct file *in_fp;
@@ -2236,8 +2302,9 @@ ssize_t sendfile(int out_fd, int in_fd, off_t *_offset, size_t count)
#undef sendfile64
LFS64(sendfile);

-NO_SYS(int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags));
+NO_SYS(OSV_LIBC_API int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags));

+OSV_LIBC_API
mode_t umask(mode_t newmask)
{
return global_umask.exchange(newmask, std::memory_order_relaxed);
@@ -2249,6 +2316,7 @@ fs_noop(void)
return 0;
}

+OSV_LIBC_API
int chroot(const char *path)
{
WARN_STUBBED();
diff --git a/include/osv/export.h b/include/osv/export.h
index 605e8e10..ab93da14 100644
--- a/include/osv/export.h
+++ b/include/osv/export.h
@@ -25,7 +25,6 @@
#define OSV_LIBAIO_API __attribute__((__visibility__("default")))
#define OSV_LIBC_API __attribute__((__visibility__("default")))
#define OSV_LIBM_API __attribute__((__visibility__("default")))
-#define OSV_LIBBSD_API __attribute__((__visibility__("default")))
#define OSV_LIBPTHREAD_API __attribute__((__visibility__("default")))
#define OSV_LIBUTIL_API __attribute__((__visibility__("default")))
#define OSV_LIBXENSTORE_API __attribute__((__visibility__("default")))
diff --git a/include/osv/sched.hh b/include/osv/sched.hh
index 27950ac3..2180fa62 100644
--- a/include/osv/sched.hh
+++ b/include/osv/sched.hh
@@ -25,6 +25,7 @@
#include <osv/rcu.hh>
#include <osv/clock.hh>
#include <osv/timer-set.hh>
+#include <osv/export.h>
#include <string.h>

typedef float runtime_t;
diff --git a/libc/eventfd.cc b/libc/eventfd.cc
index 3cfc86e1..ef00e635 100644
--- a/libc/eventfd.cc
+++ b/libc/eventfd.cc
@@ -178,6 +178,7 @@ int event_fd::poll(int events)
return rc;
}

+OSV_LIBC_API
int eventfd(unsigned int initval, int flags)
{
if (flags & (~(EFD_CLOEXEC | EFD_NONBLOCK | EFD_SEMAPHORE))) {
@@ -209,6 +210,7 @@ int eventfd(unsigned int initval, int flags)
}
weak_alias(eventfd, eventfd2);

+OSV_LIBC_API
int eventfd_read(int fd, eventfd_t *value)
{
fileref f(fileref_from_fd(fd));
@@ -231,6 +233,7 @@ int eventfd_read(int fd, eventfd_t *value)
return 0;
}

+OSV_LIBC_API
int eventfd_write(int fd, eventfd_t value)
{
fileref f(fileref_from_fd(fd));
diff --git a/libc/internal/libc.h b/libc/internal/libc.h
index bb2d7f6b..aa07ef48 100644
--- a/libc/internal/libc.h
+++ b/libc/internal/libc.h
@@ -3,6 +3,7 @@

#include <stdlib.h>
#include <osv/mutex.h>
+#include <osv/export.h>
#include "stdio.h"

__BEGIN_DECLS
@@ -49,7 +50,7 @@ extern char **__environ;
#endif

#undef LFS64_2
-#define LFS64_2(x, y) weak_alias(x, y)
+#define LFS64_2(x, y) weak_alias(x, y) OSV_LIBC_API

#undef LFS64
#define LFS64(x) LFS64_2(x, x##64)
diff --git a/libc/misc/getopt.cc b/libc/misc/getopt.cc
index 391fcd52..c1d1182a 100644
--- a/libc/misc/getopt.cc
+++ b/libc/misc/getopt.cc
@@ -8,11 +8,13 @@

extern "C" {

+OSV_LIBC_API
char *optarg;
+OSV_LIBC_API
int optind=1, opterr=1, optopt, __optpos, __optreset=0;

#define optpos __optpos
-weak_alias(__optreset, optreset);
+weak_alias(__optreset, optreset) OSV_LIBC_API;

int __getopt(int argc, char * const argv[], const char *optstring)
{
@@ -74,11 +76,12 @@ int __getopt(int argc, char * const argv[], const char *optstring)
return c;
}

+OSV_LIBC_API
int getopt(int argc, char * const argv[], const char *optstring)
{
getopt_caller_vars_copier guard;
return __getopt(argc, argv, optstring);
}

-weak_alias(getopt, __posix_getopt);
+weak_alias(getopt, __posix_getopt) OSV_LIBC_API;
}
diff --git a/libc/misc/getopt_long.cc b/libc/misc/getopt_long.cc
index cb124734..215294bc 100644
--- a/libc/misc/getopt_long.cc
+++ b/libc/misc/getopt_long.cc
@@ -1,6 +1,7 @@
#include <stddef.h>
#include <getopt.h>
#include <stdio.h>
+#include <osv/export.h>
#include "getopt.hh"

extern "C" {
@@ -52,11 +53,13 @@ static int __getopt_long(int argc, char *const *argv, const char *optstring, con
return __getopt(argc, argv, optstring);
}

+OSV_LIBC_API
int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
{
return __getopt_long(argc, argv, optstring, longopts, idx, 0);
}

+OSV_LIBC_API
int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
{
return __getopt_long(argc, argv, optstring, longopts, idx, 1);
diff --git a/libc/misc/mntent.cc b/libc/misc/mntent.cc
index 6accaeac..32a38dbf 100644
--- a/libc/misc/mntent.cc
+++ b/libc/misc/mntent.cc
@@ -76,6 +76,7 @@ int mtab_file::read(struct uio *uio, int flags)
return 0;
}

+OSV_LIBC_API
FILE *setmntent(const char *name, const char *mode)
{
if (!strcmp(name, "/proc/mounts") || !strcmp(name, "/etc/mnttab") || !strcmp(name, "/etc/mtab")) {
@@ -103,12 +104,14 @@ FILE *setmntent(const char *name, const char *mode)
return fopen(name, mode);
}

+OSV_LIBC_API
int endmntent(FILE *f)
{
fclose(f);
return 1;
}

+OSV_LIBC_API
struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen)
{
int cnt, n[8];
@@ -145,6 +148,7 @@ struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int bufle
return mnt;
}

+OSV_LIBC_API
struct mntent *getmntent(FILE *f)
{
static char linebuf[256];
@@ -167,6 +171,7 @@ bool is_mtab_file(FILE *fp)
return true;
}

+OSV_LIBC_API
int addmntent(FILE *f, const struct mntent *mnt)
{
if (is_mtab_file(f)) {
@@ -179,6 +184,7 @@ int addmntent(FILE *f, const struct mntent *mnt)
mnt->mnt_freq, mnt->mnt_passno) < 0;
}

+OSV_LIBC_API
char *hasmntopt(const struct mntent *mnt, const char *opt)
{
return strstr(mnt->mnt_opts, opt);
diff --git a/libc/mman.cc b/libc/mman.cc
index 895b9b28..9dd6429a 100644
--- a/libc/mman.cc
+++ b/libc/mman.cc
@@ -84,6 +84,7 @@ unsigned libc_madvise_to_advise(int advice)
return 0;
}

+OSV_LIBC_API
int mprotect(void *addr, size_t len, int prot)
{
// we don't support mprotecting() the linear map (e.g.., malloc() memory)
@@ -115,6 +116,7 @@ int mmap_validate(void *addr, size_t length, int flags, off_t offset)
return 0;
}

+OSV_LIBC_API
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset)
{
@@ -199,6 +201,7 @@ int munmap_validate(void *addr, size_t length)
return 0;
}

+OSV_LIBC_API
int munmap(void *addr, size_t length)
{
trace_memory_munmap(addr, length);
@@ -216,11 +219,13 @@ int munmap(void *addr, size_t length)
return ret;
}

+OSV_LIBC_API
int msync(void *addr, size_t length, int flags)
{
return mmu::msync(addr, length, flags).to_libc();
}

+OSV_LIBC_API
int mincore(void *addr, size_t length, unsigned char *vec)
{
if (!mmu::is_page_aligned(addr)) {
@@ -230,12 +235,14 @@ int mincore(void *addr, size_t length, unsigned char *vec)
return mmu::mincore(addr, length, vec).to_libc();
}

+OSV_LIBC_API
int madvise(void *addr, size_t length, int advice)
{
auto err = mmu::advise(addr, length, libc_madvise_to_advise(advice));
return err.to_libc();
}

+OSV_LIBC_API
int brk(void *addr)
{
WARN_STUBBED();
@@ -243,6 +250,7 @@ int brk(void *addr)
return -1;
}

+OSV_LIBC_API
void *sbrk(intptr_t increment)
{
WARN_STUBBED();
diff --git a/libc/pipe.cc b/libc/pipe.cc
index ef10d9e7..78cad285 100644
--- a/libc/pipe.cc
+++ b/libc/pipe.cc
@@ -86,6 +86,7 @@ int pipe_file::close()
return 0;
}

+OSV_LIBC_API
int pipe2(int pipefd[2], int flags) {
if (flags & ~(O_NONBLOCK | O_CLOEXEC)) {
return libc_error(EINVAL);
@@ -115,6 +116,7 @@ int pipe2(int pipefd[2], int flags) {
}
}

+OSV_LIBC_API
int pipe(int pipefd[2])
{
return pipe2(pipefd, 0);
diff --git a/libc/pthread.cc b/libc/pthread.cc
index 4e44082c..cda6cf90 100644
--- a/libc/pthread.cc
+++ b/libc/pthread.cc
@@ -29,6 +29,7 @@

#include <api/time.h>
#include <osv/rwlock.h>
+#include <osv/export.h>

#include "pthread.hh"

@@ -275,9 +276,9 @@ extern "C" int register_atfork(void (*prepare)(void), void (*parent)(void),

extern "C" {
int __register_atfork(void (*prepare)(void), void (*parent)(void),
- void (*child)(void), void *__dso_handle) __attribute__((alias("register_atfork")));
+ void (*child)(void), void *__dso_handle) __attribute__((alias("register_atfork"))) OSV_LIBC_API;
int __pthread_key_create(pthread_key_t* key, void (*dtor)(void*))
- __attribute__((alias("pthread_key_create")));
+ __attribute__((alias("pthread_key_create"))) OSV_LIBPTHREAD_API;
}


@@ -457,7 +458,8 @@ int pthread_mutex_unlock(pthread_mutex_t *m)
return 0;
}

-extern "C" int pthread_yield()
+extern "C" OSV_LIBPTHREAD_API
+int pthread_yield()
{
sched::thread::yield();
return 0;
@@ -528,6 +530,7 @@ int pthread_rwlock_unlock(pthread_rwlock_t *rw)
return 0;
}

+OSV_LIBC_API
int pthread_sigmask(int how, const sigset_t* set, sigset_t* oldset)
{
return sigprocmask(how, set, oldset);
@@ -993,6 +996,7 @@ int pthread_getschedparam(pthread_t thread, int *policy,
return 0;
}

+OSV_LIBPTHREAD_API
int pthread_kill(pthread_t thread, int sig)
{
// We are assuming that if pthread_kill() is called with thread
@@ -1011,6 +1015,7 @@ int pthread_kill(pthread_t thread, int sig)
return EINVAL;
}

+OSV_LIBPTHREAD_API
int raise(int sig)
{
return pthread_kill(pthread_self(), sig);
diff --git a/libc/resource.cc b/libc/resource.cc
index b24a4ee1..d5f9470c 100644
--- a/libc/resource.cc
+++ b/libc/resource.cc
@@ -34,4 +34,3 @@ int getrusage(int who, struct rusage *usage)
}
return 0;
}
-LFS64(getrusage);
diff --git a/libc/sem.cc b/libc/sem.cc
index 9277d230..fa9cd001 100644
--- a/libc/sem.cc
+++ b/libc/sem.cc
@@ -23,6 +23,7 @@ indirect_semaphore& from_libc(sem_t* p)
return *reinterpret_cast<indirect_semaphore*>(p);
}

+OSV_LIBC_API
int sem_init(sem_t* s, int pshared, unsigned val)
{
static_assert(sizeof(indirect_semaphore) <= sizeof(*s), "sem_t overflow");
@@ -30,24 +31,28 @@ int sem_init(sem_t* s, int pshared, unsigned val)
return 0;
}

+OSV_LIBC_API
int sem_destroy(sem_t *s)
{
from_libc(s).~indirect_semaphore();
return 0;
}

+OSV_LIBC_API
int sem_post(sem_t* s)
{
from_libc(s)->post();
return 0;
}

+OSV_LIBC_API
int sem_wait(sem_t* s)
{
from_libc(s)->wait();
return 0;
}

+OSV_LIBC_API
int sem_timedwait(sem_t* s, const struct timespec *abs_timeout)
{
if ((abs_timeout->tv_sec < 0) || (abs_timeout->tv_nsec < 0) || (abs_timeout->tv_nsec > 1000000000LL)) {
@@ -64,6 +69,7 @@ int sem_timedwait(sem_t* s, const struct timespec *abs_timeout)
return 0;
}

+OSV_LIBC_API
int sem_trywait(sem_t* s)
{
if (!from_libc(s)->trywait())
diff --git a/libc/signal.cc b/libc/signal.cc
index f346552d..b530a5b8 100644
--- a/libc/signal.cc
+++ b/libc/signal.cc
@@ -19,6 +19,7 @@
#include <api/setjmp.h>
#include <osv/stubbing.hh>
#include <osv/pid.h>
+#include <osv/export.h>

using namespace osv::clock::literals;

@@ -148,35 +149,41 @@ void handle_mmap_fault(ulong addr, int sig, exception_frame* ef)

using namespace osv;

+OSV_LIBC_API
int sigemptyset(sigset_t* sigset)
{
from_libc(sigset)->mask.reset();
return 0;
}

+OSV_LIBC_API
int sigfillset(sigset_t *sigset)
{
from_libc(sigset)->mask.set();
return 0;
}

+OSV_LIBC_API
int sigaddset(sigset_t *sigset, int signum)
{
from_libc(sigset)->mask.set(signum);
return 0;
}

+OSV_LIBC_API
int sigdelset(sigset_t *sigset, int signum)
{
from_libc(sigset)->mask.reset(signum);
return 0;
}

+OSV_LIBC_API
int sigismember(const sigset_t *sigset, int signum)
{
return from_libc(sigset)->mask.test(signum);
}

+OSV_LIBC_API
int sigprocmask(int how, const sigset_t* _set, sigset_t* _oldset)
{
auto set = from_libc(_set);
@@ -218,8 +225,9 @@ int sigprocmask(int how, const sigset_t* _set, sigset_t* _oldset)
return 0;
}

-UNIMPL(int sigsuspend(const sigset_t *mask));
+UNIMPL(OSV_LIBC_API int sigsuspend(const sigset_t *mask));

+OSV_LIBC_API
int sigaction(int signum, const struct sigaction* act, struct sigaction* oldact)
{
// FIXME: We do not support any sa_flags besides SA_SIGINFO.
@@ -256,12 +264,14 @@ static sighandler_t signal(int signum, sighandler_t handler, int sa_flags)
}
}

+OSV_LIBC_API
sighandler_t signal(int signum, sighandler_t handler)
{
return signal(signum, handler, SA_RESTART);
}

extern "C"
+OSV_LIBC_API
sighandler_t __sysv_signal(int signum, sighandler_t handler)
{
return signal(signum, handler, SA_RESETHAND | SA_NODEFER);
@@ -269,6 +279,7 @@ sighandler_t __sysv_signal(int signum, sighandler_t handler)

// using sigignore() and friends is not recommended as it is obsolete System V
// APIs. Nevertheless, some programs use it.
+OSV_LIBC_API
int sigignore(int signum)
{
struct sigaction act;
@@ -278,6 +289,7 @@ int sigignore(int signum)
return sigaction(signum, &act, nullptr);
}

+OSV_LIBC_API
int sigwait(const sigset_t *set, int *sig)
{
sched::thread::wait_until([sig] { return *sig = thread_pending_signal; });
@@ -306,6 +318,7 @@ int sigwait(const sigset_t *set, int *sig)
// another handler thread. We should probably block this signal while
// handling it.

+OSV_LIBC_API
int kill(pid_t pid, int sig)
{
// OSv only implements one process, whose pid is getpid().
@@ -368,6 +381,7 @@ int kill(pid_t pid, int sig)
return 0;
}

+OSV_LIBC_API
int pause(void) {
try
{
@@ -561,6 +575,7 @@ void cancel_this_thread_alarm()
itimer_virt.cancel_this_thread();
}

+OSV_LIBC_API
unsigned int alarm(unsigned int seconds)
{
unsigned int ret;
@@ -579,7 +594,8 @@ unsigned int alarm(unsigned int seconds)
return ret;
}

-extern "C" int setitimer(int which, const struct itimerval *new_value,
+extern "C" OSV_LIBC_API
+int setitimer(int which, const struct itimerval *new_value,
struct itimerval *old_value)
{
switch (which) {
@@ -592,7 +608,8 @@ extern "C" int setitimer(int which, const struct itimerval *new_value,
}
}

-extern "C" int getitimer(int which, struct itimerval *curr_value)
+extern "C" OSV_LIBC_API
+int getitimer(int which, struct itimerval *curr_value)
{
switch (which) {
case ITIMER_REAL:
@@ -617,6 +634,7 @@ extern "C" int getitimer(int which, struct itimerval *curr_value)
static __thread void* signal_stack_begin;
static __thread size_t signal_stack_size;

+OSV_LIBC_API
int sigaltstack(const stack_t *ss, stack_t *oss)
{
if (oss) {
@@ -649,14 +667,16 @@ int sigaltstack(const stack_t *ss, stack_t *oss)
return 0;
}

-extern "C" int signalfd(int fd, const sigset_t *mask, int flags)
+extern "C" OSV_LIBC_API
+int signalfd(int fd, const sigset_t *mask, int flags)
{
WARN_STUBBED();
errno = ENOSYS;
return -1;
}

-extern "C" int sigwaitinfo(const sigset_t *__restrict mask,
+extern "C" OSV_LIBC_API
+int sigwaitinfo(const sigset_t *__restrict mask,
siginfo_t *__restrict si)
{
int signo;
diff --git a/libc/time.cc b/libc/time.cc
index 8aa11580..2660eb86 100644
--- a/libc/time.cc
+++ b/libc/time.cc
@@ -20,7 +20,7 @@ u64 convert(const timespec& ts)
return ts.tv_sec * 1000000000 + ts.tv_nsec;
}

-extern "C"
+extern "C" OSV_LIBC_API
int gettimeofday(struct timeval* tv, struct timezone* tz)
{
if (!tv) {
@@ -33,12 +33,14 @@ int gettimeofday(struct timeval* tv, struct timezone* tz)
return 0;
}

+OSV_LIBC_API
int nanosleep(const struct timespec* req, struct timespec* rem)
{
sched::thread::sleep(std::chrono::nanoseconds(convert(*req)));
return 0;
}

+OSV_LIBC_API
int usleep(useconds_t usec)
{
sched::thread::sleep(std::chrono::microseconds(usec));
@@ -55,6 +57,7 @@ static inline void fill_ts(std::chrono::duration<Rep, Period> d, timespec *ts)
ts->tv_nsec = duration_cast<nanoseconds>(d).count() % 1000000000;
}

+OSV_LIBC_API
int clock_gettime(clockid_t clk_id, struct timespec* ts)
{
switch (clk_id) {
@@ -85,9 +88,10 @@ int clock_gettime(clockid_t clk_id, struct timespec* ts)
return 0;
}

-extern "C"
+extern "C" OSV_LIBC_API
int __clock_gettime(clockid_t clk_id, struct timespec* ts) __attribute__((alias("clock_gettime")));

+OSV_LIBC_API
int clock_getres(clockid_t clk_id, struct timespec* ts)
{
switch (clk_id) {
@@ -110,11 +114,13 @@ int clock_getres(clockid_t clk_id, struct timespec* ts)
return 0;
}

+OSV_LIBC_API
int clock_getcpuclockid(pid_t pid, clockid_t* clock_id)
{
return CLOCK_PROCESS_CPUTIME_ID;
}

+OSV_LIBC_API
clock_t clock(void)
{
struct timespec ts;
diff --git a/libc/timerfd.cc b/libc/timerfd.cc
index 70500dca..a5118a0e 100644
--- a/libc/timerfd.cc
+++ b/libc/timerfd.cc
@@ -229,6 +229,7 @@ int timerfd::poll(int events)
// After this long introduction, without further ado, let's implement Linux's
// three <sys/timerfd.h> functions:

+OSV_LIBC_API
int timerfd_create(int clockid, int flags) {
switch (clockid) {
case CLOCK_REALTIME:
@@ -258,6 +259,7 @@ static bool check_nsec_validity(long nsec)
return (nsec >= 0 && nsec < second);
}

+OSV_LIBC_API
int timerfd_settime(int fd, int flags, const itimerspec *newval,
itimerspec *oldval)
{
@@ -301,6 +303,7 @@ int timerfd_settime(int fd, int flags, const itimerspec *newval,
return 0;
}

+OSV_LIBC_API
int timerfd_gettime(int fd, itimerspec *val)
{
fileref f(fileref_from_fd(fd));
diff --git a/linux.cc b/linux.cc
index adeb89f0..1c2eea24 100644
--- a/linux.cc
+++ b/linux.cc
@@ -13,6 +13,7 @@
#include <osv/mutex.h>
#include <osv/waitqueue.hh>
#include <osv/stubbing.hh>
+#include <osv/export.h>
#include <memory>

#include <syscall.h>
@@ -44,7 +45,7 @@

extern "C" int eventfd2(unsigned int, int);

-extern "C" long gettid()
+extern "C" OSV_LIBC_API long gettid()
{
return sched::thread::current()->id();
}
@@ -408,7 +409,7 @@ static int tgkill(int tgid, int tid, int sig)
return -1;
}

-long syscall(long number, ...)
+OSV_LIBC_API long syscall(long number, ...)
{
// Save FPU state and restore it at the end of this function
sched::fpu_lock fpu;
diff --git a/runtime.cc b/runtime.cc
index 6a51583e..64a9b225 100644
--- a/runtime.cc
+++ b/runtime.cc
@@ -33,6 +33,7 @@
#include <osv/debug.hh>
#include <boost/format.hpp>
#include <osv/mempool.hh>
+#include <osv/export.h>
#include <pwd.h>
#include <fcntl.h>
#include <osv/barrier.hh>
@@ -138,6 +139,7 @@ void abort(const char *fmt, ...)
}

// __assert_fail() is used by the assert() macros
+OSV_LIBC_API
void __assert_fail(const char *expr, const char *file, unsigned int line, const char *func)
{
abort("Assertion failed: %s (%s: %s: %d)\n", expr, file, func, line);
@@ -190,58 +192,67 @@ void __cxa_finalize(void *dso)
}
}

+OSV_LIBC_API
int getpagesize()
{
return 4096;
}

+OSV_LIBC_API
int vfork()
{
WARN_STUBBED();
return -1;
}

+OSV_LIBC_API
int fork()
{
WARN_STUBBED();
return -1;
}

+OSV_LIBC_API
pid_t setsid(void)
{
WARN_STUBBED();
return -1;
}

-NO_SYS(int execvp(const char *, char *const []));
+NO_SYS(OSV_LIBC_API int execvp(const char *, char *const []));

+OSV_LIBC_API
int mlockall(int flags)
{
WARN_STUBBED();
return 0;
}

+OSV_LIBC_API
int munlockall(void)
{
WARN_STUBBED();
return 0;
}

+OSV_LIBC_API
int mlock(const void*, size_t)
{
WARN_STUBBED();
return 0;
}

+OSV_LIBC_API
int munlock(const void*, size_t)
{
WARN_STUBBED();
return 0;
}

-NO_SYS(int mkfifo(const char*, mode_t));
-NO_SYS(int mkfifoat(int, const char *, mode_t));
+NO_SYS(OSV_LIBC_API int mkfifo(const char*, mode_t));
+NO_SYS(OSV_LIBC_API int mkfifoat(int, const char *, mode_t));

+OSV_LIBC_API
int posix_fadvise(int fd, off_t offset, off_t len, int advice)
{
switch (advice) {
@@ -256,14 +267,16 @@ int posix_fadvise(int fd, off_t offset, off_t len, int advice)
return EINVAL;
}
}
-LFS64(posix_fadvise);
+LFS64(posix_fadvise) __attribute__((nothrow));

+OSV_LIBC_API
int posix_fallocate(int fd, off_t offset, off_t len)
{
return ENOSYS;
}
-LFS64(posix_fallocate);
+LFS64(posix_fallocate) __attribute__((nothrow));

+OSV_LIBC_API
int getpid()
{
return OSV_PID;
@@ -285,8 +298,10 @@ static struct __locale_struct c_locale = {

locale_t __c_locale_ptr = &c_locale;

+OSV_LIBC_API
void* __stack_chk_guard = reinterpret_cast<void*>(0x12345678abcdefull);
-extern "C" void __stack_chk_fail(void) {
+extern "C" OSV_LIBC_API
+void __stack_chk_fail(void) {
abort("__stack_chk_fail(): Stack overflow detected. Aborting.\n");
}

@@ -309,7 +324,7 @@ struct __locale_data {
#define _NL_CTYPE_TOUPPER 1
#define _NL_CTYPE_TOLOWER 3

-extern "C"
+extern "C" OSV_LIBC_API
__locale_t __newlocale(int category_mask, const char *locale, locale_t base)
__THROW
{
@@ -341,6 +356,7 @@ __locale_t __newlocale(int category_mask, const char *locale, locale_t base)
return nullptr;
}

+OSV_LIBC_API
long sysconf(int name)
{
switch (name) {
@@ -363,17 +379,20 @@ long sysconf(int name)
}
}

+OSV_LIBC_API
long pathconf(const char *, int name)
{
return fpathconf(-1, name);
}

+OSV_LIBC_API
long fpathconf(int, int)
{
WARN_STUBBED();
return -1;
}

+OSV_LIBC_API
size_t confstr(int name, char* buf, size_t len)
{
const char* v = nullptr;
@@ -396,12 +415,14 @@ size_t confstr(int name, char* buf, size_t len)
}
}

+OSV_LIBC_API
FILE *popen(const char *command, const char *type)
{
WARN_STUBBED();
return NULL;
}

+OSV_LIBC_API
int pclose(FILE *stream)
{
return 0;
@@ -417,17 +438,20 @@ void exit(int status)
// registered with atexit(3) or on_exit(3)."
//

+OSV_LIBC_API
int atexit(void (*func)())
{
// nothing to do
return 0;
}

+OSV_LIBC_API
int get_nprocs()
{
return sysconf(_SC_NPROCESSORS_ONLN);
}

+OSV_LIBC_API
clock_t times(struct tms *buffer)
{
using namespace std::chrono;
@@ -493,6 +517,7 @@ static int prio_find_thread(sched::thread **th, int which, int id)
//
static constexpr float prio_k = log(86) / 20;

+OSV_LIBC_API
int getpriority(int which, int id)
{
sched::thread *th;
@@ -520,6 +545,7 @@ int getpriority(int which, int id)
return prio;
}

+OSV_LIBC_API
int setpriority(int which, int id, int prio)
{
sched::thread *th;
@@ -536,12 +562,14 @@ int setpriority(int which, int id, int prio)
return 0;
}

+OSV_LIBC_API
int initgroups(const char *user, gid_t group)
{
WARN_STUBBED();
return -1;
}

+OSV_LIBC_API
int prctl(int option, ...)
{
switch (option) {
@@ -552,13 +580,14 @@ int prctl(int option, ...)
return -1;
}

+OSV_LIBC_API
int daemon(int nochdir, int noclose)
{
WARN_STUBBED();
return -1;
}

-extern "C"
+extern "C" OSV_LIBC_API
int sysctl(int *, int, void *, size_t *, void *, size_t)
{
WARN_STUBBED();
@@ -566,12 +595,13 @@ int sysctl(int *, int, void *, size_t *, void *, size_t)
return -1;
}

-extern "C"
+extern "C" OSV_LIBC_API
char *tmpnam_r(char *s)
{
return s ? tmpnam(s) : NULL;
}

+OSV_LIBC_API
pid_t wait3(int *status, int options, struct rusage *usage)
{
WARN_STUBBED();
@@ -579,6 +609,7 @@ pid_t wait3(int *status, int options, struct rusage *usage)
return -1;
}

+OSV_LIBC_API
pid_t wait4(pid_t pid, int *status, int options, struct rusage *usage)
{
WARN_STUBBED();
@@ -586,6 +617,7 @@ pid_t wait4(pid_t pid, int *status, int options, struct rusage *usage)
return -1;
}

+OSV_LIBC_API
int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
{
WARN_STUBBED();
@@ -593,6 +625,7 @@ int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
return -1;
}

+OSV_LIBC_API
int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
{
WARN_STUBBED();
@@ -600,6 +633,7 @@ int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
return -1;
}

+OSV_LIBUTIL_API
int openpty(int *amaster, int *aslave, char *name,
const struct termios *termp,
const struct winsize *winp)
@@ -609,6 +643,7 @@ int openpty(int *amaster, int *aslave, char *name,
return -1;
}

+OSV_LIBUTIL_API
pid_t forkpty(int *amaster, char *name,
const struct termios *termp,
const struct winsize *winp)
@@ -618,11 +653,13 @@ pid_t forkpty(int *amaster, char *name,
return -1;
}

+OSV_LIBC_API
int nice(int inc)
{
return setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS, 0)+inc);
}

+OSV_LIBC_API
char *ctermid(char *s)
{
static char s2[L_ctermid];
@@ -633,4 +670,5 @@ char *ctermid(char *s)
}

// OSv is always multi-threaded.

Commit Bot

unread,
Nov 28, 2021, 11:19:01 AM11/28/21
to osv...@googlegroups.com, Waldemar Kozaczuk
From: Waldemar Kozaczuk <jwkoz...@gmail.com>
Committer: Waldemar Kozaczuk <jwkoz...@gmail.com>
Branch: master

prepare to hide kernel symbols: expose libc symbols in certain files

This 2nd patch in the series annotates number of standard glibc symbols
across number of source files, mostly under bsd, core, fs and libc
folders. This does not have any effect until we introduce the changes to
the makefile to support compiling kernel with most symbols hidden.

We choose to annotate the symbols that need to be exposed because the relevant files
will be compiled with the flag '-fvisibility=hidden' which would hide
all symbols unless annotated otherwise which takes precedence. This
approach helps to minimize the number of symbols that need to be annotated.
certain files

Comparing to the version 1 of this patch, this one differs in the following
ways:
- removes changes made to bsd/sys/netinet/in.n, bsd/sys/rpc/xdr.h,
bsd/sys/sys/md5.h and bsd/sys/sys/libkern.h to avoid exposing symbols
originating from FreeBSD kernel that may not be completely compatible
with Linux
- moves some of the OSV_*API annotation from header files to the source
files

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>

---
diff --git a/arch/aarch64/feexcept.cc b/arch/aarch64/feexcept.cc
--- a/arch/x64/feexcept.cc
+++ b/arch/x64/feexcept.cc
@@ -8,7 +8,9 @@
#include <osv/types.h>
#include <fenv.h>
#include <__fenv.h>
+#include <osv/export.h>

+OSV_LIBM_API
int feenableexcept(int mask)
{
// The feenableexcept() manual page suggests that -1 should be returned
@@ -38,6 +40,7 @@ int feenableexcept(int mask)
return ret;
}

+OSV_LIBM_API
int fedisableexcept(int mask)
{
mask &= FE_ALL_EXCEPT;
@@ -56,6 +59,7 @@ int fedisableexcept(int mask)
return ret;
}

+OSV_LIBM_API
int fegetexcept()
{
u16 cw;
diff --git a/bsd/sys/kern/uipc_syscalls_wrap.cc b/bsd/sys/kern/uipc_syscalls_wrap.cc
--- a/bsd/sys/xen/xenstore/xenstore.cc
+++ b/bsd/sys/xen/xenstore/xenstore.cc
@@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$");

#include <xen/xenstore/xenstorevar.h>
#include <xen/xenstore/xenstore_internal.h>
+#include <osv/export.h>

#include <vm/vm.h>
#include <vm/pmap.h>
@@ -1316,6 +1317,7 @@ class xs_sbuf {
--- a/core/app.cc
+++ b/core/app.cc
@@ -11,6 +11,7 @@
#include <osv/run.hh>
#include <osv/power.hh>
#include <osv/trace.hh>
+#include <osv/export.h>
#include <functional>
#include <thread>
#include <libgen.h>
@@ -26,9 +27,11 @@ extern int optind;

// Java uses this global variable (supplied by Glibc) to figure out
// aproximatively where the initial thread's stack end.
+OSV_LD_LINUX_x86_64_API
void *__libc_stack_end;

-extern "C" void __libc_start_main(int (*main)(int, char**), int, char**,
+extern "C" OSV_LIBC_API
+void __libc_start_main(int (*main)(int, char**), int, char**,
void(*)(), void(*)(), void(*)(), void*)
{
auto app = osv::application::get_current();
diff --git a/core/elf.cc b/core/elf.cc
--- a/core/epoll.cc
+++ b/core/epoll.cc
@@ -21,6 +21,7 @@
#include <boost/lockfree/policies.hpp>

#include <osv/debug.hh>
+#include <osv/export.h>
#include <unordered_map>
#include <boost/range/algorithm/find.hpp>
#include <algorithm>
@@ -248,6 +249,7 @@ class epoll_file final : public special_file {
}
};

+OSV_LIBC_API
int epoll_create(int size)
{
// Note we ignore the size parameter. There's no point in checking it's
@@ -256,6 +258,7 @@ int epoll_create(int size)
return epoll_create1(0);
}

+OSV_LIBC_API
int epoll_create1(int flags)
{
flags &= ~EPOLL_CLOEXEC;
@@ -272,6 +275,7 @@ int epoll_create1(int flags)
}
}

+OSV_LIBC_API
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
{
trace_epoll_ctl(epfd, fd,
@@ -321,6 +325,7 @@ int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
}
}

+OSV_LIBC_API
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout_ms)
{
trace_epoll_wait(epfd, maxevents, timeout_ms);
@@ -339,6 +344,7 @@ int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout_
return epo->wait(events, maxevents, timeout_ms);
}

+OSV_LIBC_API
int epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout_ms,
const sigset_t *sigmask)
{
diff --git a/core/libaio.cc b/core/libaio.cc
--- a/core/libaio.cc
+++ b/core/libaio.cc
@@ -11,7 +11,9 @@
#include <api/libaio.h>

#include <osv/stubbing.hh>
+#include <osv/export.h>

+OSV_LIBAIO_API
int io_setup(int nr_events, io_context_t *ctxp_idp) {
// This is a stub that doesn't actually do anything. If the caller tries
// to follow the io_setup() call with any other libaio call, those will
@@ -23,8 +25,8 @@ int io_setup(int nr_events, io_context_t *ctxp_idp) {
return 0;
}

-UNIMPL(int io_submit(io_context_t ctx, long nr, struct iocb *ios[]))
-UNIMPL(int io_getevents(io_context_t ctx_id, long min_nr, long nr,
+UNIMPL(OSV_LIBAIO_API int io_submit(io_context_t ctx, long nr, struct iocb *ios[]))
+UNIMPL(OSV_LIBAIO_API int io_getevents(io_context_t ctx_id, long min_nr, long nr,
struct io_event *events, struct timespec *timeout))
-UNIMPL(int io_destroy(io_context_t ctx))
-UNIMPL(int io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt))
+UNIMPL(OSV_LIBAIO_API int io_destroy(io_context_t ctx))
+UNIMPL(OSV_LIBAIO_API int io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt))
diff --git a/core/math.cc b/core/math.cc
--- a/core/mempool.cc
+++ b/core/mempool.cc
@@ -35,6 +35,7 @@
#include <boost/lockfree/stack.hpp>
#include <boost/lockfree/policies.hpp>
#include <osv/migration-lock.hh>
+#include <osv/export.h>

TRACEPOINT(trace_memory_malloc, "buf=%p, len=%d, align=%d", void *, size_t,
size_t);
@@ -2010,14 +2011,16 @@ void* malloc(size_t size)
return buf;
}

+OSV_LIBC_API
void* realloc(void* obj, size_t size)
{
void* buf = std_realloc(obj, size);
trace_memory_realloc(obj, size, buf);
return buf;
}

-extern "C" void *reallocarray(void *ptr, size_t nmemb, size_t elem_size)
+extern "C" OSV_LIBC_API
+void *reallocarray(void *ptr, size_t nmemb, size_t elem_size)
{
size_t bytes;
if (__builtin_mul_overflow(nmemb, elem_size, &bytes)) {
@@ -2027,6 +2030,7 @@ extern "C" void *reallocarray(void *ptr, size_t nmemb, size_t elem_size)
return realloc(ptr, nmemb * elem_size);
}

+OSV_LIBC_API
size_t malloc_usable_size(void* obj)
{
if ( obj == nullptr ) {
@@ -2079,6 +2083,7 @@ void *aligned_alloc(size_t alignment, size_t size)
// that size be a multiple of alignment.
// memalign() is considered to be an obsolete SunOS-ism, but Linux's glibc
// supports it, and some applications still use it.
+OSV_LIBC_API
void *memalign(size_t alignment, size_t size)
{
return aligned_alloc(alignment, size);
diff --git a/core/poll.cc b/core/poll.cc
--- a/core/power.cc
+++ b/core/power.cc
@@ -7,6 +7,7 @@

#include <osv/power.hh>
#include <osv/debug.hh>
+#include <osv/export.h>
#include <smp.hh>
#include <processor.hh>
#include <arch.hh>
@@ -20,6 +21,7 @@
// is questionable (e.g., abort()) so a debug() call might call further
// problems.

+OSV_LIBC_API
int reboot(int cmd)
{
switch (cmd) {
diff --git a/core/select.cc b/core/select.cc
--- a/core/select.cc
+++ b/core/select.cc
@@ -10,13 +10,15 @@
#include <errno.h>
#include <signal.h>
#include <osv/poll.h>
+#include <osv/export.h>
#include <osv/debug.h>
#include <api/sys/select.h>
#include <bsd/porting/synch.h>

#define select_d(...) tprintf_d("select", __VA_ARGS__)

/* Basic select() implementation on top of poll() */
+OSV_LIBC_API
int select (int nfds,
fd_set * readfds,
fd_set * writefds,
@@ -184,6 +186,7 @@ int select (int nfds,
}

/* Basic pselect() on top of select() */
+OSV_LIBC_API
int pselect(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, const struct timespec *timeout_ts,
const sigset_t *sigmask)
@@ -203,7 +206,8 @@ int pselect(int nfds, fd_set *readfds, fd_set *writefds,
return ret;
}

-extern "C" unsigned long int
+extern "C" OSV_LIBC_API
+unsigned long int
__fdelt_chk (unsigned long int d)
{
if (d >= FD_SETSIZE)
diff --git a/fs/vfs/kern_descrip.cc b/fs/vfs/kern_descrip.cc
--- a/fs/vfs/kern_descrip.cc
+++ b/fs/vfs/kern_descrip.cc
@@ -14,6 +14,7 @@
#include <osv/debug.h>
#include <osv/mutex.h>
#include <osv/rcu.hh>
+#include <osv/export.h>
#include <boost/range/algorithm/find.hpp>

#include <bsd/sys/sys/queue.h>
@@ -61,7 +62,7 @@ int _fdalloc(struct file *fp, int *newfd, int min_fd)
return EMFILE;
}

-extern "C"
+extern "C" OSV_LIBC_API
int getdtablesize(void)
{
return FDMAX;
diff --git a/fs/vfs/main.cc b/fs/vfs/main.cc
@@ -701,13 +724,15 @@ int dirfd(DIR *dirp)
return dirp->fd;
}

+OSV_LIBC_API
int closedir(DIR *dir)
{
close(dir->fd);
delete dir;
@@ -2118,6 +2179,7 @@ int chmod(const char *pathname, mode_t mode)
TRACEPOINT(trace_vfs_fchmod, "\"%d\" 0%0o", int, mode_t);
TRACEPOINT(trace_vfs_fchmod_ret, "");

+OSV_LIBC_API
int fchmod(int fd, mode_t mode)
{
trace_vfs_fchmod(fd, mode);
@@ -2134,6 +2196,7 @@ int fchmod(int fd, mode_t mode)
TRACEPOINT(trace_vfs_fchown, "\"%d\" %d %d", int, uid_t, gid_t);
TRACEPOINT(trace_vfs_fchown_ret, "");

+OSV_LIBC_API
int fchown(int fd, uid_t owner, gid_t group)
{
trace_vfs_fchown(fd, owner, group);
@@ -2142,19 +2205,22 @@ int fchown(int fd, uid_t owner, gid_t group)
return 0;
}

+OSV_LIBC_API
int chown(const char *path, uid_t owner, gid_t group)
{
WARN_STUBBED();
return 0;
}

+OSV_LIBC_API
int lchown(const char *path, uid_t owner, gid_t group)
{
WARN_STUBBED();
return 0;
}


+OSV_LIBC_API
ssize_t sendfile(int out_fd, int in_fd, off_t *_offset, size_t count)
{
struct file *in_fp;
@@ -2236,8 +2302,9 @@ ssize_t sendfile(int out_fd, int in_fd, off_t *_offset, size_t count)
#undef sendfile64
LFS64(sendfile);

-NO_SYS(int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags));
+NO_SYS(OSV_LIBC_API int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags));

+OSV_LIBC_API
mode_t umask(mode_t newmask)
{
return global_umask.exchange(newmask, std::memory_order_relaxed);
@@ -2249,6 +2316,7 @@ fs_noop(void)
return 0;
}

+OSV_LIBC_API
int chroot(const char *path)
{
WARN_STUBBED();
diff --git a/include/osv/export.h b/include/osv/export.h
--- a/include/osv/export.h
+++ b/include/osv/export.h
@@ -25,7 +25,6 @@
#define OSV_LIBAIO_API __attribute__((__visibility__("default")))
#define OSV_LIBC_API __attribute__((__visibility__("default")))
#define OSV_LIBM_API __attribute__((__visibility__("default")))
-#define OSV_LIBBSD_API __attribute__((__visibility__("default")))
#define OSV_LIBPTHREAD_API __attribute__((__visibility__("default")))
#define OSV_LIBUTIL_API __attribute__((__visibility__("default")))
#define OSV_LIBXENSTORE_API __attribute__((__visibility__("default")))
diff --git a/include/osv/sched.hh b/include/osv/sched.hh
--- a/include/osv/sched.hh
+++ b/include/osv/sched.hh
@@ -25,6 +25,7 @@
#include <osv/rcu.hh>
#include <osv/clock.hh>
#include <osv/timer-set.hh>
+#include <osv/export.h>
#include <string.h>

typedef float runtime_t;
diff --git a/libc/eventfd.cc b/libc/eventfd.cc
--- a/libc/eventfd.cc
+++ b/libc/eventfd.cc
@@ -178,6 +178,7 @@ int event_fd::poll(int events)
return rc;
}

+OSV_LIBC_API
int eventfd(unsigned int initval, int flags)
{
if (flags & (~(EFD_CLOEXEC | EFD_NONBLOCK | EFD_SEMAPHORE))) {
@@ -209,6 +210,7 @@ int eventfd(unsigned int initval, int flags)
}
weak_alias(eventfd, eventfd2);

+OSV_LIBC_API
int eventfd_read(int fd, eventfd_t *value)
{
fileref f(fileref_from_fd(fd));
@@ -231,6 +233,7 @@ int eventfd_read(int fd, eventfd_t *value)
return 0;
}

+OSV_LIBC_API
int eventfd_write(int fd, eventfd_t value)
{
fileref f(fileref_from_fd(fd));
diff --git a/libc/internal/libc.h b/libc/internal/libc.h
--- a/libc/internal/libc.h
+++ b/libc/internal/libc.h
@@ -3,6 +3,7 @@

#include <stdlib.h>
#include <osv/mutex.h>
+#include <osv/export.h>
#include "stdio.h"

__BEGIN_DECLS
@@ -49,7 +50,7 @@ extern char **__environ;
#endif

#undef LFS64_2
-#define LFS64_2(x, y) weak_alias(x, y)
+#define LFS64_2(x, y) weak_alias(x, y) OSV_LIBC_API

#undef LFS64
#define LFS64(x) LFS64_2(x, x##64)
diff --git a/libc/misc/getopt.cc b/libc/misc/getopt.cc
--- a/libc/misc/getopt.cc
+++ b/libc/misc/getopt.cc
@@ -8,11 +8,13 @@

extern "C" {

+OSV_LIBC_API
char *optarg;
+OSV_LIBC_API
int optind=1, opterr=1, optopt, __optpos, __optreset=0;

#define optpos __optpos
-weak_alias(__optreset, optreset);
+weak_alias(__optreset, optreset) OSV_LIBC_API;

int __getopt(int argc, char * const argv[], const char *optstring)
{
@@ -74,11 +76,12 @@ int __getopt(int argc, char * const argv[], const char *optstring)
return c;
}

+OSV_LIBC_API
int getopt(int argc, char * const argv[], const char *optstring)
{
getopt_caller_vars_copier guard;
return __getopt(argc, argv, optstring);
}

-weak_alias(getopt, __posix_getopt);
+weak_alias(getopt, __posix_getopt) OSV_LIBC_API;
}
diff --git a/libc/misc/getopt_long.cc b/libc/misc/getopt_long.cc
--- a/libc/misc/getopt_long.cc
+++ b/libc/misc/getopt_long.cc
@@ -1,6 +1,7 @@
#include <stddef.h>
#include <getopt.h>
#include <stdio.h>
+#include <osv/export.h>
#include "getopt.hh"

extern "C" {
@@ -52,11 +53,13 @@ static int __getopt_long(int argc, char *const *argv, const char *optstring, con
return __getopt(argc, argv, optstring);
}

+OSV_LIBC_API
int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
{
return __getopt_long(argc, argv, optstring, longopts, idx, 0);
}

+OSV_LIBC_API
int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
{
return __getopt_long(argc, argv, optstring, longopts, idx, 1);
diff --git a/libc/misc/mntent.cc b/libc/misc/mntent.cc
@@ -230,19 +235,22 @@ int mincore(void *addr, size_t length, unsigned char *vec)
return mmu::mincore(addr, length, vec).to_libc();
}

+OSV_LIBC_API
int madvise(void *addr, size_t length, int advice)
{
auto err = mmu::advise(addr, length, libc_madvise_to_advise(advice));
return err.to_libc();
}

+OSV_LIBC_API
int brk(void *addr)
{
WARN_STUBBED();
errno = ENOMEM;
return -1;
}

+OSV_LIBC_API
void *sbrk(intptr_t increment)
{
WARN_STUBBED();
diff --git a/libc/pipe.cc b/libc/pipe.cc
--- a/libc/pipe.cc
+++ b/libc/pipe.cc
@@ -86,6 +86,7 @@ int pipe_file::close()
return 0;
}

+OSV_LIBC_API
int pipe2(int pipefd[2], int flags) {
if (flags & ~(O_NONBLOCK | O_CLOEXEC)) {
return libc_error(EINVAL);
@@ -115,6 +116,7 @@ int pipe2(int pipefd[2], int flags) {
}
}

+OSV_LIBC_API
int pipe(int pipefd[2])
{
return pipe2(pipefd, 0);
diff --git a/libc/pthread.cc b/libc/pthread.cc
--- a/libc/resource.cc
+++ b/libc/resource.cc
@@ -34,4 +34,3 @@ int getrusage(int who, struct rusage *usage)
}
return 0;
}
-LFS64(getrusage);
diff --git a/libc/sem.cc b/libc/sem.cc
--- a/libc/sem.cc
+++ b/libc/sem.cc
@@ -23,31 +23,36 @@ indirect_semaphore& from_libc(sem_t* p)
return *reinterpret_cast<indirect_semaphore*>(p);
}

+OSV_LIBC_API
int sem_init(sem_t* s, int pshared, unsigned val)
{
static_assert(sizeof(indirect_semaphore) <= sizeof(*s), "sem_t overflow");
new (s) indirect_semaphore(val);
return 0;
}

+OSV_LIBC_API
int sem_destroy(sem_t *s)
{
from_libc(s).~indirect_semaphore();
return 0;
}

+OSV_LIBC_API
int sem_post(sem_t* s)
{
from_libc(s)->post();
return 0;
}

+OSV_LIBC_API
int sem_wait(sem_t* s)
{
from_libc(s)->wait();
return 0;
}

+OSV_LIBC_API
int sem_timedwait(sem_t* s, const struct timespec *abs_timeout)
{
if ((abs_timeout->tv_sec < 0) || (abs_timeout->tv_nsec < 0) || (abs_timeout->tv_nsec > 1000000000LL)) {
@@ -64,6 +69,7 @@ int sem_timedwait(sem_t* s, const struct timespec *abs_timeout)
return 0;
}

+OSV_LIBC_API
int sem_trywait(sem_t* s)
{
if (!from_libc(s)->trywait())
diff --git a/libc/signal.cc b/libc/signal.cc
@@ -256,19 +264,22 @@ static sighandler_t signal(int signum, sighandler_t handler, int sa_flags)
}
}

+OSV_LIBC_API
sighandler_t signal(int signum, sighandler_t handler)
{
return signal(signum, handler, SA_RESTART);
}

extern "C"
+OSV_LIBC_API
sighandler_t __sysv_signal(int signum, sighandler_t handler)
{
return signal(signum, handler, SA_RESETHAND | SA_NODEFER);
}

--- a/libc/timerfd.cc
+++ b/libc/timerfd.cc
@@ -229,6 +229,7 @@ int timerfd::poll(int events)
// After this long introduction, without further ado, let's implement Linux's
// three <sys/timerfd.h> functions:

+OSV_LIBC_API
int timerfd_create(int clockid, int flags) {
switch (clockid) {
case CLOCK_REALTIME:
@@ -258,6 +259,7 @@ static bool check_nsec_validity(long nsec)
return (nsec >= 0 && nsec < second);
}

+OSV_LIBC_API
int timerfd_settime(int fd, int flags, const itimerspec *newval,
itimerspec *oldval)
{
@@ -301,6 +303,7 @@ int timerfd_settime(int fd, int flags, const itimerspec *newval,
return 0;
}

+OSV_LIBC_API
int timerfd_gettime(int fd, itimerspec *val)
{
fileref f(fileref_from_fd(fd));
diff --git a/linux.cc b/linux.cc
--- a/linux.cc
+++ b/linux.cc
@@ -13,6 +13,7 @@
#include <osv/mutex.h>
#include <osv/waitqueue.hh>
#include <osv/stubbing.hh>
+#include <osv/export.h>
#include <memory>

#include <syscall.h>
@@ -44,7 +45,7 @@

extern "C" int eventfd2(unsigned int, int);

-extern "C" long gettid()
+extern "C" OSV_LIBC_API long gettid()
{
return sched::thread::current()->id();
}
@@ -408,7 +409,7 @@ static int tgkill(int tgid, int tid, int sig)
return -1;
}

-long syscall(long number, ...)
+OSV_LIBC_API long syscall(long number, ...)
{
// Save FPU state and restore it at the end of this function
sched::fpu_lock fpu;
diff --git a/runtime.cc b/runtime.cc
@@ -552,54 +580,60 @@ int prctl(int option, ...)
return -1;
}

+OSV_LIBC_API
int daemon(int nochdir, int noclose)
{
WARN_STUBBED();
return -1;
}

-extern "C"
+extern "C" OSV_LIBC_API
int sysctl(int *, int, void *, size_t *, void *, size_t)
{
WARN_STUBBED();
errno = ENOTDIR;
return -1;
}

-extern "C"
+extern "C" OSV_LIBC_API
char *tmpnam_r(char *s)
{
return s ? tmpnam(s) : NULL;
}

+OSV_LIBC_API
pid_t wait3(int *status, int options, struct rusage *usage)
{
WARN_STUBBED();
errno = ECHILD;
return -1;
}

+OSV_LIBC_API
pid_t wait4(pid_t pid, int *status, int options, struct rusage *usage)
{
WARN_STUBBED();
errno = ECHILD;
return -1;
}

+OSV_LIBC_API
int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
{
WARN_STUBBED();
errno = ENOSYS;
return -1;
}

+OSV_LIBC_API
int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
{
WARN_STUBBED();
errno = ENOSYS;
return -1;
}

Reply all
Reply to author
Forward
0 new messages