From c523961d00e777a94904892bddf3deb58440f0ab Mon Sep 17 00:00:00 2001 From: Sheldon Qi <3365420+xdqi@users.noreply.github.com> Date: Sun, 4 Oct 2026 21:31:34 +0800 Subject: [PATCH 1/6] lkl: add lkl_long_t for LLP64 hosts On Win64 (MinGW-w64) long is 32 bit (LLP64) while the LKL kernel is built for LP64, where long is 64 bit. Using long in the host interface breaks syscall parameters, UAPI struct layouts and pointer casts between the application and the kernel. Add lkl_long_t / lkl_ulong_t (arch/lkl/include/uapi/asm/lkl_long.h), which are long long on LLP64 hosts and long everywhere else, so nothing changes for the existing hosts. headers_install.py replaces long with lkl_long_t in the installed UAPI headers and adds the lkl_long.h include. The host library and the tests use lkl_long_t for syscall parameters, ioctl pointer casts and return values, and print them with %lld. Also fix the case of the Windows header names in virtio_net_wintap.c so it builds on case sensitive file systems. Signed-off-by: Sheldon Qi <3365420+xdqi@users.noreply.github.com> --- arch/lkl/include/uapi/asm/lkl_long.h | 28 +++++++++++ arch/lkl/scripts/headers_install.py | 34 +++++++++++++ tools/lkl/include/lkl.h | 61 ++++++++++++----------- tools/lkl/lib/fs.c | 18 +++---- tools/lkl/lib/iomem.c | 2 +- tools/lkl/lib/iomem.h | 2 +- tools/lkl/lib/net.c | 20 ++++---- tools/lkl/lib/nt-host.c | 5 +- tools/lkl/lib/posix-host.c | 28 +++++------ tools/lkl/lib/vfio_pci.c | 8 +-- tools/lkl/lib/virtio.c | 10 ++-- tools/lkl/lib/virtio_net_wintap.c | 4 +- tools/lkl/tests/boot.c | 74 ++++++++++++++-------------- tools/lkl/tests/disk-vfio-pci.c | 2 +- tools/lkl/tests/disk.c | 4 +- tools/lkl/tests/test-dlmopen.c | 8 +-- 16 files changed, 187 insertions(+), 121 deletions(-) create mode 100644 arch/lkl/include/uapi/asm/lkl_long.h diff --git a/arch/lkl/include/uapi/asm/lkl_long.h b/arch/lkl/include/uapi/asm/lkl_long.h new file mode 100644 index 00000000000000..91adf0451e38e8 --- /dev/null +++ b/arch/lkl/include/uapi/asm/lkl_long.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _ASM_UAPI_LKL_LONG_H +#define _ASM_UAPI_LKL_LONG_H + +/* + * lkl_long_t / lkl_ulong_t: pointer-width integer types for the + * LKL cross-world interface (host_ops, syscall dispatch, UAPI structs). + * + * These must be the same size on both sides of the kernel<->host boundary: + * - Kernel side: long = 8 bytes (on Windows the kernel is built with an LP64 + * x86_64-pc-cygwin compiler, see tools/lkl/bin/x86_64-w64-mingw32-gcc) + * - Host side (LLP64 MinGW-w64): long = 4 bytes, need long long + * - Host side (LP64 Linux/Cygwin/macOS): long = 8 bytes + * + * The headers_install.py script replaces all 'long' in generated user + * headers with these types to ensure ABI compatibility across data models. + */ +#if defined(_WIN64) && !defined(__LP64__) +/* LLP64: MinGW-w64 x64 user-space */ +typedef long long lkl_long_t; +typedef unsigned long long lkl_ulong_t; +#else +/* LP64: kernel side, Linux, Cygwin, macOS, or any ILP32 system */ +typedef long lkl_long_t; +typedef unsigned long lkl_ulong_t; +#endif + +#endif /* _ASM_UAPI_LKL_LONG_H */ diff --git a/arch/lkl/scripts/headers_install.py b/arch/lkl/scripts/headers_install.py index 7d3a889bfa2d5f..0075585edf91f1 100755 --- a/arch/lkl/scripts/headers_install.py +++ b/arch/lkl/scripts/headers_install.py @@ -107,6 +107,7 @@ def lkl_prefix(self, w): def install_headers(self): self.find_headers("arch/lkl/include/uapi/asm/syscalls.h") self.headers.add("arch/lkl/include/uapi/asm/host_ops.h") + self.headers.add("arch/lkl/include/uapi/asm/lkl_long.h") self.find_headers("include/uapi/linux/android/binder.h") self.find_headers("include/uapi/linux/uhid.h") self.find_headers("include/uapi/linux/mman.h") @@ -166,6 +167,37 @@ def find_all_symbols(self): # needed for i386 self.defines.add("__NR_stime") + + def replace_long_types(self, content, h): + """Replace 'long' and 'unsigned long' with lkl_long_t/lkl_ulong_t + for LLP64 compatibility, preserving 'long long' and 'long double'.""" + # Skip lkl_long.h itself + if 'lkl_long.h' in h: + return content + # Step 1: protect 'long long' and 'long double' with placeholders + content = re.sub(r'\blong\s+long\b', '__LKLPH_LONGLONG__', content) + content = re.sub(r'\blong\s+double\b', '__LKLPH_LONGDOUBLE__', content) + # Step 2: replace 'unsigned long [int]' (now safe, no 'long long' present) + content = re.sub(r'\bunsigned\s+long(?:\s+int)?\b', 'lkl_ulong_t', content) + # Step 3: replace remaining 'long [int]' + content = re.sub(r'\blong(?:\s+int)?\b', 'lkl_long_t', content) + # Step 4: restore placeholders + content = content.replace('__LKLPH_LONGLONG__', 'long long') + content = content.replace('__LKLPH_LONGDOUBLE__', 'long double') + # Step 5: add include for lkl_long_t definition if replacements were made + if 'lkl_long_t' in content or 'lkl_ulong_t' in content: + # Insert after the first #ifndef/#define guard or at the top + include_line = '#include \n' + if include_line not in content: + # Insert after the header guard #define + m = re.search(r'(#ifndef\s+\w+\s*\n#define\s+\w+\s*\n)', content) + if m: + pos = m.end() + content = content[:pos] + '\n' + include_line + '\n' + content[pos:] + else: + content = include_line + content + return content + def update_header(self, h): # h is a .raw tmp file produced by install_headers(); the final # destination is h without the .raw suffix. @@ -192,6 +224,8 @@ def update_header(self, h): search_str = r"(\W?union\s+)" + s + r"(\W)" replace_str = "\\1" + self.lkl_prefix(s) + "\\2" content = re.sub(search_str, replace_str, content, flags = re.MULTILINE) + # Replace long/unsigned long with lkl_long_t/lkl_ulong_t + content = self.replace_long_types(content, h) content = content.encode() existing = None if os.path.exists(dst) and os.stat(dst).st_size == len(content): diff --git a/tools/lkl/include/lkl.h b/tools/lkl/include/lkl.h index eaf6c4ceebc929..3929847f7d613e 100644 --- a/tools/lkl/include/lkl.h +++ b/tools/lkl/include/lkl.h @@ -21,6 +21,7 @@ extern "C" { #undef __unused #include +#include #pragma pop_macro("__unused") @@ -67,7 +68,7 @@ static inline int lkl_sys_fstatfs(unsigned int fd, struct lkl_statfs *buf) static inline int lkl_sys_nanosleep(struct __lkl__kernel_timespec *rqtp, struct __lkl__kernel_timespec *rmtp) { - long p[6] = {LKL_CLOCK_MONOTONIC, 0, (long)rqtp, (long)rmtp, 0}; + lkl_long_t p[6] = {LKL_CLOCK_MONOTONIC, 0, (lkl_long_t)rqtp, (lkl_long_t)rmtp, 0}; return lkl_syscall(__lkl__NR_clock_nanosleep_time64, p); } @@ -93,7 +94,7 @@ static inline long long lkl_sys_lseek(unsigned int fd, __lkl__kernel_loff_t off, unsigned int whence) { long long res; - long ret = lkl_sys_llseek(fd, off >> 32, off & 0xffffffff, &res, whence); + lkl_long_t ret = lkl_sys_llseek(fd, off >> 32, off & 0xffffffff, &res, whence); return ret < 0 ? ret : res; } @@ -102,7 +103,7 @@ static inline long long lkl_sys_lseek(unsigned int fd, __lkl__kernel_loff_t off, static inline void *lkl_sys_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - return (void *)lkl_sys_mmap_pgoff((long)addr, length, prot, flags, fd, + return (void *)lkl_sys_mmap_pgoff((lkl_long_t)addr, length, prot, flags, fd, offset >> 12); } @@ -112,7 +113,7 @@ static inline void *lkl_sys_mmap(void *addr, size_t length, int prot, int flags, /** * lkl_sys_open - wrapper for lkl_sys_openat */ -static inline long lkl_sys_open(const char *file, int flags, int mode) +static inline lkl_long_t lkl_sys_open(const char *file, int flags, int mode) { return lkl_sys_openat(LKL_AT_FDCWD, file, flags, mode); } @@ -120,7 +121,7 @@ static inline long lkl_sys_open(const char *file, int flags, int mode) /** * lkl_sys_creat - wrapper for lkl_sys_openat */ -static inline long lkl_sys_creat(const char *file, int mode) +static inline lkl_long_t lkl_sys_creat(const char *file, int mode) { return lkl_sys_openat(LKL_AT_FDCWD, file, LKL_O_CREAT|LKL_O_WRONLY|LKL_O_TRUNC, mode); @@ -132,7 +133,7 @@ static inline long lkl_sys_creat(const char *file, int mode) /** * lkl_sys_access - wrapper for lkl_sys_faccessat */ -static inline long lkl_sys_access(const char *file, int mode) +static inline lkl_long_t lkl_sys_access(const char *file, int mode) { return lkl_sys_faccessat(LKL_AT_FDCWD, file, mode); } @@ -142,7 +143,7 @@ static inline long lkl_sys_access(const char *file, int mode) /** * lkl_sys_chown - wrapper for lkl_sys_fchownat */ -static inline long lkl_sys_chown(const char *path, lkl_uid_t uid, lkl_gid_t gid) +static inline lkl_long_t lkl_sys_chown(const char *path, lkl_uid_t uid, lkl_gid_t gid) { return lkl_sys_fchownat(LKL_AT_FDCWD, path, uid, gid, 0); } @@ -152,7 +153,7 @@ static inline long lkl_sys_chown(const char *path, lkl_uid_t uid, lkl_gid_t gid) /** * lkl_sys_chmod - wrapper for lkl_sys_fchmodat */ -static inline long lkl_sys_chmod(const char *path, mode_t mode) +static inline lkl_long_t lkl_sys_chmod(const char *path, mode_t mode) { return lkl_sys_fchmodat(LKL_AT_FDCWD, path, mode); } @@ -162,7 +163,7 @@ static inline long lkl_sys_chmod(const char *path, mode_t mode) /** * lkl_sys_link - wrapper for lkl_sys_linkat */ -static inline long lkl_sys_link(const char *existing, const char *new) +static inline lkl_long_t lkl_sys_link(const char *existing, const char *new) { return lkl_sys_linkat(LKL_AT_FDCWD, existing, LKL_AT_FDCWD, new, 0); } @@ -172,7 +173,7 @@ static inline long lkl_sys_link(const char *existing, const char *new) /** * lkl_sys_unlink - wrapper for lkl_sys_unlinkat */ -static inline long lkl_sys_unlink(const char *path) +static inline lkl_long_t lkl_sys_unlink(const char *path) { return lkl_sys_unlinkat(LKL_AT_FDCWD, path, 0); } @@ -182,7 +183,7 @@ static inline long lkl_sys_unlink(const char *path) /** * lkl_sys_symlink - wrapper for lkl_sys_symlinkat */ -static inline long lkl_sys_symlink(const char *existing, const char *new) +static inline lkl_long_t lkl_sys_symlink(const char *existing, const char *new) { return lkl_sys_symlinkat(existing, LKL_AT_FDCWD, new); } @@ -192,7 +193,7 @@ static inline long lkl_sys_symlink(const char *existing, const char *new) /** * lkl_sys_readlink - wrapper for lkl_sys_readlinkat */ -static inline long lkl_sys_readlink(const char *path, char *buf, size_t bufsize) +static inline lkl_long_t lkl_sys_readlink(const char *path, char *buf, size_t bufsize) { return lkl_sys_readlinkat(LKL_AT_FDCWD, path, buf, bufsize); } @@ -202,7 +203,7 @@ static inline long lkl_sys_readlink(const char *path, char *buf, size_t bufsize) /** * lkl_sys_rename - wrapper for lkl_sys_renameat */ -static inline long lkl_sys_rename(const char *old, const char *new) +static inline lkl_long_t lkl_sys_rename(const char *old, const char *new) { return lkl_sys_renameat(LKL_AT_FDCWD, old, LKL_AT_FDCWD, new); } @@ -212,7 +213,7 @@ static inline long lkl_sys_rename(const char *old, const char *new) /** * lkl_sys_mkdir - wrapper for lkl_sys_mkdirat */ -static inline long lkl_sys_mkdir(const char *path, mode_t mode) +static inline lkl_long_t lkl_sys_mkdir(const char *path, mode_t mode) { return lkl_sys_mkdirat(LKL_AT_FDCWD, path, mode); } @@ -222,7 +223,7 @@ static inline long lkl_sys_mkdir(const char *path, mode_t mode) /** * lkl_sys_rmdir - wrapper for lkl_sys_unlinkrat */ -static inline long lkl_sys_rmdir(const char *path) +static inline lkl_long_t lkl_sys_rmdir(const char *path) { return lkl_sys_unlinkat(LKL_AT_FDCWD, path, LKL_AT_REMOVEDIR); } @@ -232,7 +233,7 @@ static inline long lkl_sys_rmdir(const char *path) /** * lkl_sys_mknod - wrapper for lkl_sys_mknodat */ -static inline long lkl_sys_mknod(const char *path, mode_t mode, dev_t dev) +static inline lkl_long_t lkl_sys_mknod(const char *path, mode_t mode, dev_t dev) { return lkl_sys_mknodat(LKL_AT_FDCWD, path, mode, dev); } @@ -242,7 +243,7 @@ static inline long lkl_sys_mknod(const char *path, mode_t mode, dev_t dev) /** * lkl_sys_pipe - wrapper for lkl_sys_pipe2 */ -static inline long lkl_sys_pipe(int fd[2]) +static inline lkl_long_t lkl_sys_pipe(int fd[2]) { return lkl_sys_pipe2(fd, 0); } @@ -252,7 +253,7 @@ static inline long lkl_sys_pipe(int fd[2]) /** * lkl_sys_send - wrapper for lkl_sys_sendto */ -static inline long lkl_sys_send(int fd, void *buf, size_t len, int flags) +static inline lkl_long_t lkl_sys_send(int fd, void *buf, size_t len, int flags) { return lkl_sys_sendto(fd, buf, len, flags, 0, 0); } @@ -262,7 +263,7 @@ static inline long lkl_sys_send(int fd, void *buf, size_t len, int flags) /** * lkl_sys_recv - wrapper for lkl_sys_recvfrom */ -static inline long lkl_sys_recv(int fd, void *buf, size_t len, int flags) +static inline lkl_long_t lkl_sys_recv(int fd, void *buf, size_t len, int flags) { return lkl_sys_recvfrom(fd, buf, len, flags, 0, 0); } @@ -272,10 +273,10 @@ static inline long lkl_sys_recv(int fd, void *buf, size_t len, int flags) /** * lkl_sys_select - wrapper for lkl_sys_pselect */ -static inline long lkl_sys_select(int n, lkl_fd_set *rfds, lkl_fd_set *wfds, +static inline lkl_long_t lkl_sys_select(int n, lkl_fd_set *rfds, lkl_fd_set *wfds, lkl_fd_set *efds, struct lkl_timeval *tv) { - long data[2] = { 0, _LKL_NSIG/8 }; + lkl_long_t data[2] = { 0, _LKL_NSIG/8 }; struct __lkl__kernel_timespec ts; if (tv) { @@ -293,7 +294,7 @@ static inline long lkl_sys_select(int n, lkl_fd_set *rfds, lkl_fd_set *wfds, /** * lkl_sys_poll - wrapper for lkl_sys_ppoll */ -static inline long lkl_sys_poll(struct lkl_pollfd *fds, int n, int timeout) +static inline lkl_long_t lkl_sys_poll(struct lkl_pollfd *fds, int n, int timeout) { struct __lkl__kernel_timespec ts; @@ -311,7 +312,7 @@ static inline long lkl_sys_poll(struct lkl_pollfd *fds, int n, int timeout) /** * lkl_sys_epoll_create - wrapper for lkl_sys_epoll_create1 */ -static inline long lkl_sys_epoll_create(int size) +static inline lkl_long_t lkl_sys_epoll_create(int size) { return lkl_sys_epoll_create1(0); } @@ -321,7 +322,7 @@ static inline long lkl_sys_epoll_create(int size) /** * lkl_sys_epoll_wait - wrapper for lkl_sys_epoll_pwait */ -static inline long lkl_sys_epoll_wait(int fd, struct lkl_epoll_event *ev, +static inline lkl_long_t lkl_sys_epoll_wait(int fd, struct lkl_epoll_event *ev, int cnt, int to) { return lkl_sys_epoll_pwait(fd, ev, cnt, to, 0, _LKL_NSIG/8); @@ -428,7 +429,7 @@ int lkl_get_virtio_blkdev(int disk_id, unsigned int part, uint32_t *pdevid); * @mnt_str_len - size of mnt_str * @returns - 0 on success, a negative value on error */ -long lkl_mount_dev(unsigned int disk_id, unsigned int part, const char *fs_type, +lkl_long_t lkl_mount_dev(unsigned int disk_id, unsigned int part, const char *fs_type, int flags, const char *opts, char *mnt_str, unsigned int mnt_str_len); @@ -447,7 +448,7 @@ long lkl_mount_dev(unsigned int disk_id, unsigned int part, const char *fs_type, * @mnt_str_len - size of mnt_str * @returns - 0 on success, a negative value on error */ -long lkl_mount_blkdev(unsigned int dev, const char *fs_type, int flags, +lkl_long_t lkl_mount_blkdev(unsigned int dev, const char *fs_type, int flags, const char *opts, char *mnt_str, unsigned int mnt_str_len); @@ -464,8 +465,8 @@ long lkl_mount_blkdev(unsigned int dev, const char *fs_type, int flags, * umount can succeed * @returns - 0 on success, a negative value on error */ -long lkl_umount_dev(unsigned int disk_id, unsigned int part, int flags, - long timeout_ms); +lkl_long_t lkl_umount_dev(unsigned int disk_id, unsigned int part, int flags, + lkl_long_t timeout_ms); /** * lkl_umount_blkdev - umount a block device @@ -478,7 +479,7 @@ long lkl_umount_dev(unsigned int disk_id, unsigned int part, int flags, * umount can succeed * @returns - 0 on success, a negative value on error */ -long lkl_umount_blkdev(unsigned int dev, int flags, long timeout_ms); +lkl_long_t lkl_umount_blkdev(unsigned int dev, int flags, lkl_long_t timeout_ms); /** * lkl_umount_timeout - umount filesystem with timeout @@ -489,7 +490,7 @@ long lkl_umount_blkdev(unsigned int dev, int flags, long timeout_ms); * umount can succeed * @returns - 0 on success, a negative value on error */ -long lkl_umount_timeout(char *path, int flags, long timeout_ms); +lkl_long_t lkl_umount_timeout(char *path, int flags, lkl_long_t timeout_ms); /** * lkl_opendir - open a directory diff --git a/tools/lkl/lib/fs.c b/tools/lkl/lib/fs.c index 8bd8092fd355a7..39ed7f83042575 100644 --- a/tools/lkl/lib/fs.c +++ b/tools/lkl/lib/fs.c @@ -77,7 +77,7 @@ static int get_node_with_prefix(const char *path, const char *prefix, int lkl_encode_dev_from_sysfs(const char *sysfs_path, uint32_t *pdevid) { int ret; - long fd; + lkl_long_t fd; int major, minor; char buf[16] = { 0, }; char *bufptr; @@ -200,7 +200,7 @@ int lkl_get_virtio_blkdev(int disk_id, unsigned int part, uint32_t *pdevid) return lkl_encode_dev_from_sysfs(sysfs_path, pdevid); } -long lkl_mount_blkdev(unsigned int dev, const char *fs_type, int flags, +lkl_long_t lkl_mount_blkdev(unsigned int dev, const char *fs_type, int flags, const char *data, char *mnt_str, unsigned int mnt_str_len) { char dev_str[] = { "/dev/xxxxxxxx" }; @@ -257,7 +257,7 @@ long lkl_mount_blkdev(unsigned int dev, const char *fs_type, int flags, return 0; } -long lkl_mount_dev(unsigned int disk_id, unsigned int part, +lkl_long_t lkl_mount_dev(unsigned int disk_id, unsigned int part, const char *fs_type, int flags, const char *data, char *mnt_str, unsigned int mnt_str_len) { @@ -272,14 +272,14 @@ long lkl_mount_dev(unsigned int disk_id, unsigned int part, mnt_str_len); } -long lkl_umount_timeout(char *path, int flags, long timeout_ms) +lkl_long_t lkl_umount_timeout(char *path, int flags, lkl_long_t timeout_ms) { - long incr = 10000000; /* 10 ms */ + lkl_long_t incr = 10000000; /* 10 ms */ struct __lkl__kernel_timespec ts = { .tv_sec = 0, .tv_nsec = incr, }; - long err; + lkl_long_t err; do { err = lkl_sys_umount(path, flags); @@ -292,7 +292,7 @@ long lkl_umount_timeout(char *path, int flags, long timeout_ms) return err; } -long lkl_umount_blkdev(unsigned int dev, int flags, long timeout_ms) +lkl_long_t lkl_umount_blkdev(unsigned int dev, int flags, lkl_long_t timeout_ms) { char dev_str[] = { "/dev/xxxxxxxx" }; char mnt_str[] = { "/mnt/xxxxxxxx" }; @@ -312,8 +312,8 @@ long lkl_umount_blkdev(unsigned int dev, int flags, long timeout_ms) return lkl_sys_rmdir(mnt_str); } -long lkl_umount_dev(unsigned int disk_id, unsigned int part, int flags, - long timeout_ms) +lkl_long_t lkl_umount_dev(unsigned int disk_id, unsigned int part, int flags, + lkl_long_t timeout_ms) { unsigned int dev; int err; diff --git a/tools/lkl/lib/iomem.c b/tools/lkl/lib/iomem.c index f7dfe094ac10fe..c020b1b138c359 100644 --- a/tools/lkl/lib/iomem.c +++ b/tools/lkl/lib/iomem.c @@ -53,7 +53,7 @@ void unregister_iomem(void *base) iomem_regions[index].ops = NULL; } -void *lkl_ioremap(long addr, int size) +void *lkl_ioremap(lkl_long_t addr, int size) { int index = IOMEM_ADDR_TO_INDEX(addr); int offset = IOMEM_ADDR_TO_OFFSET(addr); diff --git a/tools/lkl/lib/iomem.h b/tools/lkl/lib/iomem.h index 42b1d6a0f10d34..5282c35dbb660a 100644 --- a/tools/lkl/lib/iomem.h +++ b/tools/lkl/lib/iomem.h @@ -8,7 +8,7 @@ struct lkl_iomem_ops { void* register_iomem(void *data, int size, const struct lkl_iomem_ops *ops); void unregister_iomem(void *iomem_base); -void *lkl_ioremap(long addr, int size); +void *lkl_ioremap(lkl_long_t addr, int size); int lkl_iomem_access(const volatile void *addr, void *res, int size, int write); #endif /* _LKL_LIB_IOMEM_H */ diff --git a/tools/lkl/lib/net.c b/tools/lkl/lib/net.c index 8c4f692308c5c8..8d337fe778778e 100644 --- a/tools/lkl/lib/net.c +++ b/tools/lkl/lib/net.c @@ -44,7 +44,7 @@ int lkl_inet_pton(int af, const char *src, void *dst) static inline int ifindex_to_name(int sock, struct lkl_ifreq *ifr, int ifindex) { ifr->lkl_ifr_ifindex = ifindex; - return lkl_sys_ioctl(sock, LKL_SIOCGIFNAME, (long)ifr); + return lkl_sys_ioctl(sock, LKL_SIOCGIFNAME, (lkl_long_t)ifr); } int lkl_ifname_to_ifindex(const char *name) @@ -58,7 +58,7 @@ int lkl_ifname_to_ifindex(const char *name) strcpy(ifr.lkl_ifr_name, name); - ret = lkl_sys_ioctl(fd, LKL_SIOCGIFINDEX, (long)&ifr); + ret = lkl_sys_ioctl(fd, LKL_SIOCGIFINDEX, (lkl_long_t)&ifr); if (ret < 0) return ret; @@ -76,10 +76,10 @@ int lkl_if_up(int ifindex) if (err < 0) return err; - err = lkl_sys_ioctl(sock, LKL_SIOCGIFFLAGS, (long)&ifr); + err = lkl_sys_ioctl(sock, LKL_SIOCGIFFLAGS, (lkl_long_t)&ifr); if (!err) { ifr.lkl_ifr_flags |= LKL_IFF_UP; - err = lkl_sys_ioctl(sock, LKL_SIOCSIFFLAGS, (long)&ifr); + err = lkl_sys_ioctl(sock, LKL_SIOCSIFFLAGS, (lkl_long_t)&ifr); } lkl_sys_close(sock); @@ -100,10 +100,10 @@ int lkl_if_down(int ifindex) if (err < 0) return err; - err = lkl_sys_ioctl(sock, LKL_SIOCGIFFLAGS, (long)&ifr); + err = lkl_sys_ioctl(sock, LKL_SIOCGIFFLAGS, (lkl_long_t)&ifr); if (!err) { ifr.lkl_ifr_flags &= ~LKL_IFF_UP; - err = lkl_sys_ioctl(sock, LKL_SIOCSIFFLAGS, (long)&ifr); + err = lkl_sys_ioctl(sock, LKL_SIOCSIFFLAGS, (lkl_long_t)&ifr); } lkl_sys_close(sock); @@ -126,7 +126,7 @@ int lkl_if_set_mtu(int ifindex, int mtu) ifr.lkl_ifr_mtu = mtu; - err = lkl_sys_ioctl(sock, LKL_SIOCSIFMTU, (long)&ifr); + err = lkl_sys_ioctl(sock, LKL_SIOCSIFMTU, (lkl_long_t)&ifr); lkl_sys_close(sock); @@ -146,10 +146,10 @@ int lkl_if_set_mac(int ifindex, void *addr) if (err < 0) goto out; - err = lkl_sys_ioctl(sock, LKL_SIOCGIFHWADDR, (long)&ifr); + err = lkl_sys_ioctl(sock, LKL_SIOCGIFHWADDR, (lkl_long_t)&ifr); if (!err) { memcpy(ifr.lkl_ifr_hwaddr.sa_data, addr, LKL_ETH_ALEN); - err = lkl_sys_ioctl(sock, LKL_SIOCSIFHWADDR, (long)&ifr); + err = lkl_sys_ioctl(sock, LKL_SIOCSIFHWADDR, (lkl_long_t)&ifr); } out: @@ -193,7 +193,7 @@ int lkl_netdev_get_ifindex(int id) return sock; snprintf(ifr.lkl_ifr_name, sizeof(ifr.lkl_ifr_name), "eth%d", id); - ret = lkl_sys_ioctl(sock, LKL_SIOCGIFINDEX, (long)&ifr); + ret = lkl_sys_ioctl(sock, LKL_SIOCGIFINDEX, (lkl_long_t)&ifr); lkl_sys_close(sock); return ret < 0 ? ret : ifr.lkl_ifr_ifindex; diff --git a/tools/lkl/lib/nt-host.c b/tools/lkl/lib/nt-host.c index 1d643da4168f9d..06089b1497f469 100644 --- a/tools/lkl/lib/nt-host.c +++ b/tools/lkl/lib/nt-host.c @@ -208,7 +208,7 @@ static void CALLBACK timer_callback(void *arg, BOOLEAN TimerOrWaitFired) t->callback(); } -static int timer_set_oneshot(void *timer, unsigned long ns) +static int timer_set_oneshot(void *timer, lkl_ulong_t ns) { struct timer *t = (struct timer *)timer; HANDLE tmp; @@ -241,11 +241,12 @@ static void print(const char *str, int len) write(1, str, len); } -static void *mem_alloc(unsigned long size) +static void *mem_alloc(lkl_ulong_t size) { return malloc(size); } + struct lkl_host_operations lkl_host_ops = { .panic = panic, .thread_create = thread_create, diff --git a/tools/lkl/lib/posix-host.c b/tools/lkl/lib/posix-host.c index 2f4e0191dd78a7..4b80376a33c596 100644 --- a/tools/lkl/lib/posix-host.c +++ b/tools/lkl/lib/posix-host.c @@ -260,7 +260,7 @@ static int thread_equal(lkl_thread_t a, lkl_thread_t b) #define pthread_getattr_np pthread_attr_get_np #endif -void *thread_stack(unsigned long *size) +void *thread_stack(lkl_ulong_t *size) { pthread_attr_t thread_attr; size_t stack_size; @@ -426,7 +426,7 @@ static void *timer_alloc(void (*fn)(void)) return (void *)(long)timer; } -static int timer_set_oneshot(void *_timer, unsigned long ns) +static int timer_set_oneshot(void *_timer, lkl_ulong_t ns) { timer_t timer = (timer_t)(long)_timer; struct itimerspec ts = { @@ -451,7 +451,7 @@ static void panic(void) assert(0); } -static void *page_alloc(unsigned long size) +static void *page_alloc(lkl_ulong_t size) { void *addr; @@ -464,7 +464,7 @@ static void *page_alloc(unsigned long size) return addr; } -static void page_free(void *addr, unsigned long size) +static void page_free(void *addr, lkl_ulong_t size) { munmap((void *)addr, size); } @@ -495,7 +495,7 @@ static inline int get_prot(enum lkl_prot lkl_prot) #endif #endif -static void *lkl_mmap(void *addr, unsigned long size, enum lkl_prot prot) +static void *lkl_mmap(void *addr, lkl_ulong_t size, enum lkl_prot prot) { void *ret; int fl = MAP_ANON | MAP_PRIVATE | MAP_FIXED_NOREPLACE | MAP_NORESERVE; @@ -510,7 +510,7 @@ static void *lkl_mmap(void *addr, unsigned long size, enum lkl_prot prot) return ret; } -static int lkl_munmap(void *addr, unsigned long size) +static int lkl_munmap(void *addr, lkl_ulong_t size) { return munmap(addr, size); } @@ -521,9 +521,9 @@ extern struct lkl_dev_pci_ops vfio_pci_ops; #ifdef LKL_HOST_CONFIG_MMU static int shared_mem_fd = -1; -static unsigned long shared_mem_size; +static lkl_ulong_t shared_mem_size; -static void shmem_init(unsigned long size) +static void shmem_init(lkl_ulong_t size) { int rwx = 00700; char lkl_shmem_id[NAME_MAX]; @@ -535,8 +535,8 @@ static void shmem_init(unsigned long size) assert(ftruncate(shared_mem_fd, shared_mem_size) == 0); } -static void *lkl_shmem_mmap(void *addr, unsigned long pg_off, - unsigned long size, enum lkl_prot mem_prot_flags) +static void *lkl_shmem_mmap(void *addr, lkl_ulong_t pg_off, + lkl_ulong_t size, enum lkl_prot mem_prot_flags) { int prot = get_prot(mem_prot_flags); int flags = MAP_SHARED | MAP_FIXED_NOREPLACE; @@ -548,22 +548,22 @@ static void *lkl_shmem_mmap(void *addr, unsigned long pg_off, } #endif // LKL_HOST_CONFIG_MMU -static void *posix_malloc(unsigned long size) +static void *posix_malloc(lkl_ulong_t size) { return malloc((size_t)size); } -static void *posix_memcpy(void *dest, const void *src, unsigned long n) +static void *posix_memcpy(void *dest, const void *src, lkl_ulong_t n) { return memcpy(dest, src, (size_t)n); } -static void *posix_memset(void *s, int c, unsigned long n) +static void *posix_memset(void *s, int c, lkl_ulong_t n) { return memset(s, c, (size_t)n); } -static void *posix_memmove(void *dest, const void *src, unsigned long n) +static void *posix_memmove(void *dest, const void *src, lkl_ulong_t n) { return memmove(dest, src, (size_t)n); } diff --git a/tools/lkl/lib/vfio_pci.c b/tools/lkl/lib/vfio_pci.c index b68f904253a5eb..49deabd4091615 100644 --- a/tools/lkl/lib/vfio_pci.c +++ b/tools/lkl/lib/vfio_pci.c @@ -56,7 +56,7 @@ struct lkl_pci_dev { */ static struct lkl_pci_dev *vfio_pci_add(const char *name, void *kernel_ram, - unsigned long ram_size) + lkl_ulong_t ram_size) { struct lkl_pci_dev *dev; char path[128], link[128], *l; @@ -605,13 +605,13 @@ static void vfio_pci_remove(struct lkl_pci_dev *dev) } static unsigned long long vfio_map_page(struct lkl_pci_dev *dev, void *vaddr, - unsigned long size) + lkl_ulong_t size) { return (unsigned long long)vaddr - dev->dma_map.vaddr; } static void vfio_unmap_page(struct lkl_pci_dev *dev, - unsigned long long dma_handle, unsigned long size) + unsigned long long dma_handle, lkl_ulong_t size) { } @@ -716,7 +716,7 @@ static const struct lkl_iomem_ops pci_resource_ops = { #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) static void *vfio_resource_alloc(struct lkl_pci_dev *dev, - unsigned long resource_size, + lkl_ulong_t resource_size, int resource_index) { unsigned int region_index_list[] = { diff --git a/tools/lkl/lib/virtio.c b/tools/lkl/lib/virtio.c index a83dde5258897f..bf296aece14c35 100644 --- a/tools/lkl/lib/virtio.c +++ b/tools/lkl/lib/virtio.c @@ -405,7 +405,7 @@ static inline void set_ptr_low(void **ptr, uint32_t val) uint64_t tmp = (uintptr_t)*ptr; tmp = (tmp & 0xFFFFFFFF00000000) | val; - *ptr = (void *)(long)tmp; + *ptr = (void *)(lkl_long_t)tmp; } static inline void set_ptr_high(void **ptr, uint32_t val) @@ -413,7 +413,7 @@ static inline void set_ptr_high(void **ptr, uint32_t val) uint64_t tmp = (uintptr_t)*ptr; tmp = (tmp & 0x00000000FFFFFFFF) | ((uint64_t)val << 32); - *ptr = (void *)(long)tmp; + *ptr = (void *)(lkl_long_t)tmp; } static inline void set_status(struct virtio_dev *dev, uint32_t val) @@ -562,7 +562,7 @@ int virtio_dev_setup(struct virtio_dev *dev, int queues, int num_max) dev->virtio_mmio_id = lkl_num_virtio_boot_devs++; } else { ret = - lkl_sys_virtio_mmio_device_add((long)dev->base, mmio_size, + lkl_sys_virtio_mmio_device_add((lkl_long_t)dev->base, mmio_size, dev->irq); if (ret < 0) { lkl_printf("can't register mmio device\n"); @@ -577,8 +577,8 @@ int virtio_dev_setup(struct virtio_dev *dev, int queues, int num_max) int virtio_dev_cleanup(struct virtio_dev *dev) { char devname[100]; - long fd, ret; - long mount_ret; + lkl_long_t fd, ret; + lkl_long_t mount_ret; if (!lkl_is_running()) goto skip_unbind; diff --git a/tools/lkl/lib/virtio_net_wintap.c b/tools/lkl/lib/virtio_net_wintap.c index 5f29737094ecf2..e49764553e9043 100644 --- a/tools/lkl/lib/virtio_net_wintap.c +++ b/tools/lkl/lib/virtio_net_wintap.c @@ -6,8 +6,8 @@ * Author: Hajime Tazaki * */ -#include -#include +#include +#include #include #include #include diff --git a/tools/lkl/tests/boot.c b/tools/lkl/tests/boot.c index f7b7d4fa0a360e..7f746d0c3d9e87 100644 --- a/tools/lkl/tests/boot.c +++ b/tools/lkl/tests/boot.c @@ -32,8 +32,8 @@ int lkl_test_nanosleep(void) .tv_nsec = sleep_ns, }; struct timespec start, stop; - long delta; - long ret; + lkl_long_t delta; + lkl_long_t ret; clock_gettime(CLOCK_MONOTONIC, &start); ret = lkl_sys_nanosleep(&ts, NULL); @@ -54,12 +54,12 @@ int lkl_test_nanosleep(void) LKL_TEST_CALL(getpid, lkl_sys_getpid, 1) -void check_latency(long (*f)(void), long *min, long *max, long *avg) +void check_latency(lkl_long_t (*f)(void), lkl_long_t *min, lkl_long_t *max, lkl_long_t *avg) { int i; unsigned long long start, stop, sum = 0; static const int count = 1000; - long delta; + lkl_long_t delta; *min = 1000000000; *max = -1; @@ -78,7 +78,7 @@ void check_latency(long (*f)(void), long *min, long *max, long *avg) *avg = sum / count; } -static long native_getpid(void) +static lkl_long_t native_getpid(void) { #ifdef __MINGW32__ GetCurrentProcessId(); @@ -90,17 +90,19 @@ static long native_getpid(void) int lkl_test_syscall_latency(void) { - long min, max, avg; + lkl_long_t min, max, avg; lkl_test_logf("avg/min/max: "); check_latency(lkl_sys_getpid, &min, &max, &avg); - lkl_test_logf("lkl:%ld/%ld/%ld ", avg, min, max); + lkl_test_logf("lkl:%lld/%lld/%lld ", (long long)avg, (long long)min, + (long long)max); check_latency(native_getpid, &min, &max, &avg); - lkl_test_logf("native:%ld/%ld/%ld\n", avg, min, max); + lkl_test_logf("native:%lld/%lld/%lld\n", (long long)avg, (long long)min, + (long long)max); return TEST_SUCCESS; } @@ -122,11 +124,11 @@ LKL_TEST_CALL(lseek_set, lkl_sys_lseek, 0, 0, 0, LKL_SEEK_SET); int lkl_test_read(void) { char buf[10] = { 0, }; - long ret; + lkl_long_t ret; ret = lkl_sys_read(0, buf, sizeof(buf)); - lkl_test_logf("lkl_sys_read=%ld buf=%s\n", ret, buf); + lkl_test_logf("lkl_sys_read=%lld buf=%s\n", (long long)ret, buf); if (ret == sizeof(wrbuf) && !strcmp(wrbuf, buf)) return TEST_SUCCESS; @@ -137,12 +139,12 @@ int lkl_test_read(void) int lkl_test_fstat(void) { struct lkl_stat stat; - long ret; + lkl_long_t ret; ret = lkl_sys_fstat(0, &stat); - lkl_test_logf("lkl_sys_fstat=%ld mode=%o size=%zd\n", ret, stat.st_mode, - stat.st_size); + lkl_test_logf("lkl_sys_fstat=%lld mode=%o size=%lld\n", (long long)ret, + stat.st_mode, (long long)stat.st_size); if (ret == 0 && stat.st_size == sizeof(wrbuf) && stat.st_mode == (access_rights | LKL_S_IFREG)) @@ -156,11 +158,11 @@ LKL_TEST_CALL(mkdir, lkl_sys_mkdir, 0, "/mnt", access_rights) int lkl_test_stat(void) { struct lkl_stat stat; - long ret; + lkl_long_t ret; ret = lkl_sys_stat("/mnt", &stat); - lkl_test_logf("lkl_sys_stat(\"/mnt\")=%ld mode=%o\n", ret, + lkl_test_logf("lkl_sys_stat(\"/mnt\")=%lld mode=%o\n", (long long)ret, stat.st_mode); if (ret == 0 && stat.st_mode == (access_rights | LKL_S_IFDIR)) @@ -177,7 +179,7 @@ static int lkl_test_pipe2(void) char str[20]; int msg_len_bytes = strlen(msg) + 1; int cmp_res; - long ret; + lkl_long_t ret; ret = lkl_sys_pipe2(pipe_fds, LKL_O_NONBLOCK); if (ret) { @@ -190,7 +192,7 @@ static int lkl_test_pipe2(void) if (ret < 0) lkl_test_logf("write error: %s\n", lkl_strerror(ret)); else - lkl_test_logf("short write: %ld\n", ret); + lkl_test_logf("short write: %lld\n", (long long)ret); return TEST_FAILURE; } @@ -199,7 +201,7 @@ static int lkl_test_pipe2(void) if (ret < 0) lkl_test_logf("read error: %s\n", lkl_strerror(ret)); else - lkl_test_logf("short read: %ld\n", ret); + lkl_test_logf("short read: %lld\n", (long long)ret); return TEST_FAILURE; } @@ -230,7 +232,7 @@ static int lkl_test_epoll(void) int READ_IDX = 0, WRITE_IDX = 1; struct lkl_epoll_event wait_on, read_result; const char msg[] = "Hello world!"; - long ret; + lkl_long_t ret; memset(&wait_on, 0, sizeof(wait_on)); memset(&read_result, 0, sizeof(read_result)); @@ -264,7 +266,7 @@ static int lkl_test_epoll(void) lkl_test_logf("epoll_wait error: %s\n", lkl_strerror(ret)); else - lkl_test_logf("epoll_wait: bad event: 0x%lx\n", ret); + lkl_test_logf("epoll_wait: bad event: 0x%llx\n", (long long)ret); return TEST_FAILURE; } @@ -281,7 +283,7 @@ static int lkl_test_epoll(void) lkl_test_logf("epoll_wait error: %s\n", lkl_strerror(ret)); else - lkl_test_logf("epoll_wait: bad ev no %ld\n", ret); + lkl_test_logf("epoll_wait: bad ev no %lld\n", (long long)ret); return TEST_FAILURE; } @@ -312,7 +314,7 @@ static int lkl_test_open_cwd(void) static int lkl_test_getdents64(void) { - long ret; + lkl_long_t ret; char buf[1024], *pos; struct lkl_linux_dirent64 *de; int wr; @@ -346,7 +348,7 @@ LKL_TEST_CALL(lo_ifup, lkl_if_up, 0, 1); static int lkl_test_mutex(void) { - long ret = TEST_SUCCESS; + lkl_long_t ret = TEST_SUCCESS; /* * Can't do much to verify that this works, so we'll just let Valgrind * warn us on CI if we've made bad memory accesses. @@ -371,7 +373,7 @@ static int lkl_test_mutex(void) static int lkl_test_semaphore(void) { - long ret = TEST_SUCCESS; + lkl_long_t ret = TEST_SUCCESS; /* * Can't do much to verify that this works, so we'll just let Valgrind * warn us on CI if we've made bad memory accesses. @@ -400,7 +402,7 @@ static int lkl_test_syscall_thread(void) { int pipe_fds[2]; char tmp[LKL_PIPE_BUF+1]; - long ret; + lkl_long_t ret; lkl_thread_t tid; ret = lkl_sys_pipe2(pipe_fds, 0); @@ -426,7 +428,7 @@ static int lkl_test_syscall_thread(void) if (ret < 0) lkl_test_logf("write error: %s\n", lkl_strerror(ret)); else - lkl_test_logf("short write: %ld\n", ret); + lkl_test_logf("short write: %lld\n", (long long)ret); return TEST_FAILURE; } @@ -468,8 +470,8 @@ static int lkl_test_many_syscall_threads(void) } struct lkl_test_tgid { - long tgid; - long parent_pid; + lkl_long_t tgid; + lkl_long_t parent_pid; int new_thread_group_leader_result; }; @@ -489,7 +491,7 @@ static void thread_get_tgid(void *arg) static int lkl_test_new_tgid_threads(void) { lkl_thread_t tid; - long current_pid; + lkl_long_t current_pid; int count = 65, ret; struct lkl_test_tgid test_tgid; @@ -545,10 +547,10 @@ static int lkl_test_join(void) int ret = lkl_host_ops.thread_join(tid); if (ret == 0) { - lkl_test_logf("joined %ld\n", tid); + lkl_test_logf("joined %lld\n", (long long)tid); return TEST_SUCCESS; } else { - lkl_test_logf("failed joining %ld\n", tid); + lkl_test_logf("failed joining %lld\n", (long long)tid); return TEST_FAILURE; } } @@ -599,7 +601,7 @@ static int lkl_test_shared_mmap(void) if (fd < 0) return TEST_FAILURE; - unsigned long mem_size = 15 * 4096; + lkl_ulong_t mem_size = 15 * 4096; if (lkl_sys_ftruncate(fd, mem_size) < 0) return TEST_FAILURE; @@ -627,10 +629,10 @@ static int lkl_test_shared_mmap(void) if (memcmp(mem1, mem2, mem_size) != 0) return TEST_FAILURE; - if (lkl_sys_munmap((unsigned long)mem1, mem_size) != 0) + if (lkl_sys_munmap((lkl_ulong_t)mem1, mem_size) != 0) return TEST_FAILURE; - if (lkl_sys_munmap((unsigned long)mem2, mem_size) != 0) + if (lkl_sys_munmap((lkl_ulong_t)mem2, mem_size) != 0) return TEST_FAILURE; return TEST_SUCCESS; @@ -638,7 +640,7 @@ static int lkl_test_shared_mmap(void) static int lkl_test_private_mmap(void) { - unsigned long mem_size = 3 * 4096; + lkl_ulong_t mem_size = 3 * 4096; int mem_prot = LKL_PROT_WRITE | LKL_PROT_READ; // Super important to use LKL_MAP_POPULATE to force populating pages in the // mapping as in the LKL context we don't have a way to fault in the pages. @@ -650,7 +652,7 @@ static int lkl_test_private_mmap(void) *(unsigned int *)mem = 13; - if (lkl_sys_munmap((unsigned long)mem, mem_size) < 0) + if (lkl_sys_munmap((lkl_ulong_t)mem, mem_size) < 0) return TEST_FAILURE; return TEST_SUCCESS; diff --git a/tools/lkl/tests/disk-vfio-pci.c b/tools/lkl/tests/disk-vfio-pci.c index 8779f59bf2e5d5..b57f7091607c27 100644 --- a/tools/lkl/tests/disk-vfio-pci.c +++ b/tools/lkl/tests/disk-vfio-pci.c @@ -120,7 +120,7 @@ static int lkl_test_blkdev(void) return TEST_FAILURE; } - err = lkl_sys_ioctl(fd, LKL_BLKGETSIZE64, (unsigned long)&size); + err = lkl_sys_ioctl(fd, LKL_BLKGETSIZE64, (lkl_ulong_t)&size); if (err < 0) { lkl_test_logf("BLKGETSIZE64 failed: %s\n", lkl_strerror(fd)); lkl_sys_close(fd); diff --git a/tools/lkl/tests/disk.c b/tools/lkl/tests/disk.c index 5e1a6113bfa72f..bfa008a1a021e9 100644 --- a/tools/lkl/tests/disk.c +++ b/tools/lkl/tests/disk.c @@ -104,13 +104,13 @@ LKL_TEST_CALL(mount_dev, lkl_mount_dev, 0, disk_id, cla.partition, cla.fstype, static int lkl_test_umount_dev(void) { - long ret, ret2; + lkl_long_t ret, ret2; ret = lkl_sys_chdir("/"); ret2 = lkl_umount_dev(disk_id, cla.partition, 0, 1000); - lkl_test_logf("%ld %ld", ret, ret2); + lkl_test_logf("%lld %lld", (long long)ret, (long long)ret2); if (!ret && !ret2) return TEST_SUCCESS; diff --git a/tools/lkl/tests/test-dlmopen.c b/tools/lkl/tests/test-dlmopen.c index 292eec7094a832..2257dfd2420bb0 100644 --- a/tools/lkl/tests/test-dlmopen.c +++ b/tools/lkl/tests/test-dlmopen.c @@ -24,13 +24,13 @@ static int lkl_test_dlmopen(void) { void *handle; - long ret; + lkl_long_t ret; char *filename = "liblkl.so"; - long params[6] = {0}; + lkl_long_t params[6] = {0}; int (*fn_init)(struct lkl_host_operations *ops); int (*fn_start)(char *fmt, ...); - long (*fn_syscall)(long no, long *params); - long (*fn_sys_halt)(void); + lkl_long_t (*fn_syscall)(lkl_long_t no, lkl_long_t *params); + lkl_long_t (*fn_sys_halt)(void); void (*fn_tls_mode)(void); struct lkl_host_operations *lkl_host_ops; From 7b5395f6ca66f640ac882064f43fec68597c7eac Mon Sep 17 00:00:00 2001 From: Sheldon Qi <3365420+xdqi@users.noreply.github.com> Date: Sun, 4 Oct 2026 21:31:34 +0800 Subject: [PATCH 2/6] lkl: nt-host: implement memcpy/memset/memmove host ops CONFIG_LKL_HOST_MEMCPY/MEMSET/MEMMOVE are enabled in the kernel config, so the kernel expects these lkl_host_ops to be set. Without them the kernel does not start on Win64. Wrap the libc routines so that the lkl_ulong_t signature matches. Signed-off-by: Sheldon Qi <3365420+xdqi@users.noreply.github.com> --- tools/lkl/lib/nt-host.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tools/lkl/lib/nt-host.c b/tools/lkl/lib/nt-host.c index 06089b1497f469..e75de674e3911e 100644 --- a/tools/lkl/lib/nt-host.c +++ b/tools/lkl/lib/nt-host.c @@ -246,9 +246,26 @@ static void *mem_alloc(lkl_ulong_t size) return malloc(size); } +static void *nt_memcpy(void *dest, const void *src, lkl_ulong_t n) +{ + return memcpy(dest, src, (size_t)n); +} + +static void *nt_memset(void *s, int c, lkl_ulong_t n) +{ + return memset(s, c, (size_t)n); +} + +static void *nt_memmove(void *dest, const void *src, lkl_ulong_t n) +{ + return memmove(dest, src, (size_t)n); +} struct lkl_host_operations lkl_host_ops = { .panic = panic, + .memcpy = nt_memcpy, + .memset = nt_memset, + .memmove = nt_memmove, .thread_create = thread_create, .thread_detach = thread_detach, .thread_exit = thread_exit, From c2b0deb779f963eee66ffa25a4fa1a57510ae900 Mon Sep 17 00:00:00 2001 From: Sheldon Qi <3365420+xdqi@users.noreply.github.com> Date: Sun, 4 Oct 2026 21:31:34 +0800 Subject: [PATCH 3/6] lkl: use non-SEH setjmp/longjmp on Win64 On Win64 longjmp() unwinds the stack with RtlUnwindEx(), which fails when LKL jumps between the stacks of different threads. Define __USE_MINGW_SETJMP_NON_SEH so that setjmp() does not record a frame; longjmp() then only restores the registers. The Win64 jmp_buf also holds xmm registers and must be 16 bytes aligned, so align it inside struct lkl_jmp_buf. Signed-off-by: Sheldon Qi <3365420+xdqi@users.noreply.github.com> --- tools/lkl/lib/jmp_buf.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/tools/lkl/lib/jmp_buf.c b/tools/lkl/lib/jmp_buf.c index 4cce84b751302d..79dc3829bba9aa 100644 --- a/tools/lkl/lib/jmp_buf.c +++ b/tools/lkl/lib/jmp_buf.c @@ -1,13 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifdef _WIN64 +/* + * The Win64 longjmp() unwinds the stack with RtlUnwindEx(), which fails when + * LKL jumps between the stacks of different threads. Without a frame, i.e. + * _setjmp(buf, NULL), longjmp() only restores the registers. + */ +#define __USE_MINGW_SETJMP_NON_SEH +#endif #include +#include #include +static jmp_buf *get_jmp_buf(struct lkl_jmp_buf *jmpb) +{ +#ifdef _WIN64 + /* the Win64 jmp_buf holds xmm registers and must be 16 bytes aligned */ + _Static_assert(sizeof(jmp_buf) + 15 <= sizeof(jmpb->buf), + "lkl_jmp_buf is too small"); + return (jmp_buf *)(((uintptr_t)jmpb->buf + 15) & ~(uintptr_t)15); +#else + return (jmp_buf *)jmpb->buf; +#endif +} + void jmp_buf_set(struct lkl_jmp_buf *jmpb, void (*f)(void)) { - if (!setjmp(*((jmp_buf *)jmpb->buf))) + if (!setjmp(*get_jmp_buf(jmpb))) f(); } void jmp_buf_longjmp(struct lkl_jmp_buf *jmpb, int val) { - longjmp(*((jmp_buf *)jmpb->buf), val); + longjmp(*get_jmp_buf(jmpb), val); } From eb5ef6bd530b3effdb51abc2cc295821358cad60 Mon Sep 17 00:00:00 2001 From: Sheldon Qi <3365420+xdqi@users.noreply.github.com> Date: Sun, 4 Oct 2026 21:31:54 +0800 Subject: [PATCH 4/6] lkl: add Win64 (x86_64-w64-mingw32) build support The kernel has to be built for LP64, but MinGW-w64 compilers are LLP64. Add a compiler shim, tools/lkl/scripts/win64-cc.sh, linked as x86_64-w64-mingw32-gcc from tools/lkl/bin, which is in PATH for the kernel build. It compiles the kernel with x86_64-pc-cygwin-gcc, which produces PE/COFF objects using the same MS x64 calling convention as MinGW, but with a 64 bit long. User space code is still compiled with the real MinGW-w64 gcc and talks to the kernel through lkl_long_t. The kernel link needs binutils with the NT weak externals fixes, see tools/lkl/scripts/binutils-build.sh. Build with: make -C tools/lkl CROSS_COMPILE=x86_64-w64-mingw32- Also skip in disk-vfio-pci.c, MinGW does not have it. Signed-off-by: Sheldon Qi <3365420+xdqi@users.noreply.github.com> --- tools/lkl/bin/x86_64-w64-mingw32-cc | 1 + tools/lkl/bin/x86_64-w64-mingw32-gcc | 1 + tools/lkl/scripts/win64-cc.sh | 36 ++++++++++++++++++++++++++++ tools/lkl/tests/disk-vfio-pci.c | 2 ++ 4 files changed, 40 insertions(+) create mode 120000 tools/lkl/bin/x86_64-w64-mingw32-cc create mode 120000 tools/lkl/bin/x86_64-w64-mingw32-gcc create mode 100755 tools/lkl/scripts/win64-cc.sh diff --git a/tools/lkl/bin/x86_64-w64-mingw32-cc b/tools/lkl/bin/x86_64-w64-mingw32-cc new file mode 120000 index 00000000000000..9113d989a69fe1 --- /dev/null +++ b/tools/lkl/bin/x86_64-w64-mingw32-cc @@ -0,0 +1 @@ +../scripts/win64-cc.sh \ No newline at end of file diff --git a/tools/lkl/bin/x86_64-w64-mingw32-gcc b/tools/lkl/bin/x86_64-w64-mingw32-gcc new file mode 120000 index 00000000000000..9113d989a69fe1 --- /dev/null +++ b/tools/lkl/bin/x86_64-w64-mingw32-gcc @@ -0,0 +1 @@ +../scripts/win64-cc.sh \ No newline at end of file diff --git a/tools/lkl/scripts/win64-cc.sh b/tools/lkl/scripts/win64-cc.sh new file mode 100755 index 00000000000000..9d408822161b7d --- /dev/null +++ b/tools/lkl/scripts/win64-cc.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Win64 compiler shim, used as x86_64-w64-mingw32-gcc through the links in +# tools/lkl/bin, which is in PATH for the kernel build. The kernel must be +# built for LP64 (long is 64 bit) while Win64 is LLP64 (long is 32 bit), so: +# +# - kernel code and any link is routed to x86_64-pc-cygwin-gcc: same MS x64 +# calling convention and PE/COFF output as MinGW, but LP64; MinGW ld also +# overflows IMAGE_REL_AMD64_REL32 relocations on the large kernel object +# - user space code is compiled with the real x86_64-w64-mingw32-gcc +# +# The LKL API uses lkl_long_t (always 64 bit) to bridge the difference. + +LKL_BIN_DIR="$(cd "$(dirname "$0")" && pwd)" + +for arg in "$@"; do + if [[ "$arg" == "-D__KERNEL__" || "$arg" == *lkl.o ]]; then + exec x86_64-pc-cygwin-gcc "$@" + fi +done + +case " $* " in +*" -c "*|*" -S "*|*" -E "*) ;; +*) exec x86_64-pc-cygwin-gcc "$@" ;; +esac + +# Find the real MinGW gcc, skipping this shim +for gcc in $(which -a x86_64-w64-mingw32-gcc); do + if [[ "$(cd "$(dirname "$gcc")" && pwd)" != "$LKL_BIN_DIR" ]]; then + exec "$gcc" "$@" + fi +done + +echo "$0: x86_64-w64-mingw32-gcc not found" >&2 +exit 1 diff --git a/tools/lkl/tests/disk-vfio-pci.c b/tools/lkl/tests/disk-vfio-pci.c index b57f7091607c27..bf5b9b7a3d6be5 100644 --- a/tools/lkl/tests/disk-vfio-pci.c +++ b/tools/lkl/tests/disk-vfio-pci.c @@ -6,7 +6,9 @@ #include #include #include +#ifndef __MINGW32__ #include +#endif #include #include From 505348c01b88d5fbbe259e5664bdac2fcfb9d3b2 Mon Sep 17 00:00:00 2001 From: Sheldon Qi <3365420+xdqi@users.noreply.github.com> Date: Sun, 4 Oct 2026 21:31:54 +0800 Subject: [PATCH 5/6] lkl/scripts: add a script to build binutils for Windows hosts Linking LKL for Windows needs binutils with fixes for PE/COFF NT weak externals that are not upstream: - relocate the weak external aux entries in ld -r output (Octavian Purdila) - convert NT weak externals to local symbols in objcopy -G (Octavian Purdila) - resolve the weak externals by name instead of the stale tag index left by ld -r, which made objcopy -G resolve some of them to the wrong symbol (Sheldon Qi) binutils 2.47 implements linking NT weak externals natively, so the older "Fix linker error when using NT weak externals" patch is no longer needed. Instead of committing more prebuilt binaries, add binutils-build.sh, which downloads binutils 2.47, applies the patches from binutils-patches/ and installs the tools in $BINUTILS_PREFIX. Signed-off-by: Sheldon Qi <3365420+xdqi@users.noreply.github.com> --- tools/lkl/scripts/binutils-build.sh | 46 ++++++ tools/lkl/scripts/binutils-patches/.gitignore | 1 + ...te-aux-entries-for-NT-weak-externals.patch | 123 +++++++++++++++ ...-Convert-NT-weak-externals-to-locals.patch | 139 ++++++++++++++++ ...ernals-by-name-rather-than-stale-tag.patch | 148 ++++++++++++++++++ 5 files changed, 457 insertions(+) create mode 100755 tools/lkl/scripts/binutils-build.sh create mode 100644 tools/lkl/scripts/binutils-patches/.gitignore create mode 100644 tools/lkl/scripts/binutils-patches/0001-Relocate-aux-entries-for-NT-weak-externals.patch create mode 100644 tools/lkl/scripts/binutils-patches/0002-Convert-NT-weak-externals-to-locals.patch create mode 100644 tools/lkl/scripts/binutils-patches/0003-Resolve-weak-externals-by-name-rather-than-stale-tag.patch diff --git a/tools/lkl/scripts/binutils-build.sh b/tools/lkl/scripts/binutils-build.sh new file mode 100755 index 00000000000000..dc8267e339a04b --- /dev/null +++ b/tools/lkl/scripts/binutils-build.sh @@ -0,0 +1,46 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Build GNU binutils with the PE/COFF NT weak externals fixes needed to +# link LKL for Windows hosts. The patches live in binutils-patches/. +# +# usage: binutils-build.sh [target...] +# +# The default target is x86_64-w64-mingw32. The tools are installed in +# $BINUTILS_PREFIX (default: $HOME/lkl-binutils); put $BINUTILS_PREFIX/bin +# in PATH before building LKL. + +set -e + +version=2.47 +sha256=154ab23b60070e8f27013c22977f1129425d67d1e8acd6e13010e617811e4cff +mirror=${GNU_MIRROR:-https://ftpmirror.gnu.org/gnu} + +patches=$(cd "$(dirname "$0")/binutils-patches" && pwd) +prefix=${BINUTILS_PREFIX:-$HOME/lkl-binutils} +targets=${*:-x86_64-w64-mingw32} +jobs=$(nproc 2>/dev/null || echo 4) + +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' EXIT +cd "$tmp" + +curl -fsSL --retry 3 -o binutils-$version.tar.xz \ + $mirror/binutils/binutils-$version.tar.xz +echo "$sha256 binutils-$version.tar.xz" | sha256sum -c - +tar -xf binutils-$version.tar.xz + +for p in "$patches"/*.patch; do + patch -d binutils-$version -p1 < "$p" +done + +for target in $targets; do + mkdir build-$target + cd build-$target + ../binutils-$version/configure --target=$target --prefix="$prefix" \ + --disable-nls --disable-werror --disable-gdb --disable-gdbserver \ + --disable-sim --disable-gprof --disable-gprofng + make -j$jobs all-gas all-ld all-binutils + make install-gas install-ld install-binutils + cd .. +done diff --git a/tools/lkl/scripts/binutils-patches/.gitignore b/tools/lkl/scripts/binutils-patches/.gitignore new file mode 100644 index 00000000000000..69f1bf45309577 --- /dev/null +++ b/tools/lkl/scripts/binutils-patches/.gitignore @@ -0,0 +1 @@ +!*.patch diff --git a/tools/lkl/scripts/binutils-patches/0001-Relocate-aux-entries-for-NT-weak-externals.patch b/tools/lkl/scripts/binutils-patches/0001-Relocate-aux-entries-for-NT-weak-externals.patch new file mode 100644 index 00000000000000..0a906749c7f0fc --- /dev/null +++ b/tools/lkl/scripts/binutils-patches/0001-Relocate-aux-entries-for-NT-weak-externals.patch @@ -0,0 +1,123 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Octavian Purdila +Date: Mon, 26 Oct 2015 15:57:34 +0200 +Subject: [PATCH 1/3] Relocate aux entries for NT weak externals + +Currently the tagndx for NT weak externals are not relocated when +creating a relocatable object which breaks relocations when doing the +final link of the relocatable object. + +For the following example: + + a.c: + void foo(void); + + int main() + { + foo(); + return 0; + } + + b.c: + #include + + void __attribute__((weak)) foo(void) + { + printf("%s weak\n", __func__); + } + +$ i686-w64-mingw32-ld -r -o r.o a.o b.o + +This is how the symbol table looks for b.o: + +$ i686-w64-mingw32-objdump -x b.o | grep -A 1 foo +[ 23](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 .weak._foo. +[ 24](sec 0)(fl 0x00)(ty 20)(scl 105) (nx 1) 0x00000000 _foo + +And this is how the symbol table looks for r.o: + +$ i686-w64-mingw32-objdump -x r.o | grep -A 1 foo +[ 45](sec 0)(fl 0x00)(ty 20)(scl 105) (nx 1) 0x00000000 _foo +AUX lnno 1 size 0x0 tagndx 23 +... +[ 48](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x00000000 .weak._foo. + +As you can see the AUX entry for _foo is wrong in r.o, it should be 48 +but it is 23. + +The patch uses the sym_indices array to relocate the AUX entries for +weak externals in _bfd_coff_link_input_bfd. + +In order to do so we need the .weak. counterpart symbol to be loaded +before the weak external symbol. This is prevented by the ISFCN() +check _bfd_coff_link_input_bfd and is caused by the fact that the AUX +entry type is 0. To fix this issue we patch gas to propagate the type +of external weak symbols to its .weak. counterpart symbol. + +Note that we perform the AUX tag relocations only int the case of +relocatable output because weak external relocation handling +(_bfd_coff_generic_relocate_section) uses the tagndx relative to the +input object. + +bfd/ + +2015-10-26 Octavian Purdila + + * cofflink.c (_bfd_coff_link_input_bfd): relocate AUX entries for + weak externals when generating relocatable objects + +gas/ + +2015-10-26 Octavian Purdila + + * obj-coff.c (coff_frob_symbol): propagate the type of external + weak symbol to its .weak. counterpart +--- + bfd/cofflink.c | 14 +++++++++++--- + gas/config/obj-coff.c | 1 + + 2 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/bfd/cofflink.c b/bfd/cofflink.c +index d029bec..bc7820f 100644 +--- a/bfd/cofflink.c ++++ b/bfd/cofflink.c +@@ -2124,7 +2124,8 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *flaginfo, bfd *input_bfd) + if ((*indexp < 0 + || (bfd_size_type) *indexp < syment_base) + && (*sym_hash == NULL +- || (*sym_hash)->auxbfd != input_bfd)) ++ || (*sym_hash)->auxbfd != input_bfd) ++ && isymp->n_sclass != C_NT_WEAK) + esym += add * isymesz; + else + { +@@ -2194,8 +2195,15 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *flaginfo, bfd *input_bfd) + auxp->x_file.x_n.x_n.x_offset = STRING_SIZE_SIZE + indx; + } + } +- else if ((isymp->n_sclass != C_STAT || isymp->n_type != T_NULL) +- && isymp->n_sclass != C_NT_WEAK) ++ else if (isymp->n_sclass == C_NT_WEAK) ++ { ++ unsigned int *tagndx = &auxp->x_sym.x_tagndx.u32; ++ ++ if (bfd_link_relocatable (flaginfo->info) && ++ flaginfo->sym_indices[*tagndx] > 0) ++ *tagndx = flaginfo->sym_indices[*tagndx]; ++ } ++ else if (isymp->n_sclass != C_STAT || isymp->n_type != T_NULL) + { + unsigned long indx; + +diff --git a/gas/config/obj-coff.c b/gas/config/obj-coff.c +index 7732c0a..5df3940 100644 +--- a/gas/config/obj-coff.c ++++ b/gas/config/obj-coff.c +@@ -1259,6 +1259,7 @@ coff_frob_symbol (symbolS *symp, int *punt) + symbol_get_value_expression (weakp)); + symbol_set_frag (symp, symbol_get_frag (weakp)); + S_SET_SEGMENT (symp, S_GET_SEGMENT (weakp)); ++ S_SET_DATA_TYPE (symp, S_GET_DATA_TYPE (weakp)); + } + else + { diff --git a/tools/lkl/scripts/binutils-patches/0002-Convert-NT-weak-externals-to-locals.patch b/tools/lkl/scripts/binutils-patches/0002-Convert-NT-weak-externals-to-locals.patch new file mode 100644 index 00000000000000..a279be446b9c33 --- /dev/null +++ b/tools/lkl/scripts/binutils-patches/0002-Convert-NT-weak-externals-to-locals.patch @@ -0,0 +1,139 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Octavian Purdila +Date: Mon, 26 Oct 2015 15:57:35 +0200 +Subject: [PATCH 2/3] Convert NT weak externals to locals + +This patch allows converting a weak external symbol to a local symbol +by setting up its section and value to the ones of the alternate +symbol. This is useful when we want to make only a few selected +symbols visible (e.g. objcopy -G). + +The conversion is triggered when an NT weak external symbol has been +marked with BSF_LOCAL. + +bfd/ + +2015-10-22 Octavian Purdila + + * coffgen.c: add coff_nt_weak_to_local() that implements weak + external to local symbol conversion + * coffcode.h (coff_write_object_contents): call + coff_nt_weak_to_local() + * libcoff.h: add coff_nt_weak_to_local() declaration + +binutils/ + +2015-10-26 Octavian Purdila + + * objcopy.c (filter_symbols): allow converting undefined weak + symbols to local symbols for PE objects (as PE weak externals are + implemented as undefined weak symbols) +--- + bfd/coffcode.h | 1 + + bfd/coffgen.c | 43 +++++++++++++++++++++++++++++++++++++++++++ + bfd/libcoff.h | 2 ++ + binutils/objcopy.c | 12 +++++++++++- + 4 files changed, 57 insertions(+), 1 deletion(-) + +diff --git a/bfd/coffcode.h b/bfd/coffcode.h +index 12cc7c3..719e5fc 100644 +--- a/bfd/coffcode.h ++++ b/bfd/coffcode.h +@@ -4157,6 +4157,7 @@ coff_write_object_contents (bfd * abfd) + { + int firstundef; + ++ coff_nt_weak_to_local(abfd); + if (!coff_renumber_symbols (abfd, &firstundef)) + return false; + coff_mangle_symbols (abfd); +diff --git a/bfd/coffgen.c b/bfd/coffgen.c +index f306064..23b4ec8 100644 +--- a/bfd/coffgen.c ++++ b/bfd/coffgen.c +@@ -890,6 +890,49 @@ coff_renumber_symbols (bfd *bfd_ptr, int *first_undef) + return true; + } + ++/* Transform weak externals to local symbols if requested (e.g. objcopy). */ ++void coff_nt_weak_to_local(bfd *abfd) ++{ ++ unsigned int symbol_count = bfd_get_symcount (abfd); ++ asymbol **symbol_ptr_ptr = abfd->outsymbols; ++ unsigned int symbol_index; ++ ++ for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) ++ { ++ asymbol *symbol = symbol_ptr_ptr[symbol_index]; ++ coff_symbol_type *coff_symbol_ptr; ++ combined_entry_type *native; ++ struct internal_syment *sym; ++ ++ coff_symbol_ptr = coff_symbol_from (symbol); ++ if (!coff_symbol_ptr) ++ continue; ++ ++ native = coff_symbol_ptr->native; ++ if (!native) ++ continue; ++ ++ sym = &native->u.syment; ++ ++ if ((symbol->flags & BSF_LOCAL) && sym->n_sclass == C_NT_WEAK ++ && sym->n_numaux == 1) { ++ union internal_auxent *aux = &native[1].u.auxent; ++ struct internal_syment *wsym = &aux->x_sym.x_tagndx.p->u.syment; ++ ++ if (!wsym) { ++ symbol->flags &= BSF_LOCAL; ++ continue; ++ } ++ ++ symbol->flags &= ~BSF_WEAK; ++ symbol->value = wsym->n_value; ++ symbol->section = coff_section_from_bfd_index (abfd, wsym->n_scnum); ++ symbol->section->output_section = symbol->section; ++ sym->n_numaux = 0; ++ } ++ } ++} ++ + /* Run thorough the symbol table again, and fix it so that all + pointers to entries are changed to the entries' index in the output + symbol table. */ +diff --git a/bfd/libcoff.h b/bfd/libcoff.h +index 8d918ba..a852fd7 100644 +--- a/bfd/libcoff.h ++++ b/bfd/libcoff.h +@@ -368,6 +368,8 @@ extern int coff_count_linenumbers + (bfd *) ATTRIBUTE_HIDDEN; + extern bool coff_renumber_symbols + (bfd *, int *) ATTRIBUTE_HIDDEN; ++extern void coff_nt_weak_to_local ++ (bfd *) ATTRIBUTE_HIDDEN; + extern void coff_mangle_symbols + (bfd *) ATTRIBUTE_HIDDEN; + extern bool coff_write_symbols +diff --git a/binutils/objcopy.c b/binutils/objcopy.c +index 4ab7e89..afb55b8 100644 +--- a/binutils/objcopy.c ++++ b/binutils/objcopy.c +@@ -1765,7 +1765,17 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms, + + if (keep) + { +- if (!undefined ++ if ((flags & BSF_GLOBAL) != 0 ++ && (weaken || is_specified_symbol (name, weaken_specific_htab))) ++ { ++ sym->flags &= ~ BSF_GLOBAL; ++ sym->flags |= BSF_WEAK; ++ } ++ ++ /* We want to check even undefined weak symbols in the case of PE, ++ * since weak externals are classified as undefined. */ ++ if ((!undefined || (bfd_get_flavour (abfd) == bfd_target_coff_flavour && ++ startswith ((abfd)->xvec->name, "pe"))) + && (flags & (BSF_GLOBAL | BSF_WEAK)) + && (is_specified_symbol (name, localize_specific_htab) + || (htab_elements (keepglobal_specific_htab) != 0 diff --git a/tools/lkl/scripts/binutils-patches/0003-Resolve-weak-externals-by-name-rather-than-stale-tag.patch b/tools/lkl/scripts/binutils-patches/0003-Resolve-weak-externals-by-name-rather-than-stale-tag.patch new file mode 100644 index 00000000000000..fc1411b3e7437d --- /dev/null +++ b/tools/lkl/scripts/binutils-patches/0003-Resolve-weak-externals-by-name-rather-than-stale-tag.patch @@ -0,0 +1,148 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sheldon Qi <3365420+xdqi@users.noreply.github.com> +Date: Thu, 30 Apr 2026 22:18:21 +0800 +Subject: [PATCH 3/3] Resolve weak externals by name rather than stale tagndx + +When ld -r creates a relocatable object (e.g. vmlinux), the tagndx +field in weak external aux entries is not relocated and points to the +wrong symbol. All 352 C_NT_WEAK symbols in vmlinux have incorrect +tagndx values -- some point to non-code sections (e.g. .data section +symbols) while others point to completely unrelated code symbols +(e.g. bpf_arena_get_user_vm_start tagndx -> cmd_line_append). + +The previous implementation only fell back to name-based lookup when +tagndx pointed to a non-code section, which missed the case where +tagndx points to a wrong but valid code symbol. This caused objcopy +-G to resolve weak externals to incorrect addresses, leading to +runtime crashes (e.g. ktime_get dereferencing NULL through +tk_core->clock, or lkl_start_kernel calling the wrong functions). + +Fix coff_nt_weak_to_local() to always search for the .weak.. +implementation by name first, since PE COFF weak external naming is +deterministic. Only fall back to the tagndx pointer when no name match +is found. + +Co-Authored-By: Claude Opus 4.7 +--- + bfd/coffgen.c | 93 ++++++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 77 insertions(+), 16 deletions(-) + +diff --git a/bfd/coffgen.c b/bfd/coffgen.c +index 23b4ec8..0cefa34 100644 +--- a/bfd/coffgen.c ++++ b/bfd/coffgen.c +@@ -890,7 +890,12 @@ coff_renumber_symbols (bfd *bfd_ptr, int *first_undef) + return true; + } + +-/* Transform weak externals to local symbols if requested (e.g. objcopy). */ ++/* Transform weak externals to local symbols if requested (e.g. objcopy). ++ When ld -r creates a relocatable object, the tagndx field in the weak ++ external's aux entry may point to the wrong symbol due to unrelocated ++ symbol indices. We always search for the .weak. counterpart by name, ++ which is reliable, and only fall back to the tagndx pointer when no ++ .weak. match is found. */ + void coff_nt_weak_to_local(bfd *abfd) + { + unsigned int symbol_count = bfd_get_symcount (abfd); +@@ -906,29 +911,85 @@ void coff_nt_weak_to_local(bfd *abfd) + + coff_symbol_ptr = coff_symbol_from (symbol); + if (!coff_symbol_ptr) +- continue; ++ continue; + + native = coff_symbol_ptr->native; + if (!native) +- continue; ++ continue; + + sym = &native->u.syment; + + if ((symbol->flags & BSF_LOCAL) && sym->n_sclass == C_NT_WEAK + && sym->n_numaux == 1) { +- union internal_auxent *aux = &native[1].u.auxent; +- struct internal_syment *wsym = &aux->x_sym.x_tagndx.p->u.syment; +- +- if (!wsym) { +- symbol->flags &= BSF_LOCAL; +- continue; +- } +- +- symbol->flags &= ~BSF_WEAK; +- symbol->value = wsym->n_value; +- symbol->section = coff_section_from_bfd_index (abfd, wsym->n_scnum); +- symbol->section->output_section = symbol->section; +- sym->n_numaux = 0; ++ union internal_auxent *aux = &native[1].u.auxent; ++ const char *weakname = bfd_asymbol_name (symbol); ++ char leading = bfd_get_symbol_leading_char (abfd); ++ const char *stripped = weakname; ++ unsigned int j; ++ int found = 0; ++ ++ if (leading && stripped[0] == leading) ++ stripped++; ++ size_t nlen = strlen (stripped); ++ ++ /* Always search for the .weak. implementation by name. ++ The tagndx field is unreliable after ld -r. */ ++ for (j = 0; j < symbol_count; j++) ++ { ++ asymbol *wsym_ptr = symbol_ptr_ptr[j]; ++ const char *wname = bfd_asymbol_name (wsym_ptr); ++ const char *wstripped = wname; ++ size_t wslen; ++ if (leading && wstripped[0] == leading) ++ wstripped++; ++ wslen = strlen (wstripped); ++ /* .weak. symbols: ".weak.." */ ++ if (wslen > 6 + nlen + 1 ++ && strncmp (wstripped, ".weak.", 6) == 0 ++ && wstripped[6 + nlen] == '.' ++ && strncmp (wstripped + 6, stripped, nlen) == 0) ++ { ++ asection *s = wsym_ptr->section; ++ if (s && (s->flags & SEC_CODE)) ++ { ++ symbol->value = bfd_asymbol_value (wsym_ptr); ++ symbol->section = s; ++ symbol->section->output_section = s; ++ symbol->flags &= ~BSF_WEAK; ++ sym->n_numaux = 0; ++ found = 1; ++ break; ++ } ++ } ++ } ++ ++ if (!found) ++ { ++ /* No .weak. code counterpart found by name; check if the ++ tagndx pointer points somewhere usable. */ ++ struct internal_syment *wsym; ++ asection *wsec; ++ ++ wsym = &aux->x_sym.x_tagndx.p->u.syment; ++ wsec = coff_section_from_bfd_index (abfd, wsym->n_scnum); ++ ++ if (wsec && wsec != bfd_abs_section_ptr ++ && !bfd_is_und_section (wsec) ++ && !bfd_is_com_section (wsec) ++ && (wsec->flags & SEC_CODE)) ++ { ++ symbol->flags &= ~BSF_WEAK; ++ symbol->value = wsym->n_value; ++ symbol->section = wsec; ++ symbol->section->output_section = wsec; ++ sym->n_numaux = 0; ++ } ++ else ++ { ++ /* No usable target; just mark local */ ++ symbol->flags &= BSF_LOCAL; ++ } ++ } + } + } + } From 2046bd2d81bbdbb9bc8c9531f7d784780c46d4e6 Mon Sep 17 00:00:00 2001 From: Sheldon Qi <3365420+xdqi@users.noreply.github.com> Date: Sun, 4 Oct 2026 21:31:54 +0800 Subject: [PATCH 6/6] lkl/ci: build and test Win64 under wine Add a win64 job that cross compiles LKL on Linux and runs the tests with wine. win64-toolchain.sh installs x86_64-pc-cygwin-gcc and the MinGW-w64 gcc from the msys2-cross release packages (https://github.com/xdqi/msys-cross) and builds binutils with binutils-build.sh. Under wine the tap and wintap backends are not usable, so skip the tap test on Windows hosts and the wintap test when netsh is missing. Signed-off-by: Sheldon Qi <3365420+xdqi@users.noreply.github.com> --- .github/workflows/ci.yml | 16 ++++++++ tools/lkl/scripts/win64-toolchain.sh | 56 ++++++++++++++++++++++++++++ tools/lkl/tests/net.sh | 7 ++++ 3 files changed, 79 insertions(+) create mode 100755 tools/lkl/scripts/win64-toolchain.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 037c7efab5c996..3f67d536f16475 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,6 +41,13 @@ jobs: build_options: "LLVM=1 CROSS_COMPILE=x86_64-unknown-freebsd SYSROOT=~/freebsd-sysroot" make_sysroot: "./tools/lkl/scripts/freebsd-make-sysroot.sh" run_qemu: true + - displayTargetName: win64 + os: unix + runs_on: ubuntu-24.04 + pip_option: --break-system-packages + shell: bash + build_options: "CROSS_COMPILE=x86_64-w64-mingw32-" + make_sysroot: "./tools/lkl/scripts/win64-toolchain.sh" - displayTargetName: fuzzers os: unix runs_on: ubuntu-22.04 @@ -123,6 +130,15 @@ jobs: qemu-utils sshpass cloud-image-utils binutils cmake ninja-build liblzma-dev libz-dev \ pkg-config autoconf libtool + - name: Install wine + if: matrix.displayTargetName == 'win64' + run: | + sudo apt install -y wine wine64 + echo "WINEDEBUG=-all" >> $GITHUB_ENV + # skip the Mono and Gecko installers, they hang without a display + echo "WINEDLLOVERRIDES=mscoree=;mshtml=" >> $GITHUB_ENV + WINEDEBUG=-all WINEDLLOVERRIDES="mscoree=;mshtml=" wineboot -i + - name: Install patched binutils for Windows if: runner.os == 'Windows' run: | diff --git a/tools/lkl/scripts/win64-toolchain.sh b/tools/lkl/scripts/win64-toolchain.sh new file mode 100755 index 00000000000000..e93f9122ca69ac --- /dev/null +++ b/tools/lkl/scripts/win64-toolchain.sh @@ -0,0 +1,56 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Install a Linux hosted toolchain for Win64 (x86_64-w64-mingw32) builds: +# +# - x86_64-pc-cygwin-gcc (kernel, LP64) and x86_64-w64-mingw32-gcc (user +# space, LLP64) from msys2-cross (https://github.com/xdqi/msys-cross) +# - binutils with the NT weak externals fixes, see binutils-build.sh +# +# Then build with patched binutils first in PATH: +# +# PATH=$BINUTILS_PREFIX/bin:$MSYS_CROSS_PREFIX/bin:$PATH \ +# make -C tools/lkl CROSS_COMPILE=x86_64-w64-mingw32- +# +# When running in GitHub Actions the directories are added to $GITHUB_PATH. + +set -e + +release=${MSYS_CROSS_RELEASE:-build-20261001.1} +url=https://github.com/xdqi/msys-cross/releases/download/$release +prefix=${MSYS_CROSS_PREFIX:-/opt/msys2-cross} +binutils_prefix=${BINUTILS_PREFIX:-$HOME/lkl-binutils} +script_dir=$(cd "$(dirname "$0")" && pwd) + +if ! mkdir -p "$prefix" 2>/dev/null; then + sudo mkdir -p "$prefix" + sudo chown "$(id -u):$(id -g)" "$prefix" +fi + +if [ ! -x "$prefix/bin/msys-pacman" ]; then + curl -fsSL --retry 3 $url/bootstrap.tar.xz | + tar -xJ -C "$prefix" --strip-components=1 +fi + +# Serve the package database locally and download the packages from the +# release assets: pacman tries the servers in order for each file. +repo=$prefix/var/lib/msys-cross-repo +mkdir -p "$repo" +curl -fsSL --retry 3 -o "$repo/msys-cross.db" $url/msys-cross.db.tar.gz +sed -i -e '/^\[msys-cross\]/,/^\[/ { /^Server = /d }' \ + -e "/^\[msys-cross\]/a Server = file://$repo\nServer = $url" \ + "$prefix/etc/pacman.d/pacman.conf" + +"$prefix/bin/msys-pacman" -Sy --noconfirm --needed \ + msys-cross-cygwin-gcc msys-cross-mingw64-gcc + +if [ ! -x "$binutils_prefix/bin/x86_64-w64-mingw32-ld" ]; then + BINUTILS_PREFIX=$binutils_prefix "$script_dir/binutils-build.sh" \ + x86_64-w64-mingw32 +fi + +# Entries added later take precedence +if [ -n "$GITHUB_PATH" ]; then + echo "$prefix/bin" >> "$GITHUB_PATH" + echo "$binutils_prefix/bin" >> "$GITHUB_PATH" +fi diff --git a/tools/lkl/tests/net.sh b/tools/lkl/tests/net.sh index 05bb2843a9d439..e7b9c40dc74a41 100755 --- a/tools/lkl/tests/net.sh +++ b/tools/lkl/tests/net.sh @@ -82,6 +82,9 @@ setup_backend() export_vars work_dir fifo1 fifo2 ;; "tap") + if [ -n "$LKL_HOST_CONFIG_NT" ]; then + return $TEST_SKIP + fi tap_prepare if ! lkl_test_cmd test -c /dev/net/tun; then if [ -z "$LKL_HOST_CONFIG_BSD" ]; then @@ -121,6 +124,10 @@ setup_backend() echo "skipping on non-windows 64-bits host" return $TEST_SKIP fi + if ! command -v netsh > /dev/null; then + echo "no netsh command (running under wine?)" + return $TEST_SKIP + fi netsh interface ip set address \ "OpenVPN TAP-Windows6" static $(ip_host) 255.255.255.0 0.0.0.0 netsh advfirewall set allprofiles state off