2023-07-15 18:30:04

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 00/18] tools/nolibc: shrink arch support

Hi, Willy, Thomas

Thanks very much for your careful review and great suggestions, now, we
get v4 revision of the arch shrink series [1], it mainly include a new
fixup for -O0 under gcc < 11.1.0, the stackprotector support for
_start_c(), new testcases for startup code and two new test targets.

All of the tests passed or skipped (tinyconfig + few options +
qemu-system) for both -Os and -O0:

arch/board | result
------------|------------
arm/versatilepb | 165 test(s): 158 passed, 7 skipped, 0 failed => status: warning.
arm/vexpress-a9 | 165 test(s): 158 passed, 7 skipped, 0 failed => status: warning.
arm/virt | 165 test(s): 158 passed, 7 skipped, 0 failed => status: warning.
aarch64/virt | 165 test(s): 158 passed, 7 skipped, 0 failed => status: warning.
i386/pc | 165 test(s): 158 passed, 7 skipped, 0 failed => status: warning.
x86_64/pc | 165 test(s): 158 passed, 7 skipped, 0 failed => status: warning.
mipsel/malta | 165 test(s): 158 passed, 7 skipped, 0 failed => status: warning.
loongarch64/virt | 165 test(s): 158 passed, 7 skipped, 0 failed => status: warning.
riscv64/virt | 165 test(s): 158 passed, 7 skipped, 0 failed => status: warning.
s390x/s390-ccw-virtio | 165 test(s): 158 passed, 7 skipped, 0 failed => status: warning.

And more, for both -Os and -O0:

$ for r in run-user run-nolibc-test run-libc-test; do make clean > /dev/null; make $r | grep status; done
165 test(s): 157 passed, 8 skipped, 0 failed => status: warning
165 test(s): 157 passed, 8 skipped, 0 failed => status: warning
165 test(s): 153 passed, 12 skipped, 0 failed => status: warning

// for make run-user, the euid0 and 32bit limit related tests are
// skipped
$ make clean && make run-user
$ grep -i skip run.out
17 chroot_root [SKIPPED]
39 link_dir [SKIPPED]
62 limit_intptr_min_32 [SKIPPED]
63 limit_intptr_max_32 [SKIPPED]
64 limit_uintptr_max_32 [SKIPPED]
65 limit_ptrdiff_min_32 [SKIPPED]
66 limit_ptrdiff_max_32 [SKIPPED]
67 limit_size_max_32 [SKIPPED]

// for run-libc-test, the _auxv variables, euid0, 32bits limit and
// stackprotector related tests are skipped
$ make clean && make run-libc-test
$ grep -i skip run.out
9 environ_auxv [SKIPPED]
10 environ_total [SKIPPED]
12 auxv_addr [SKIPPED]
17 chroot_root [SKIPPED]
39 link_dir [SKIPPED]
62 limit_intptr_min_32 [SKIPPED]
63 limit_intptr_max_32 [SKIPPED]
64 limit_uintptr_max_32 [SKIPPED]
65 limit_ptrdiff_min_32 [SKIPPED]
66 limit_ptrdiff_max_32 [SKIPPED]
67 limit_size_max_32 [SKIPPED]
0 -fstackprotector not supported [SKIPPED]

$ make clean >/dev/null; make run-libc-test CC=/labs/linux-lab/src/examples/musl-install/bin/musl-gcc | grep status
165 test(s): 151 passed, 12 skipped, 2 failed => status: failure

// The failures are expected for musl has disabled both sbrk and brk
// but not the sbrk(0); the _auxv variables, euid0, 32bits limit and
// stackprotector related tests are skipped for musl too

$ grep FAIL -ur run.out
9 sbrk = 1 ENOMEM [FAIL]
10 brk = -1 ENOMEM [FAIL]

$ grep "SKIP" -ur run.out
9 environ_auxv [SKIPPED]
10 environ_total [SKIPPED]
12 auxv_addr [SKIPPED]
17 chroot_root [SKIPPED]
39 link_dir [SKIPPED]
62 limit_intptr_min_32 [SKIPPED]
63 limit_intptr_max_32 [SKIPPED]
64 limit_uintptr_max_32 [SKIPPED]
65 limit_ptrdiff_min_32 [SKIPPED]
66 limit_ptrdiff_max_32 [SKIPPED]
67 limit_size_max_32 [SKIPPED]
0 -fstackprotector not supported [SKIPPED]

For stackprotector, gcc 13.1.0 is used to test on x86_64 standalonely:

$ make run-user CROSS_COMPILE=x86_64-linux- | grep status
165 test(s): 157 passed, 8 skipped, 0 failed => status: warning
$ grep stack -ur run.out
0 -fstackprotector [OK]
$ make run-nolibc-test CROSS_COMPILE=x86_64-linux- | grep status
165 test(s): 157 passed, 8 skipped, 0 failed => status: warning
$ grep stack -ur run.out
0 -fstackprotector [OK]

Changes from v3 --> v4:

* tools/nolibc: arch-*.h: add missing space after ','
tools/nolibc: fix up startup failures for -O0 under gcc < 11.1.0

Both of the above changes are for _start, it is able to merge them
if necessary.

The first one is old for format errors reported by
scripts/checkpatch.pl

The second one is for -O0 failure under gcc < 11.1.0, applied the
optimize("-Os", "omit-frame-pointer") suggestion from Thomas.

* tools/nolibc: remove the old sys_stat support

As suggested by Willy, Document carefully about the statx supported
Linux version info.

* tools/nolibc: add new crt.h with _start_c

The code is polished carefully for smaller size and better
readability.

* tools/nolibc: stackprotector.h: add empty __stack_chk_init for !_NOLIBC_STACKPROTECTOR
tools/nolibc: crt.h: initialize stack protector

As suggested by Thomas, init stackprotector in _start_c() too.

* tools/nolibc: arm: shrink _start with _start_c
tools/nolibc: aarch64: shrink _start with _start_c
tools/nolibc: i386: shrink _start with _start_c
tools/nolibc: x86_64: shrink _start with _start_c
tools/nolibc: mips: shrink _start with _start_c
tools/nolibc: loongarch: shrink _start with _start_c
tools/nolibc: riscv: shrink _start with _start_c
tools/nolibc: s390: shrink _start with _start_c

Removed the stackprotector initialization from _start too, we
already have it in _start_c().

* selftests/nolibc: add EXPECT_PTRGE, EXPECT_PTRGT, EXPECT_PTRLE, EXPECT_PTRLT
selftests/nolibc: add testcases for startup code

Add a new startup test group to cover the testing of argc,
argv/argv0, envp/environ and _auxv.

Some testcases are enhanced, some are newly added from after the
discussion during v3 review.

* selftests/nolibc: allow run nolibc-test locally
selftests/nolibc: allow test -include /path/to/nolibc.h

Two new test targets are added to cover more scenes.

Hope you like this revisoin ;-)

Next patchset is powerpc & powerpc64 support, after that we will send
the v2 of tinyconfig support, at last the left rv32 patches (mainly
64bit time).

Best regards,
Zhangjin
---
[1]: https://lore.kernel.org/lkml/[email protected]/

Zhangjin Wu (18):
tools/nolibc: arch-*.h: add missing space after ','
tools/nolibc: fix up startup failures for -O0 under gcc < 11.1.0
tools/nolibc: remove the old sys_stat support
tools/nolibc: add new crt.h with _start_c
tools/nolibc: stackprotector.h: add empty __stack_chk_init for
!_NOLIBC_STACKPROTECTOR
tools/nolibc: crt.h: initialize stack protector
tools/nolibc: arm: shrink _start with _start_c
tools/nolibc: aarch64: shrink _start with _start_c
tools/nolibc: i386: shrink _start with _start_c
tools/nolibc: x86_64: shrink _start with _start_c
tools/nolibc: mips: shrink _start with _start_c
tools/nolibc: loongarch: shrink _start with _start_c
tools/nolibc: riscv: shrink _start with _start_c
tools/nolibc: s390: shrink _start with _start_c
selftests/nolibc: add EXPECT_PTRGE, EXPECT_PTRGT, EXPECT_PTRLE,
EXPECT_PTRLT
selftests/nolibc: add testcases for startup code
selftests/nolibc: allow run nolibc-test locally
selftests/nolibc: allow test -include /path/to/nolibc.h

tools/include/nolibc/Makefile | 1 +
tools/include/nolibc/arch-aarch64.h | 57 +---------
tools/include/nolibc/arch-arm.h | 83 ++-------------
tools/include/nolibc/arch-i386.h | 62 ++---------
tools/include/nolibc/arch-loongarch.h | 46 +-------
tools/include/nolibc/arch-mips.h | 76 ++-----------
tools/include/nolibc/arch-riscv.h | 69 ++----------
tools/include/nolibc/arch-s390.h | 63 ++---------
tools/include/nolibc/arch-x86_64.h | 58 ++--------
tools/include/nolibc/crt.h | 61 +++++++++++
tools/include/nolibc/stackprotector.h | 2 +
tools/include/nolibc/sys.h | 63 ++---------
tools/include/nolibc/types.h | 4 +-
tools/testing/selftests/nolibc/Makefile | 12 +++
tools/testing/selftests/nolibc/nolibc-test.c | 106 ++++++++++++++++++-
15 files changed, 246 insertions(+), 517 deletions(-)
create mode 100644 tools/include/nolibc/crt.h

--
2.25.1



2023-07-15 18:31:52

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 03/18] tools/nolibc: remove the old sys_stat support

The statx manpage [1] shows that it has been supported from Linux 4.11
and glibc 2.28, the Linux support can be checked for all of the
architectures with this command:

$ git grep -r statx v4.11 arch/ include/uapi/asm-generic/unistd.h \
| grep -E "aarch64|arm|mips|s390|x86|:include/uapi"

Besides riscv and loongarch, all of the nolibc supported architectures
have added sys_statx from Linux v4.11. riscv is mainlined to v4.15,
loongarch is mainlined to v5.19, both of them use the generic unistd.h,
so, they have added sys_statx from their first mainline versions.

The current oldest stable branch is v4.14, only reserving sys_statx
still preserves compatibility with all of the supported stable branches,
So, let's remove the old arch related and dependent sys_stat support
completely.

This is friendly to the future new architecture porting.

[1]: https://man7.org/linux/man-pages/man2/statx.2.html

Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/include/nolibc/arch-aarch64.h | 28 -------------
tools/include/nolibc/arch-arm.h | 37 -----------------
tools/include/nolibc/arch-i386.h | 26 ------------
tools/include/nolibc/arch-mips.h | 28 -------------
tools/include/nolibc/arch-riscv.h | 23 -----------
tools/include/nolibc/arch-s390.h | 25 ------------
tools/include/nolibc/arch-x86_64.h | 27 -------------
tools/include/nolibc/sys.h | 63 +++++------------------------
tools/include/nolibc/types.h | 4 +-
9 files changed, 13 insertions(+), 248 deletions(-)

diff --git a/tools/include/nolibc/arch-aarch64.h b/tools/include/nolibc/arch-aarch64.h
index 21e9482a4235..3c0a5f47b3e8 100644
--- a/tools/include/nolibc/arch-aarch64.h
+++ b/tools/include/nolibc/arch-aarch64.h
@@ -9,34 +9,6 @@

#include "compiler.h"

-/* The struct returned by the newfstatat() syscall. Differs slightly from the
- * x86_64's stat one by field ordering, so be careful.
- */
-struct sys_stat_struct {
- unsigned long st_dev;
- unsigned long st_ino;
- unsigned int st_mode;
- unsigned int st_nlink;
- unsigned int st_uid;
- unsigned int st_gid;
-
- unsigned long st_rdev;
- unsigned long __pad1;
- long st_size;
- int st_blksize;
- int __pad2;
-
- long st_blocks;
- long st_atime;
- unsigned long st_atime_nsec;
- long st_mtime;
-
- unsigned long st_mtime_nsec;
- long st_ctime;
- unsigned long st_ctime_nsec;
- unsigned int __unused[2];
-};
-
/* Syscalls for AARCH64 :
* - registers are 64-bit
* - stack is 16-byte aligned
diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h
index 4451bef5f94d..a06dad789a22 100644
--- a/tools/include/nolibc/arch-arm.h
+++ b/tools/include/nolibc/arch-arm.h
@@ -9,43 +9,6 @@

#include "compiler.h"

-/* The struct returned by the stat() syscall, 32-bit only, the syscall returns
- * exactly 56 bytes (stops before the unused array). In big endian, the format
- * differs as devices are returned as short only.
- */
-struct sys_stat_struct {
-#if defined(__ARMEB__)
- unsigned short st_dev;
- unsigned short __pad1;
-#else
- unsigned long st_dev;
-#endif
- unsigned long st_ino;
- unsigned short st_mode;
- unsigned short st_nlink;
- unsigned short st_uid;
- unsigned short st_gid;
-
-#if defined(__ARMEB__)
- unsigned short st_rdev;
- unsigned short __pad2;
-#else
- unsigned long st_rdev;
-#endif
- unsigned long st_size;
- unsigned long st_blksize;
- unsigned long st_blocks;
-
- unsigned long st_atime;
- unsigned long st_atime_nsec;
- unsigned long st_mtime;
- unsigned long st_mtime_nsec;
-
- unsigned long st_ctime;
- unsigned long st_ctime_nsec;
- unsigned long __unused[2];
-};
-
/* Syscalls for ARM in ARM or Thumb modes :
* - registers are 32-bit
* - stack is 8-byte aligned
diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h
index 4c94a81e860f..fe0b73f032c3 100644
--- a/tools/include/nolibc/arch-i386.h
+++ b/tools/include/nolibc/arch-i386.h
@@ -9,32 +9,6 @@

#include "compiler.h"

-/* The struct returned by the stat() syscall, 32-bit only, the syscall returns
- * exactly 56 bytes (stops before the unused array).
- */
-struct sys_stat_struct {
- unsigned long st_dev;
- unsigned long st_ino;
- unsigned short st_mode;
- unsigned short st_nlink;
- unsigned short st_uid;
- unsigned short st_gid;
-
- unsigned long st_rdev;
- unsigned long st_size;
- unsigned long st_blksize;
- unsigned long st_blocks;
-
- unsigned long st_atime;
- unsigned long st_atime_nsec;
- unsigned long st_mtime;
- unsigned long st_mtime_nsec;
-
- unsigned long st_ctime;
- unsigned long st_ctime_nsec;
- unsigned long __unused[2];
-};
-
/* Syscalls for i386 :
* - mostly similar to x86_64
* - registers are 32-bit
diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h
index d3f0bf4c4245..7242fc9de04f 100644
--- a/tools/include/nolibc/arch-mips.h
+++ b/tools/include/nolibc/arch-mips.h
@@ -9,34 +9,6 @@

#include "compiler.h"

-/* The struct returned by the stat() syscall. 88 bytes are returned by the
- * syscall.
- */
-struct sys_stat_struct {
- unsigned int st_dev;
- long st_pad1[3];
- unsigned long st_ino;
- unsigned int st_mode;
- unsigned int st_nlink;
- unsigned int st_uid;
- unsigned int st_gid;
- unsigned int st_rdev;
- long st_pad2[2];
- long st_size;
- long st_pad3;
-
- long st_atime;
- long st_atime_nsec;
- long st_mtime;
- long st_mtime_nsec;
-
- long st_ctime;
- long st_ctime_nsec;
- long st_blksize;
- long st_blocks;
- long st_pad4[14];
-};
-
/* Syscalls for MIPS ABI O32 :
* - WARNING! there's always a delayed slot!
* - WARNING again, the syntax is different, registers take a '$' and numbers
diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h
index 322c96f4acdb..d49f5ecbf815 100644
--- a/tools/include/nolibc/arch-riscv.h
+++ b/tools/include/nolibc/arch-riscv.h
@@ -9,29 +9,6 @@

#include "compiler.h"

-struct sys_stat_struct {
- unsigned long st_dev; /* Device. */
- unsigned long st_ino; /* File serial number. */
- unsigned int st_mode; /* File mode. */
- unsigned int st_nlink; /* Link count. */
- unsigned int st_uid; /* User ID of the file's owner. */
- unsigned int st_gid; /* Group ID of the file's group. */
- unsigned long st_rdev; /* Device number, if device. */
- unsigned long __pad1;
- long st_size; /* Size of file, in bytes. */
- int st_blksize; /* Optimal block size for I/O. */
- int __pad2;
- long st_blocks; /* Number 512-byte blocks allocated. */
- long st_atime; /* Time of last access. */
- unsigned long st_atime_nsec;
- long st_mtime; /* Time of last modification. */
- unsigned long st_mtime_nsec;
- long st_ctime; /* Time of last status change. */
- unsigned long st_ctime_nsec;
- unsigned int __unused4;
- unsigned int __unused5;
-};
-
#if __riscv_xlen == 64
#define PTRLOG "3"
#define SZREG "8"
diff --git a/tools/include/nolibc/arch-s390.h b/tools/include/nolibc/arch-s390.h
index 587cc91295fa..3b94ae0cb1d1 100644
--- a/tools/include/nolibc/arch-s390.h
+++ b/tools/include/nolibc/arch-s390.h
@@ -10,31 +10,6 @@

#include "compiler.h"

-/* The struct returned by the stat() syscall, equivalent to stat64(). The
- * syscall returns 116 bytes and stops in the middle of __unused.
- */
-
-struct sys_stat_struct {
- unsigned long st_dev;
- unsigned long st_ino;
- unsigned long st_nlink;
- unsigned int st_mode;
- unsigned int st_uid;
- unsigned int st_gid;
- unsigned int __pad1;
- unsigned long st_rdev;
- unsigned long st_size;
- unsigned long st_atime;
- unsigned long st_atime_nsec;
- unsigned long st_mtime;
- unsigned long st_mtime_nsec;
- unsigned long st_ctime;
- unsigned long st_ctime_nsec;
- unsigned long st_blksize;
- long st_blocks;
- unsigned long __unused[3];
-};
-
/* Syscalls for s390:
* - registers are 64-bit
* - syscall number is passed in r1
diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h
index 5e950a04bc77..6b494ca471ef 100644
--- a/tools/include/nolibc/arch-x86_64.h
+++ b/tools/include/nolibc/arch-x86_64.h
@@ -9,33 +9,6 @@

#include "compiler.h"

-/* The struct returned by the stat() syscall, equivalent to stat64(). The
- * syscall returns 116 bytes and stops in the middle of __unused.
- */
-struct sys_stat_struct {
- unsigned long st_dev;
- unsigned long st_ino;
- unsigned long st_nlink;
- unsigned int st_mode;
- unsigned int st_uid;
-
- unsigned int st_gid;
- unsigned int __pad0;
- unsigned long st_rdev;
- long st_size;
- long st_blksize;
-
- long st_blocks;
- unsigned long st_atime;
- unsigned long st_atime_nsec;
- unsigned long st_mtime;
-
- unsigned long st_mtime_nsec;
- unsigned long st_ctime;
- unsigned long st_ctime_nsec;
- long __unused[3];
-};
-
/* Syscalls for x86_64 :
* - registers are 64-bit
* - syscall number is passed in rax
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index dee56894a811..8bfe7db20b80 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -943,15 +943,19 @@ pid_t setsid(void)
return __sysret(sys_setsid());
}

-#if defined(__NR_statx)
/*
* int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf);
+ * int stat(const char *path, struct stat *buf);
*/

static __attribute__((unused))
int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf)
{
+#ifdef __NR_statx
return my_syscall5(__NR_statx, fd, path, flags, mask, buf);
+#else
+ return -ENOSYS;
+#endif
}

static __attribute__((unused))
@@ -959,24 +963,18 @@ int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *
{
return __sysret(sys_statx(fd, path, flags, mask, buf));
}
-#endif

-/*
- * int stat(const char *path, struct stat *buf);
- * Warning: the struct stat's layout is arch-dependent.
- */

-#if defined(__NR_statx) && !defined(__NR_newfstatat) && !defined(__NR_stat)
-/*
- * Maybe we can just use statx() when available for all architectures?
- */
static __attribute__((unused))
-int sys_stat(const char *path, struct stat *buf)
+int stat(const char *path, struct stat *buf)
{
struct statx statx;
long ret;

- ret = sys_statx(AT_FDCWD, path, AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx);
+ ret = __sysret(sys_statx(AT_FDCWD, path, AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx));
+ if (ret == -1)
+ return ret;
+
buf->st_dev = ((statx.stx_dev_minor & 0xff)
| (statx.stx_dev_major << 8)
| ((statx.stx_dev_minor & ~0xff) << 12));
@@ -997,47 +995,8 @@ int sys_stat(const char *path, struct stat *buf)
buf->st_mtim.tv_nsec = statx.stx_mtime.tv_nsec;
buf->st_ctim.tv_sec = statx.stx_ctime.tv_sec;
buf->st_ctim.tv_nsec = statx.stx_ctime.tv_nsec;
- return ret;
-}
-#else
-static __attribute__((unused))
-int sys_stat(const char *path, struct stat *buf)
-{
- struct sys_stat_struct stat;
- long ret;
-
-#ifdef __NR_newfstatat
- /* only solution for arm64 */
- ret = my_syscall4(__NR_newfstatat, AT_FDCWD, path, &stat, 0);
-#elif defined(__NR_stat)
- ret = my_syscall2(__NR_stat, path, &stat);
-#else
- return -ENOSYS;
-#endif
- buf->st_dev = stat.st_dev;
- buf->st_ino = stat.st_ino;
- buf->st_mode = stat.st_mode;
- buf->st_nlink = stat.st_nlink;
- buf->st_uid = stat.st_uid;
- buf->st_gid = stat.st_gid;
- buf->st_rdev = stat.st_rdev;
- buf->st_size = stat.st_size;
- buf->st_blksize = stat.st_blksize;
- buf->st_blocks = stat.st_blocks;
- buf->st_atim.tv_sec = stat.st_atime;
- buf->st_atim.tv_nsec = stat.st_atime_nsec;
- buf->st_mtim.tv_sec = stat.st_mtime;
- buf->st_mtim.tv_nsec = stat.st_mtime_nsec;
- buf->st_ctim.tv_sec = stat.st_ctime;
- buf->st_ctim.tv_nsec = stat.st_ctime_nsec;
- return ret;
-}
-#endif

-static __attribute__((unused))
-int stat(const char *path, struct stat *buf)
-{
- return __sysret(sys_stat(path, buf));
+ return 0;
}


diff --git a/tools/include/nolibc/types.h b/tools/include/nolibc/types.h
index 23963e48d8ee..8cfc4c860fa4 100644
--- a/tools/include/nolibc/types.h
+++ b/tools/include/nolibc/types.h
@@ -15,8 +15,8 @@


/* Only the generic macros and types may be defined here. The arch-specific
- * ones such as the O_RDONLY and related macros used by fcntl() and open(), or
- * the layout of sys_stat_struct must not be defined here.
+ * ones such as the O_RDONLY and related macros used by fcntl() and open()
+ * must not be defined here.
*/

/* stat flags (WARNING, octal here). We need to check for an existing
--
2.25.1


2023-07-15 18:33:52

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 05/18] tools/nolibc: stackprotector.h: add empty __stack_chk_init for !_NOLIBC_STACKPROTECTOR

Let's define an empty __stack_chk_init for the !_NOLIBC_STACKPROTECTOR
branch.

This allows to remove #ifdef around every call of __stack_chk_init().

Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/include/nolibc/stackprotector.h | 2 ++
1 file changed, 2 insertions(+)

diff --git a/tools/include/nolibc/stackprotector.h b/tools/include/nolibc/stackprotector.h
index 88f7b2d098ff..b620f2b9578d 100644
--- a/tools/include/nolibc/stackprotector.h
+++ b/tools/include/nolibc/stackprotector.h
@@ -45,6 +45,8 @@ void __stack_chk_init(void)
if (__stack_chk_guard != (uintptr_t) &__stack_chk_guard)
__stack_chk_guard ^= (uintptr_t) &__stack_chk_guard;
}
+#else /* !defined(_NOLIBC_STACKPROTECTOR) */
+__inline__ void __stack_chk_init(void) {}
#endif /* defined(_NOLIBC_STACKPROTECTOR) */

#endif /* _NOLIBC_STACKPROTECTOR_H */
--
2.25.1


2023-07-15 18:34:26

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 07/18] tools/nolibc: arm: shrink _start with _start_c

move most of the _start operations to _start_c(), include the
stackprotector initialization.

Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/include/nolibc/arch-arm.h | 44 ++++-----------------------------
1 file changed, 5 insertions(+), 39 deletions(-)

diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h
index a06dad789a22..cae4afa7c1c7 100644
--- a/tools/include/nolibc/arch-arm.h
+++ b/tools/include/nolibc/arch-arm.h
@@ -8,6 +8,7 @@
#define _NOLIBC_ARCH_ARM_H

#include "compiler.h"
+#include "crt.h"

/* Syscalls for ARM in ARM or Thumb modes :
* - registers are 32-bit
@@ -183,49 +184,14 @@
_arg1; \
})

-
-char **environ __attribute__((weak));
-const unsigned long *_auxv __attribute__((weak));
-
/* startup code */
void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
-#ifdef _NOLIBC_STACKPROTECTOR
- "bl __stack_chk_init\n" /* initialize stack protector */
-#endif
- "pop {%r0}\n" /* argc was in the stack */
- "mov %r1, %sp\n" /* argv = sp */
-
- "add %r2, %r0, $1\n" /* envp = (argc + 1) ... */
- "lsl %r2, %r2, $2\n" /* * 4 ... */
- "add %r2, %r2, %r1\n" /* + argv */
- "ldr %r3, 1f\n" /* r3 = &environ (see below) */
- "str %r2, [r3]\n" /* store envp into environ */
-
- "mov r4, r2\n" /* search for auxv (follows NULL after last env) */
- "0:\n"
- "mov r5, r4\n" /* r5 = r4 */
- "add r4, r4, #4\n" /* r4 += 4 */
- "ldr r5,[r5]\n" /* r5 = *r5 = *(r4-4) */
- "cmp r5, #0\n" /* and stop at NULL after last env */
- "bne 0b\n"
- "ldr %r3, 2f\n" /* r3 = &_auxv (low bits) */
- "str r4, [r3]\n" /* store r4 into _auxv */
-
- "mov %r3, $8\n" /* AAPCS : sp must be 8-byte aligned in the */
- "neg %r3, %r3\n" /* callee, and bl doesn't push (lr=pc) */
- "and %r3, %r3, %r1\n" /* so we do sp = r1(=sp) & r3(=-8); */
- "mov %sp, %r3\n"
-
- "bl main\n" /* main() returns the status code, we'll exit with it. */
- "movs r7, $1\n" /* NR_exit == 1 */
- "svc $0x00\n"
- ".align 2\n" /* below are the pointers to a few variables */
- "1:\n"
- ".word environ\n"
- "2:\n"
- ".word _auxv\n"
+ "mov %r0, sp\n" /* save stack pointer to %r0, as arg1 of _start_c */
+ "and ip, %r0, #-8\n" /* sp must be 8-byte aligned in the callee */
+ "mov sp, ip\n"
+ "bl _start_c\n" /* transfer to c runtime */
);
__builtin_unreachable();
}
--
2.25.1


2023-07-15 18:36:26

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 09/18] tools/nolibc: i386: shrink _start with _start_c

move most of the _start operations to _start_c(), include the
stackprotector initialization.

Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/include/nolibc/arch-i386.h | 34 +++++++-------------------------
1 file changed, 7 insertions(+), 27 deletions(-)

diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h
index fe0b73f032c3..64415b9fac77 100644
--- a/tools/include/nolibc/arch-i386.h
+++ b/tools/include/nolibc/arch-i386.h
@@ -8,6 +8,7 @@
#define _NOLIBC_ARCH_I386_H

#include "compiler.h"
+#include "crt.h"

/* Syscalls for i386 :
* - mostly similar to x86_64
@@ -154,9 +155,6 @@
_eax; \
})

-char **environ __attribute__((weak));
-const unsigned long *_auxv __attribute__((weak));
-
/* startup code */
/*
* i386 System V ABI mandates:
@@ -167,30 +165,12 @@ const unsigned long *_auxv __attribute__((weak));
void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
-#ifdef _NOLIBC_STACKPROTECTOR
- "call __stack_chk_init\n" /* initialize stack protector */
-#endif
- "pop %eax\n" /* argc (first arg, %eax) */
- "mov %esp, %ebx\n" /* argv[] (second arg, %ebx) */
- "lea 4(%ebx,%eax,4),%ecx\n" /* then a NULL then envp (third arg, %ecx) */
- "mov %ecx, environ\n" /* save environ */
- "xor %ebp, %ebp\n" /* zero the stack frame */
- "mov %ecx, %edx\n" /* search for auxv (follows NULL after last env) */
- "0:\n"
- "add $4, %edx\n" /* search for auxv using edx, it follows the */
- "cmp -4(%edx), %ebp\n" /* ... NULL after last env (ebp is zero here) */
- "jnz 0b\n"
- "mov %edx, _auxv\n" /* save it into _auxv */
- "and $-16, %esp\n" /* x86 ABI : esp must be 16-byte aligned before */
- "sub $4, %esp\n" /* the call instruction (args are aligned) */
- "push %ecx\n" /* push all registers on the stack so that we */
- "push %ebx\n" /* support both regparm and plain stack modes */
- "push %eax\n"
- "call main\n" /* main() returns the status code in %eax */
- "mov %eax, %ebx\n" /* retrieve exit code (32-bit int) */
- "movl $1, %eax\n" /* NR_exit == 1 */
- "int $0x80\n" /* exit now */
- "hlt\n" /* ensure it does not */
+ "xor %ebp, %ebp\n" /* zero the stack frame */
+ "mov %esp, %eax\n" /* save stack pointer to %eax, as arg1 of _start_c */
+ "and $-16, %esp\n" /* last pushed argument must be 16-byte aligned */
+ "push %eax\n" /* push arg1 on stack to support plain stack modes too */
+ "call _start_c\n" /* transfer to c runtime */
+ "hlt\n" /* ensure it does not return */
);
__builtin_unreachable();
}
--
2.25.1


2023-07-15 18:42:25

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 02/18] tools/nolibc: fix up startup failures for -O0 under gcc < 11.1.0

As gcc doc [1] shows:

Most optimizations are completely disabled at -O0 or if an -O level is
not set on the command line, even if individual optimization flags are
specified.

Test result [2] shows, gcc>=11.1.0 deviates from the above description,
but before gcc 11.1.0, "-O0" still forcely uses frame pointer in the
_start function even if the individual optimize("omit-frame-pointer")
flag is specified.

The frame pointer related operations will change the stack pointer (e.g.
In x86_64, an extra "push %rbp" will be inserted at the beginning of
_start) and make it differs from the one we expected, as a result, break
the whole startup function.

To fix up this issue, as suggested by Thomas, the individual "Os" and
"omit-frame-pointer" optimize flags are used together on _start function
to disable frame pointer completely even if the -O0 is set on the
command line.

[1]: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
[2]: https://lore.kernel.org/lkml/[email protected]/

Suggested-by: Thomas Weißschuh <[email protected]>
Link: https://lore.kernel.org/lkml/[email protected]/
Fixes: 7f8548589661 ("tools/nolibc: make compiler and assembler agree on the section around _start")
Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/include/nolibc/arch-aarch64.h | 2 +-
tools/include/nolibc/arch-arm.h | 2 +-
tools/include/nolibc/arch-i386.h | 2 +-
tools/include/nolibc/arch-loongarch.h | 2 +-
tools/include/nolibc/arch-mips.h | 2 +-
tools/include/nolibc/arch-riscv.h | 2 +-
tools/include/nolibc/arch-s390.h | 2 +-
tools/include/nolibc/arch-x86_64.h | 2 +-
8 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/tools/include/nolibc/arch-aarch64.h b/tools/include/nolibc/arch-aarch64.h
index 6151be6cd7a9..21e9482a4235 100644
--- a/tools/include/nolibc/arch-aarch64.h
+++ b/tools/include/nolibc/arch-aarch64.h
@@ -175,7 +175,7 @@ char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));

/* startup code */
-void __attribute__((weak, noreturn, optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
+void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
#ifdef _NOLIBC_STACKPROTECTOR
diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h
index 5b12b6e1c83e..4451bef5f94d 100644
--- a/tools/include/nolibc/arch-arm.h
+++ b/tools/include/nolibc/arch-arm.h
@@ -225,7 +225,7 @@ char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));

/* startup code */
-void __attribute__((weak, noreturn, optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
+void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
#ifdef _NOLIBC_STACKPROTECTOR
diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h
index 35680b4a25d4..4c94a81e860f 100644
--- a/tools/include/nolibc/arch-i386.h
+++ b/tools/include/nolibc/arch-i386.h
@@ -190,7 +190,7 @@ const unsigned long *_auxv __attribute__((weak));
* 2) The deepest stack frame should be set to zero
*
*/
-void __attribute__((weak, noreturn, optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
+void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
#ifdef _NOLIBC_STACKPROTECTOR
diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h
index ada5a69e3fcc..590155a4e543 100644
--- a/tools/include/nolibc/arch-loongarch.h
+++ b/tools/include/nolibc/arch-loongarch.h
@@ -167,7 +167,7 @@ const unsigned long *_auxv __attribute__((weak));
#endif

/* startup code */
-void __attribute__((weak, noreturn, optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
+void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
#ifdef _NOLIBC_STACKPROTECTOR
diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h
index dd0f12131b55..d3f0bf4c4245 100644
--- a/tools/include/nolibc/arch-mips.h
+++ b/tools/include/nolibc/arch-mips.h
@@ -205,7 +205,7 @@ char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));

/* startup code, note that it's called __start on MIPS */
-void __attribute__((weak, noreturn, optimize("omit-frame-pointer"))) __no_stack_protector __start(void)
+void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector __start(void)
{
__asm__ volatile (
/*".set nomips16\n"*/
diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h
index 1dd7083c2ac8..322c96f4acdb 100644
--- a/tools/include/nolibc/arch-riscv.h
+++ b/tools/include/nolibc/arch-riscv.h
@@ -180,7 +180,7 @@ char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));

/* startup code */
-void __attribute__((weak, noreturn, optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
+void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
".option push\n"
diff --git a/tools/include/nolibc/arch-s390.h b/tools/include/nolibc/arch-s390.h
index 8254caff8bfa..587cc91295fa 100644
--- a/tools/include/nolibc/arch-s390.h
+++ b/tools/include/nolibc/arch-s390.h
@@ -166,7 +166,7 @@ char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));

/* startup code */
-void __attribute__((weak, noreturn, optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
+void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
"lg %r2,0(%r15)\n" /* argument count */
diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h
index fb00ab2e9274..5e950a04bc77 100644
--- a/tools/include/nolibc/arch-x86_64.h
+++ b/tools/include/nolibc/arch-x86_64.h
@@ -190,7 +190,7 @@ const unsigned long *_auxv __attribute__((weak));
* 2) The deepest stack frame should be zero (the %rbp).
*
*/
-void __attribute__((weak, noreturn, optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
+void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
#ifdef _NOLIBC_STACKPROTECTOR
--
2.25.1


2023-07-15 18:54:39

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 01/18] tools/nolibc: arch-*.h: add missing space after ','

Fix up such errors reported by scripts/checkpatch.pl:

ERROR: space required after that ',' (ctx:VxV)
#148: FILE: tools/include/nolibc/arch-aarch64.h:148:
+void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
^

ERROR: space required after that ',' (ctx:VxV)
#148: FILE: tools/include/nolibc/arch-aarch64.h:148:
+void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
^

Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/include/nolibc/arch-aarch64.h | 2 +-
tools/include/nolibc/arch-arm.h | 2 +-
tools/include/nolibc/arch-i386.h | 2 +-
tools/include/nolibc/arch-loongarch.h | 2 +-
tools/include/nolibc/arch-mips.h | 2 +-
tools/include/nolibc/arch-riscv.h | 2 +-
tools/include/nolibc/arch-s390.h | 2 +-
tools/include/nolibc/arch-x86_64.h | 2 +-
8 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/tools/include/nolibc/arch-aarch64.h b/tools/include/nolibc/arch-aarch64.h
index 6227b77a4a09..6151be6cd7a9 100644
--- a/tools/include/nolibc/arch-aarch64.h
+++ b/tools/include/nolibc/arch-aarch64.h
@@ -175,7 +175,7 @@ char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));

/* startup code */
-void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
+void __attribute__((weak, noreturn, optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
#ifdef _NOLIBC_STACKPROTECTOR
diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h
index 4d4887a5f04b..5b12b6e1c83e 100644
--- a/tools/include/nolibc/arch-arm.h
+++ b/tools/include/nolibc/arch-arm.h
@@ -225,7 +225,7 @@ char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));

/* startup code */
-void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
+void __attribute__((weak, noreturn, optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
#ifdef _NOLIBC_STACKPROTECTOR
diff --git a/tools/include/nolibc/arch-i386.h b/tools/include/nolibc/arch-i386.h
index 4c6b7c04e2e7..35680b4a25d4 100644
--- a/tools/include/nolibc/arch-i386.h
+++ b/tools/include/nolibc/arch-i386.h
@@ -190,7 +190,7 @@ const unsigned long *_auxv __attribute__((weak));
* 2) The deepest stack frame should be set to zero
*
*/
-void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
+void __attribute__((weak, noreturn, optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
#ifdef _NOLIBC_STACKPROTECTOR
diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h
index 8aa7724fe38e..ada5a69e3fcc 100644
--- a/tools/include/nolibc/arch-loongarch.h
+++ b/tools/include/nolibc/arch-loongarch.h
@@ -167,7 +167,7 @@ const unsigned long *_auxv __attribute__((weak));
#endif

/* startup code */
-void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
+void __attribute__((weak, noreturn, optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
#ifdef _NOLIBC_STACKPROTECTOR
diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h
index a2bfdf57b957..dd0f12131b55 100644
--- a/tools/include/nolibc/arch-mips.h
+++ b/tools/include/nolibc/arch-mips.h
@@ -205,7 +205,7 @@ char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));

/* startup code, note that it's called __start on MIPS */
-void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector __start(void)
+void __attribute__((weak, noreturn, optimize("omit-frame-pointer"))) __no_stack_protector __start(void)
{
__asm__ volatile (
/*".set nomips16\n"*/
diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h
index cd958b2f4b1b..1dd7083c2ac8 100644
--- a/tools/include/nolibc/arch-riscv.h
+++ b/tools/include/nolibc/arch-riscv.h
@@ -180,7 +180,7 @@ char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));

/* startup code */
-void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
+void __attribute__((weak, noreturn, optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
".option push\n"
diff --git a/tools/include/nolibc/arch-s390.h b/tools/include/nolibc/arch-s390.h
index a644ecd361c0..8254caff8bfa 100644
--- a/tools/include/nolibc/arch-s390.h
+++ b/tools/include/nolibc/arch-s390.h
@@ -166,7 +166,7 @@ char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));

/* startup code */
-void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
+void __attribute__((weak, noreturn, optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
"lg %r2,0(%r15)\n" /* argument count */
diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h
index e69113742a99..fb00ab2e9274 100644
--- a/tools/include/nolibc/arch-x86_64.h
+++ b/tools/include/nolibc/arch-x86_64.h
@@ -190,7 +190,7 @@ const unsigned long *_auxv __attribute__((weak));
* 2) The deepest stack frame should be zero (the %rbp).
*
*/
-void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
+void __attribute__((weak, noreturn, optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
#ifdef _NOLIBC_STACKPROTECTOR
--
2.25.1



2023-07-15 18:54:43

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 10/18] tools/nolibc: x86_64: shrink _start with _start_c

move most of the _start operations to _start_c(), include the
stackprotector initialization.

Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/include/nolibc/arch-x86_64.h | 29 ++++++-----------------------
1 file changed, 6 insertions(+), 23 deletions(-)

diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h
index 6b494ca471ef..e5ccb926c903 100644
--- a/tools/include/nolibc/arch-x86_64.h
+++ b/tools/include/nolibc/arch-x86_64.h
@@ -8,6 +8,7 @@
#define _NOLIBC_ARCH_X86_64_H

#include "compiler.h"
+#include "crt.h"

/* Syscalls for x86_64 :
* - registers are 64-bit
@@ -153,9 +154,6 @@
_ret; \
})

-char **environ __attribute__((weak));
-const unsigned long *_auxv __attribute__((weak));
-
/* startup code */
/*
* x86-64 System V ABI mandates:
@@ -166,26 +164,11 @@ const unsigned long *_auxv __attribute__((weak));
void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
-#ifdef _NOLIBC_STACKPROTECTOR
- "call __stack_chk_init\n" /* initialize stack protector */
-#endif
- "pop %rdi\n" /* argc (first arg, %rdi) */
- "mov %rsp, %rsi\n" /* argv[] (second arg, %rsi) */
- "lea 8(%rsi,%rdi,8),%rdx\n" /* then a NULL then envp (third arg, %rdx) */
- "mov %rdx, environ\n" /* save environ */
- "xor %ebp, %ebp\n" /* zero the stack frame */
- "mov %rdx, %rax\n" /* search for auxv (follows NULL after last env) */
- "0:\n"
- "add $8, %rax\n" /* search for auxv using rax, it follows the */
- "cmp -8(%rax), %rbp\n" /* ... NULL after last env (rbp is zero here) */
- "jnz 0b\n"
- "mov %rax, _auxv\n" /* save it into _auxv */
- "and $-16, %rsp\n" /* x86 ABI : esp must be 16-byte aligned before call */
- "call main\n" /* main() returns the status code, we'll exit with it. */
- "mov %eax, %edi\n" /* retrieve exit code (32 bit) */
- "mov $60, %eax\n" /* NR_exit == 60 */
- "syscall\n" /* really exit */
- "hlt\n" /* ensure it does not return */
+ "xor %ebp, %ebp\n" /* zero the stack frame */
+ "mov %rsp, %rdi\n" /* save stack pointer to %rdi, as arg1 of _start_c */
+ "and $-16, %rsp\n" /* %rsp must be 16-byte aligned before call */
+ "call _start_c\n" /* transfer to c runtime */
+ "hlt\n" /* ensure it does not return */
);
__builtin_unreachable();
}
--
2.25.1


2023-07-15 18:54:53

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 04/18] tools/nolibc: add new crt.h with _start_c

As the environ and _auxv support added for nolibc, the assembly _start
function becomes more and more complex and therefore makes the porting
of nolibc to new architectures harder and harder.

To simplify portability, this C version of _start_c() is added to do
most of the assembly start operations in C, which reduces the complexity
a lot and will eventually simplify the porting of nolibc to the new
architectures.

The new _start_c() only requires a stack pointer argument, it will find
argc, argv, envp/environ and _auxv for us, and then call main(),
finally, it exit() with main's return status. With this new _start_c(),
the future new architectures only require to add very few assembly
instructions.

As suggested by Thomas, users may use a different signature of main
(e.g. void main(void)), a _nolibc_main alias is added for main to
silence the warning about potential conflicting types.

As suggested by Willy, the code is carefully polished for both smaller
size and better readability with local variables and the right types.

Suggested-by: Willy Tarreau <[email protected]>
Link: https://lore.kernel.org/lkml/[email protected]/
Suggested-by: Thomas Weißschuh <[email protected]>
Link: https://lore.kernel.org/lkml/[email protected]/
Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/include/nolibc/Makefile | 1 +
tools/include/nolibc/crt.h | 57 +++++++++++++++++++++++++++++++++++
2 files changed, 58 insertions(+)
create mode 100644 tools/include/nolibc/crt.h

diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile
index 64d67b080744..909b6eb500fe 100644
--- a/tools/include/nolibc/Makefile
+++ b/tools/include/nolibc/Makefile
@@ -27,6 +27,7 @@ nolibc_arch := $(patsubst arm64,aarch64,$(ARCH))
arch_file := arch-$(nolibc_arch).h
all_files := \
compiler.h \
+ crt.h \
ctype.h \
errno.h \
nolibc.h \
diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h
new file mode 100644
index 000000000000..92a2a0478cb1
--- /dev/null
+++ b/tools/include/nolibc/crt.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
+/*
+ * C Run Time support for NOLIBC
+ * Copyright (C) 2023 Zhangjin Wu <[email protected]>
+ */
+
+#ifndef _NOLIBC_CRT_H
+#define _NOLIBC_CRT_H
+
+char **environ __attribute__((weak));
+const unsigned long *_auxv __attribute__((weak));
+
+static void exit(int);
+
+void _start_c(long *sp)
+{
+ long argc;
+ char **argv;
+ char **envp;
+ const unsigned long *auxv;
+ /* silence potential warning: conflicting types for 'main' */
+ int _nolibc_main(int, char **, char **) __asm__ ("main");
+
+ /*
+ * sp : argc <-- argument count, required by main()
+ * argv: argv[0] <-- argument vector, required by main()
+ * argv[1]
+ * ...
+ * argv[argc-1]
+ * null
+ * environ: environ[0] <-- environment variables, required by main() and getenv()
+ * environ[1]
+ * ...
+ * null
+ * _auxv: _auxv[0] <-- auxiliary vector, required by getauxval()
+ * _auxv[1]
+ * ...
+ * null
+ */
+
+ /* assign argc and argv */
+ argc = *sp;
+ argv = (void *)(sp + 1);
+
+ /* find environ */
+ environ = envp = argv + argc + 1;
+
+ /* find _auxv */
+ for (auxv = (void *)envp; *auxv++;)
+ ;
+ _auxv = auxv;
+
+ /* go to application */
+ exit(_nolibc_main(argc, argv, envp));
+}
+
+#endif /* _NOLIBC_CRT_H */
--
2.25.1


2023-07-15 18:54:54

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 06/18] tools/nolibc: crt.h: initialize stack protector

As suggested by Thomas, It is able to move the stackprotector
initialization from the assembly _start to the beginning of the new
_start_c(). Let's call __stack_chk_init() in _start_c() as a
preparation.

Suggested-by: Thomas Weißschuh <[email protected]>
Link: https://lore.kernel.org/lkml/[email protected]/
Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/include/nolibc/crt.h | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h
index 92a2a0478cb1..32e128b0fb62 100644
--- a/tools/include/nolibc/crt.h
+++ b/tools/include/nolibc/crt.h
@@ -10,6 +10,7 @@
char **environ __attribute__((weak));
const unsigned long *_auxv __attribute__((weak));

+void __stack_chk_init(void);
static void exit(int);

void _start_c(long *sp)
@@ -21,6 +22,9 @@ void _start_c(long *sp)
/* silence potential warning: conflicting types for 'main' */
int _nolibc_main(int, char **, char **) __asm__ ("main");

+ /* initialize stack protector */
+ __stack_chk_init();
+
/*
* sp : argc <-- argument count, required by main()
* argv: argv[0] <-- argument vector, required by main()
--
2.25.1


2023-07-15 18:55:04

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 15/18] selftests/nolibc: add EXPECT_PTRGE, EXPECT_PTRGT, EXPECT_PTRLE, EXPECT_PTRLT

4 new pointer compare macros are added, they are similar to the integer
compare macros.

Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/testing/selftests/nolibc/nolibc-test.c | 50 ++++++++++++++++++++
1 file changed, 50 insertions(+)

diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index dfadd07ee7d9..3ff706078fbd 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -410,6 +410,56 @@ static int expect_ptrne(const void *expr, int llen, const void *cmp)
return ret;
}

+#define EXPECT_PTRGE(cond, expr, cmp) \
+ do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrge(expr, llen, cmp); } while (0)
+
+static int expect_ptrge(const void *expr, int llen, const void *cmp)
+{
+ int ret = !(expr >= cmp);
+
+ llen += printf(" = <%p> ", expr);
+ result(llen, ret ? FAIL : OK);
+ return ret;
+}
+
+#define EXPECT_PTRGT(cond, expr, cmp) \
+ do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrgt(expr, llen, cmp); } while (0)
+
+static int expect_ptrgt(const void *expr, int llen, const void *cmp)
+{
+ int ret = !(expr > cmp);
+
+ llen += printf(" = <%p> ", expr);
+ result(llen, ret ? FAIL : OK);
+ return ret;
+}
+
+
+#define EXPECT_PTRLE(cond, expr, cmp) \
+ do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrle(expr, llen, cmp); } while (0)
+
+static int expect_ptrle(const void *expr, int llen, const void *cmp)
+{
+ int ret = !(expr <= cmp);
+
+ llen += printf(" = <%p> ", expr);
+ result(llen, ret ? FAIL : OK);
+ return ret;
+}
+
+
+#define EXPECT_PTRLT(cond, expr, cmp) \
+ do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrlt(expr, llen, cmp); } while (0)
+
+static int expect_ptrlt(const void *expr, int llen, const void *cmp)
+{
+ int ret = !(expr < cmp);
+
+ llen += printf(" = <%p> ", expr);
+ result(llen, ret ? FAIL : OK);
+ return ret;
+}
+
#define EXPECT_PTRER2(cond, expr, expret, experr1, experr2) \
do { if (!(cond)) result(llen, SKIPPED); else ret += expect_ptrerr2(expr, expret, experr1, experr2, llen); } while (0)

--
2.25.1


2023-07-15 18:55:14

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 08/18] tools/nolibc: aarch64: shrink _start with _start_c

move most of the _start operations to _start_c(), include the
stackprotector initialization.

Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/include/nolibc/arch-aarch64.h | 27 ++++-----------------------
1 file changed, 4 insertions(+), 23 deletions(-)

diff --git a/tools/include/nolibc/arch-aarch64.h b/tools/include/nolibc/arch-aarch64.h
index 3c0a5f47b3e8..6c33c46848e3 100644
--- a/tools/include/nolibc/arch-aarch64.h
+++ b/tools/include/nolibc/arch-aarch64.h
@@ -8,6 +8,7 @@
#define _NOLIBC_ARCH_AARCH64_H

#include "compiler.h"
+#include "crt.h"

/* Syscalls for AARCH64 :
* - registers are 64-bit
@@ -143,33 +144,13 @@
_arg1; \
})

-char **environ __attribute__((weak));
-const unsigned long *_auxv __attribute__((weak));
-
/* startup code */
void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
-#ifdef _NOLIBC_STACKPROTECTOR
- "bl __stack_chk_init\n" /* initialize stack protector */
-#endif
- "ldr x0, [sp]\n" /* argc (x0) was in the stack */
- "add x1, sp, 8\n" /* argv (x1) = sp */
- "lsl x2, x0, 3\n" /* envp (x2) = 8*argc ... */
- "add x2, x2, 8\n" /* + 8 (skip null) */
- "add x2, x2, x1\n" /* + argv */
- "adrp x3, environ\n" /* x3 = &environ (high bits) */
- "str x2, [x3, #:lo12:environ]\n" /* store envp into environ */
- "mov x4, x2\n" /* search for auxv (follows NULL after last env) */
- "0:\n"
- "ldr x5, [x4], 8\n" /* x5 = *x4; x4 += 8 */
- "cbnz x5, 0b\n" /* and stop at NULL after last env */
- "adrp x3, _auxv\n" /* x3 = &_auxv (high bits) */
- "str x4, [x3, #:lo12:_auxv]\n" /* store x4 into _auxv */
- "and sp, x1, -16\n" /* sp must be 16-byte aligned in the callee */
- "bl main\n" /* main() returns the status code, we'll exit with it. */
- "mov x8, 93\n" /* NR_exit == 93 */
- "svc #0\n"
+ "mov x0, sp\n" /* save stack pointer to x0, as arg1 of _start_c */
+ "and sp, x0, -16\n" /* sp must be 16-byte aligned in the callee */
+ "bl _start_c\n" /* transfer to c runtime */
);
__builtin_unreachable();
}
--
2.25.1


2023-07-15 18:55:45

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 14/18] tools/nolibc: s390: shrink _start with _start_c

move most of the _start operations to _start_c(), include the
stackprotector initialization.

Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/include/nolibc/arch-s390.h | 36 +++++---------------------------
1 file changed, 5 insertions(+), 31 deletions(-)

diff --git a/tools/include/nolibc/arch-s390.h b/tools/include/nolibc/arch-s390.h
index 3b94ae0cb1d1..5d60fd43f883 100644
--- a/tools/include/nolibc/arch-s390.h
+++ b/tools/include/nolibc/arch-s390.h
@@ -9,6 +9,7 @@
#include <asm/unistd.h>

#include "compiler.h"
+#include "crt.h"

/* Syscalls for s390:
* - registers are 64-bit
@@ -137,41 +138,14 @@
_arg1; \
})

-char **environ __attribute__((weak));
-const unsigned long *_auxv __attribute__((weak));
-
/* startup code */
void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
- "lg %r2,0(%r15)\n" /* argument count */
- "la %r3,8(%r15)\n" /* argument pointers */
-
- "xgr %r0,%r0\n" /* r0 will be our NULL value */
- /* search for envp */
- "lgr %r4,%r3\n" /* start at argv */
- "0:\n"
- "clg %r0,0(%r4)\n" /* entry zero? */
- "la %r4,8(%r4)\n" /* advance pointer */
- "jnz 0b\n" /* no -> test next pointer */
- /* yes -> r4 now contains start of envp */
- "larl %r1,environ\n"
- "stg %r4,0(%r1)\n"
-
- /* search for auxv */
- "lgr %r5,%r4\n" /* start at envp */
- "1:\n"
- "clg %r0,0(%r5)\n" /* entry zero? */
- "la %r5,8(%r5)\n" /* advance pointer */
- "jnz 1b\n" /* no -> test next pointer */
- "larl %r1,_auxv\n" /* yes -> store value in _auxv */
- "stg %r5,0(%r1)\n"
-
- "aghi %r15,-160\n" /* allocate new stackframe */
- "xc 0(8,%r15),0(%r15)\n" /* clear backchain */
- "brasl %r14,main\n" /* ret value of main is arg to exit */
- "lghi %r1,1\n" /* __NR_exit */
- "svc 0\n"
+ "lgr %r2, %r15\n" /* save stack pointer to %r2, as arg1 of _start_c */
+ "aghi %r15, -160\n" /* allocate new stackframe */
+ "xc 0(8,%r15), 0(%r15)\n" /* clear backchain */
+ "brasl %r14, _start_c\n" /* transfer to c runtime */
);
__builtin_unreachable();
}
--
2.25.1


2023-07-15 19:02:46

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 18/18] selftests/nolibc: allow test -include /path/to/nolibc.h

As the head comment of nolibc-test.c shows, it can be built in 3 ways:

$(CC) -nostdlib -include /path/to/nolibc.h => NOLIBC already defined
$(CC) -nostdlib -I/path/to/nolibc/sysroot => _NOLIBC_* guards are present
$(CC) with default libc => NOLIBC* never defined

Only last two of them are tested currently, let's allow test the first one too.

This may help to find issues about using nolibc.h to build programs. it
derives from this change:

commit 3a8039e289a3 ("tools/nolibc: Fix build of stdio.h due to header ordering")

Usage:

// test with sysroot by default
$ make run-user

// test without sysroot, using nolibc.h directly
$ make run-user NOLIBC_SYSROOT=0

Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/testing/selftests/nolibc/Makefile | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile
index b42e67b1a7e2..f42adef87e12 100644
--- a/tools/testing/selftests/nolibc/Makefile
+++ b/tools/testing/selftests/nolibc/Makefile
@@ -126,9 +126,15 @@ sysroot/$(ARCH)/include:
$(Q)$(MAKE) -C ../../../include/nolibc ARCH=$(ARCH) OUTPUT=$(CURDIR)/sysroot/ headers_standalone
$(Q)mv sysroot/sysroot sysroot/$(ARCH)

+ifneq ($(NOLIBC_SYSROOT),0)
nolibc-test: nolibc-test.c sysroot/$(ARCH)/include
$(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \
-nostdlib -static -Isysroot/$(ARCH)/include $< -lgcc
+else
+nolibc-test: nolibc-test.c
+ $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ \
+ -nostdlib -static -include ../../../include/nolibc/nolibc.h $< -lgcc
+endif

libc-test: nolibc-test.c
$(QUIET_CC)$(CC) -o $@ $<
--
2.25.1


2023-07-15 19:05:44

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 16/18] selftests/nolibc: add testcases for startup code

The startup code is critical to get the right argc, argv, envp/environ
and _auxv, let's add a startup test group and the corresponding
testcases.

The "environ" test case is also moved from the stdlib test group to this
new startup test group and it is renamed to "environ_envp".

Since argv0 has been used by many other test cases, let's add testcases
to gurantee it too.

Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/testing/selftests/nolibc/nolibc-test.c | 56 +++++++++++++++++++-
1 file changed, 55 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index 3ff706078fbd..03b1d30f5507 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -15,6 +15,7 @@
#include <string.h>
#ifndef _NOLIBC_STDIO_H
/* standard libcs need more includes */
+#include <sys/auxv.h>
#include <sys/io.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
@@ -47,6 +48,12 @@
/* will be used to test initialization of environ */
static char **test_envp;

+/* will be used to test initialization of argv */
+static char **test_argv;
+
+/* will be used to test initialization of argc */
+static int test_argc;
+
/* will be used by some test cases as readable file, please don't write it */
static const char *argv0;

@@ -561,6 +568,51 @@ static int expect_strne(const char *expr, int llen, const char *cmp)
#define CASE_TEST(name) \
case __LINE__: llen += printf("%d %s", test, #name);

+int run_startup(int min, int max)
+{
+ int test;
+ int ret = 0;
+ /* kernel at least passes HOME and TERM, shell passes more */
+ int env_total = 2;
+ /* checking NULL for argv/argv0, environ and _auxv is not enough, let's compare with sbrk(0) or &end */
+ extern char end;
+ char *brk = sbrk(0) != (void *)-1 ? sbrk(0) : &end;
+ /* differ from nolibc, both glibc and musl have no global _auxv */
+ const unsigned long *test_auxv = (void *)-1;
+#ifdef NOLIBC
+ test_auxv = _auxv;
+#endif
+
+ for (test = min; test >= 0 && test <= max; test++) {
+ int llen = 0; /* line length */
+
+ /* avoid leaving empty lines below, this will insert holes into
+ * test numbers.
+ */
+ switch (test + __LINE__ + 1) {
+ CASE_TEST(argc); EXPECT_GE(1, test_argc, 1); break;
+ CASE_TEST(argv_addr); EXPECT_PTRGT(1, test_argv, brk); break;
+ CASE_TEST(argv_environ); EXPECT_PTRLT(1, test_argv, environ); break;
+ CASE_TEST(argv_total); EXPECT_EQ(1, environ - test_argv - 1, test_argc ?: 1); break;
+ CASE_TEST(argv0_addr); EXPECT_PTRGT(1, argv0, brk); break;
+ CASE_TEST(argv0_str); EXPECT_STRNZ(1, argv0 > brk ? argv0 : NULL); break;
+ CASE_TEST(argv0_len); EXPECT_GE(1, argv0 > brk ? strlen(argv0) : 0, 1); break;
+ CASE_TEST(environ_addr); EXPECT_PTRGT(1, environ, brk); break;
+ CASE_TEST(environ_envp); EXPECT_PTREQ(1, environ, test_envp); break;
+ CASE_TEST(environ_auxv); EXPECT_PTRLT(test_auxv != (void *)-1, environ, test_auxv); break;
+ CASE_TEST(environ_total); EXPECT_GE(test_auxv != (void *)-1, (void *)test_auxv - (void *)environ - 1, env_total); break;
+ CASE_TEST(environ_HOME); EXPECT_PTRNZ(1, getenv("HOME")); break;
+ CASE_TEST(auxv_addr); EXPECT_PTRGT(test_auxv != (void *)-1, test_auxv, brk); break;
+ CASE_TEST(auxv_AT_UID); EXPECT_EQ(1, getauxval(AT_UID), getuid()); break;
+ CASE_TEST(auxv_AT_PAGESZ); EXPECT_GE(1, getauxval(AT_PAGESZ), 4096); break;
+ case __LINE__:
+ return ret; /* must be last */
+ /* note: do not set any defaults so as to permit holes above */
+ }
+ }
+ return ret;
+}
+

/* used by some syscall tests below */
int test_getdents64(const char *dir)
@@ -844,7 +896,6 @@ int run_stdlib(int min, int max)
* test numbers.
*/
switch (test + __LINE__ + 1) {
- CASE_TEST(environ); EXPECT_PTREQ(1, environ, test_envp); break;
CASE_TEST(getenv_TERM); EXPECT_STRNZ(1, getenv("TERM")); break;
CASE_TEST(getenv_blah); EXPECT_STRZR(1, getenv("blah")); break;
CASE_TEST(setcmp_blah_blah); EXPECT_EQ(1, strcmp("blah", "blah"), 0); break;
@@ -1128,6 +1179,7 @@ int prepare(void)
/* This is the definition of known test names, with their functions */
static const struct test test_names[] = {
/* add new tests here */
+ { .name = "startup", .func = run_startup },
{ .name = "syscall", .func = run_syscall },
{ .name = "stdlib", .func = run_stdlib },
{ .name = "vfprintf", .func = run_vfprintf },
@@ -1174,6 +1226,8 @@ int main(int argc, char **argv, char **envp)
char *test;

argv0 = argv[0];
+ test_argc = argc;
+ test_argv = argv;
test_envp = envp;

/* when called as init, it's possible that no console was opened, for
--
2.25.1


2023-07-15 19:16:08

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 17/18] selftests/nolibc: allow run nolibc-test locally

It is able to run nolibc-test directly without qemu-user when the target
machine is the same as the host machine.

Sometimes, the result running locally may help a lot when the qemu-user
package is too old.

When the target machine differs from the host machine, it is also able
to run nolibc-test directly with qemu-user-static + binfmt_misc.

Link: https://lore.kernel.org/lkml/[email protected]/
Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/testing/selftests/nolibc/Makefile | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile
index d31d6cea82e2..b42e67b1a7e2 100644
--- a/tools/testing/selftests/nolibc/Makefile
+++ b/tools/testing/selftests/nolibc/Makefile
@@ -133,10 +133,16 @@ nolibc-test: nolibc-test.c sysroot/$(ARCH)/include
libc-test: nolibc-test.c
$(QUIET_CC)$(CC) -o $@ $<

+# local libc-test
run-libc-test: libc-test
$(Q)./libc-test > "$(CURDIR)/run.out" || :
$(Q)$(REPORT) $(CURDIR)/run.out

+# local nolibc-test
+run-nolibc-test: nolibc-test
+ $(Q)./nolibc-test > "$(CURDIR)/run.out" || :
+ $(Q)$(REPORT) $(CURDIR)/run.out
+
# qemu user-land test
run-user: nolibc-test
$(Q)qemu-$(QEMU_ARCH) ./nolibc-test > "$(CURDIR)/run.out" || :
--
2.25.1


2023-07-15 19:22:45

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 11/18] tools/nolibc: mips: shrink _start with _start_c

move most of the _start operations to _start_c(), include the
stackprotector initialization.

Also clean up the instructions in delayed slots.

Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/include/nolibc/arch-mips.h | 46 ++++++--------------------------
1 file changed, 8 insertions(+), 38 deletions(-)

diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h
index 7242fc9de04f..4ab6fa54beee 100644
--- a/tools/include/nolibc/arch-mips.h
+++ b/tools/include/nolibc/arch-mips.h
@@ -8,6 +8,7 @@
#define _NOLIBC_ARCH_MIPS_H

#include "compiler.h"
+#include "crt.h"

/* Syscalls for MIPS ABI O32 :
* - WARNING! there's always a delayed slot!
@@ -173,50 +174,19 @@
_arg4 ? -_num : _num; \
})

-char **environ __attribute__((weak));
-const unsigned long *_auxv __attribute__((weak));
-
/* startup code, note that it's called __start on MIPS */
void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector __start(void)
{
__asm__ volatile (
- /*".set nomips16\n"*/
".set push\n"
- ".set noreorder\n"
+ ".set noreorder\n"
".option pic0\n"
-#ifdef _NOLIBC_STACKPROTECTOR
- "jal __stack_chk_init\n" /* initialize stack protector */
- "nop\n" /* delayed slot */
-#endif
- /*".ent __start\n"*/
- /*"__start:\n"*/
- "lw $a0,($sp)\n" /* argc was in the stack */
- "addiu $a1, $sp, 4\n" /* argv = sp + 4 */
- "sll $a2, $a0, 2\n" /* a2 = argc * 4 */
- "add $a2, $a2, $a1\n" /* envp = argv + 4*argc ... */
- "addiu $a2, $a2, 4\n" /* ... + 4 */
- "lui $a3, %hi(environ)\n" /* load environ into a3 (hi) */
- "addiu $a3, %lo(environ)\n" /* load environ into a3 (lo) */
- "sw $a2,($a3)\n" /* store envp(a2) into environ */
-
- "move $t0, $a2\n" /* iterate t0 over envp, look for NULL */
- "0:" /* do { */
- "lw $a3, ($t0)\n" /* a3=*(t0); */
- "bne $a3, $0, 0b\n" /* } while (a3); */
- "addiu $t0, $t0, 4\n" /* delayed slot: t0+=4; */
- "lui $a3, %hi(_auxv)\n" /* load _auxv into a3 (hi) */
- "addiu $a3, %lo(_auxv)\n" /* load _auxv into a3 (lo) */
- "sw $t0, ($a3)\n" /* store t0 into _auxv */
-
- "li $t0, -8\n"
- "and $sp, $sp, $t0\n" /* sp must be 8-byte aligned */
- "addiu $sp,$sp,-16\n" /* the callee expects to save a0..a3 there! */
- "jal main\n" /* main() returns the status code, we'll exit with it. */
- "nop\n" /* delayed slot */
- "move $a0, $v0\n" /* retrieve 32-bit exit code from v0 */
- "li $v0, 4001\n" /* NR_exit == 4001 */
- "syscall\n"
- /*".end __start\n"*/
+ "move $a0, $sp\n" /* save stack pointer to $a0, as arg1 of _start_c */
+ "li $t0, -8\n"
+ "and $sp, $sp, $t0\n" /* $sp must be 8-byte aligned */
+ "addiu $sp, $sp, -16\n" /* the callee expects to save a0..a3 there */
+ "jal _start_c\n" /* transfer to c runtime */
+ " nop\n" /* delayed slot */
".set pop\n"
);
__builtin_unreachable();
--
2.25.1


2023-07-15 19:23:29

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 12/18] tools/nolibc: loongarch: shrink _start with _start_c

move most of the _start operations to _start_c(), include the
stackprotector initialization.

Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/include/nolibc/arch-loongarch.h | 44 +++------------------------
1 file changed, 4 insertions(+), 40 deletions(-)

diff --git a/tools/include/nolibc/arch-loongarch.h b/tools/include/nolibc/arch-loongarch.h
index 590155a4e543..bf98f6220195 100644
--- a/tools/include/nolibc/arch-loongarch.h
+++ b/tools/include/nolibc/arch-loongarch.h
@@ -8,6 +8,7 @@
#define _NOLIBC_ARCH_LOONGARCH_H

#include "compiler.h"
+#include "crt.h"

/* Syscalls for LoongArch :
* - stack is 16-byte aligned
@@ -143,26 +144,9 @@
_arg1; \
})

-char **environ __attribute__((weak));
-const unsigned long *_auxv __attribute__((weak));
-
#if __loongarch_grlen == 32
-#define LONGLOG "2"
-#define SZREG "4"
-#define REG_L "ld.w"
-#define LONG_S "st.w"
-#define LONG_ADD "add.w"
-#define LONG_ADDI "addi.w"
-#define LONG_SLL "slli.w"
#define LONG_BSTRINS "bstrins.w"
#else /* __loongarch_grlen == 64 */
-#define LONGLOG "3"
-#define SZREG "8"
-#define REG_L "ld.d"
-#define LONG_S "st.d"
-#define LONG_ADD "add.d"
-#define LONG_ADDI "addi.d"
-#define LONG_SLL "slli.d"
#define LONG_BSTRINS "bstrins.d"
#endif

@@ -170,29 +154,9 @@ const unsigned long *_auxv __attribute__((weak));
void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
-#ifdef _NOLIBC_STACKPROTECTOR
- "bl __stack_chk_init\n" /* initialize stack protector */
-#endif
- REG_L " $a0, $sp, 0\n" /* argc (a0) was in the stack */
- LONG_ADDI " $a1, $sp, "SZREG"\n" /* argv (a1) = sp + SZREG */
- LONG_SLL " $a2, $a0, "LONGLOG"\n" /* envp (a2) = SZREG*argc ... */
- LONG_ADDI " $a2, $a2, "SZREG"\n" /* + SZREG (skip null) */
- LONG_ADD " $a2, $a2, $a1\n" /* + argv */
-
- "move $a3, $a2\n" /* iterate a3 over envp to find auxv (after NULL) */
- "0:\n" /* do { */
- REG_L " $a4, $a3, 0\n" /* a4 = *a3; */
- LONG_ADDI " $a3, $a3, "SZREG"\n" /* a3 += sizeof(void*); */
- "bne $a4, $zero, 0b\n" /* } while (a4); */
- "la.pcrel $a4, _auxv\n" /* a4 = &_auxv */
- LONG_S " $a3, $a4, 0\n" /* store a3 into _auxv */
-
- "la.pcrel $a3, environ\n" /* a3 = &environ */
- LONG_S " $a2, $a3, 0\n" /* store envp(a2) into environ */
- LONG_BSTRINS " $sp, $zero, 3, 0\n" /* sp must be 16-byte aligned */
- "bl main\n" /* main() returns the status code, we'll exit with it. */
- "li.w $a7, 93\n" /* NR_exit == 93 */
- "syscall 0\n"
+ "move $a0, $sp\n" /* save stack pointer to $a0, as arg1 of _start_c */
+ LONG_BSTRINS " $sp, $zero, 3, 0\n" /* $sp must be 16-byte aligned */
+ "bl _start_c\n" /* transfer to c runtime */
);
__builtin_unreachable();
}
--
2.25.1


2023-07-15 19:27:01

by Zhangjin Wu

[permalink] [raw]
Subject: [PATCH v4 13/18] tools/nolibc: riscv: shrink _start with _start_c

move most of the _start operations to _start_c(), include the
stackprotector initialization.

Signed-off-by: Zhangjin Wu <[email protected]>
---
tools/include/nolibc/arch-riscv.h | 44 ++++---------------------------
1 file changed, 5 insertions(+), 39 deletions(-)

diff --git a/tools/include/nolibc/arch-riscv.h b/tools/include/nolibc/arch-riscv.h
index d49f5ecbf815..950cc2283fd7 100644
--- a/tools/include/nolibc/arch-riscv.h
+++ b/tools/include/nolibc/arch-riscv.h
@@ -8,18 +8,7 @@
#define _NOLIBC_ARCH_RISCV_H

#include "compiler.h"
-
-#if __riscv_xlen == 64
-#define PTRLOG "3"
-#define SZREG "8"
-#define REG_L "ld"
-#define REG_S "sd"
-#elif __riscv_xlen == 32
-#define PTRLOG "2"
-#define SZREG "4"
-#define REG_L "lw"
-#define REG_S "sw"
-#endif
+#include "crt.h"

/* Syscalls for RISCV :
* - stack is 16-byte aligned
@@ -153,40 +142,17 @@
_arg1; \
})

-char **environ __attribute__((weak));
-const unsigned long *_auxv __attribute__((weak));
-
/* startup code */
void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
{
__asm__ volatile (
".option push\n"
".option norelax\n"
- "lla gp, __global_pointer$\n"
+ "lla gp, __global_pointer$\n"
".option pop\n"
-#ifdef _NOLIBC_STACKPROTECTOR
- "call __stack_chk_init\n" /* initialize stack protector */
-#endif
- REG_L" a0, 0(sp)\n" /* argc (a0) was in the stack */
- "add a1, sp, "SZREG"\n" /* argv (a1) = sp */
- "slli a2, a0, "PTRLOG"\n" /* envp (a2) = SZREG*argc ... */
- "add a2, a2, "SZREG"\n" /* + SZREG (skip null) */
- "add a2,a2,a1\n" /* + argv */
-
- "add a3, a2, zero\n" /* iterate a3 over envp to find auxv (after NULL) */
- "0:\n" /* do { */
- REG_L" a4, 0(a3)\n" /* a4 = *a3; */
- "add a3, a3, "SZREG"\n" /* a3 += sizeof(void*); */
- "bne a4, zero, 0b\n" /* } while (a4); */
- "lui a4, %hi(_auxv)\n" /* a4 = &_auxv (high bits) */
- REG_S" a3, %lo(_auxv)(a4)\n" /* store a3 into _auxv */
-
- "lui a3, %hi(environ)\n" /* a3 = &environ (high bits) */
- REG_S" a2,%lo(environ)(a3)\n"/* store envp(a2) into environ */
- "andi sp,a1,-16\n" /* sp must be 16-byte aligned */
- "call main\n" /* main() returns the status code, we'll exit with it. */
- "li a7, 93\n" /* NR_exit == 93 */
- "ecall\n"
+ "mv a0, sp\n" /* save stack pointer to a0, as arg1 of _start_c */
+ "andi sp, a0, -16\n" /* sp must be 16-byte aligned */
+ "call _start_c\n" /* transfer to c runtime */
);
__builtin_unreachable();
}
--
2.25.1


2023-07-15 23:09:04

by Willy Tarreau

[permalink] [raw]
Subject: Re: [PATCH v4 00/18] tools/nolibc: shrink arch support

Hi Zhangjin,

On Sun, Jul 16, 2023 at 02:16:36AM +0800, Zhangjin Wu wrote:
> Hi, Willy, Thomas
>
> Thanks very much for your careful review and great suggestions, now, we
> get v4 revision of the arch shrink series [1], it mainly include a new
> fixup for -O0 under gcc < 11.1.0, the stackprotector support for
> _start_c(), new testcases for startup code and two new test targets.
>
> All of the tests passed or skipped (tinyconfig + few options +
> qemu-system) for both -Os and -O0:
(...)

First, good news, it looks OK from the nolibc-test perspective and
by looking at the code, so I merged all this into branch

20230715-nolibc-next-1

Second, bad news, my preinit code doesn't build anymore due to missing
definitions for statx. It's built using the default method which involves
just including nolibc.h (and getting linux includes from the default path).
I could simplify it to this one-liner:

$ printf "int test_stat(const char *p, struct stat *b) { return stat(p,b); }\n" |
gcc -c -o test.o -xc - -nostdlib -include ./sysroot/x86/include/nolibc.h

In file included from ././sysroot/x86/include/nolibc.h:98:0,
from <command-line>:32:
././sysroot/x86/include/sys.h:952:78: warning: 'struct statx' declared inside parameter list will not be visible outside of this definition or declaration
int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf)
^~~~~
././sysroot/x86/include/sys.h:962:74: warning: 'struct statx' declared inside parameter list will not be visible outside of this definition or declaration
int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf)
^~~~~
././sysroot/x86/include/sys.h: In function 'statx':
././sysroot/x86/include/sys.h:964:51: warning: passing argument 5 of 'sys_statx' from incompatible pointer type [-Wincompatible-pointer-types]
return __sysret(sys_statx(fd, path, flags, mask, buf));
^~~
././sysroot/x86/include/sys.h:952:5: note: expected 'struct statx *' but argument is of type 'struct statx *'
int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf)
^~~~~~~~~
././sysroot/x86/include/sys.h: In function 'stat':
././sysroot/x86/include/sys.h:971:15: error: storage size of 'statx' isn't known
struct statx statx;
^~~~~
././sysroot/x86/include/sys.h:974:60: error: 'STATX_BASIC_STATS' undeclared (first use in this function)
ret = __sysret(sys_statx(AT_FDCWD, path, AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx));
^~~~~~~~~~~~~~~~~
././sysroot/x86/include/sys.h:974:60: note: each undeclared identifier is reported only once for each function it appears in

I finally found that it's due to the lack of -Isysroot/x86/include, so
it used to get linux includes from those provided by glibc and these ones
were missing statx since packaged for an older kernel.

I knew that sooner or later I'd have to reinstall this machine but I
can't get out of my head that to date I have yet not been convinced by
the absolute necessity of this modification which is progressively adding
more burden :-/ Time will tell...

Cheers,
Willy

2023-07-16 01:46:49

by Zhangjin Wu

[permalink] [raw]
Subject: Re: [PATCH v4 00/18] tools/nolibc: shrink arch support

Hi, Willy

> Hi Zhangjin,
>
> On Sun, Jul 16, 2023 at 02:16:36AM +0800, Zhangjin Wu wrote:
> > Hi, Willy, Thomas
> >
> > Thanks very much for your careful review and great suggestions, now, we
> > get v4 revision of the arch shrink series [1], it mainly include a new
> > fixup for -O0 under gcc < 11.1.0, the stackprotector support for
> > _start_c(), new testcases for startup code and two new test targets.
> >
> > All of the tests passed or skipped (tinyconfig + few options +
> > qemu-system) for both -Os and -O0:
> (...)
>
> First, good news, it looks OK from the nolibc-test perspective and
> by looking at the code, so I merged all this into branch
>
> 20230715-nolibc-next-1
>

Thanks very much.

> Second, bad news, my preinit code doesn't build anymore due to missing
> definitions for statx. It's built using the default method which involves
> just including nolibc.h (and getting linux includes from the default path).
> I could simplify it to this one-liner:
>
> $ printf "int test_stat(const char *p, struct stat *b) { return stat(p,b); }\n" |
> gcc -c -o test.o -xc - -nostdlib -include ./sysroot/x86/include/nolibc.h
>
> In file included from ././sysroot/x86/include/nolibc.h:98:0,
> from <command-line>:32:
> ././sysroot/x86/include/sys.h:952:78: warning: 'struct statx' declared inside parameter list will not be visible outside of this definition or declaration
> int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf)
> ^~~~~
> ././sysroot/x86/include/sys.h:962:74: warning: 'struct statx' declared inside parameter list will not be visible outside of this definition or declaration
> int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf)
> ^~~~~
> ././sysroot/x86/include/sys.h: In function 'statx':
> ././sysroot/x86/include/sys.h:964:51: warning: passing argument 5 of 'sys_statx' from incompatible pointer type [-Wincompatible-pointer-types]
> return __sysret(sys_statx(fd, path, flags, mask, buf));
> ^~~
> ././sysroot/x86/include/sys.h:952:5: note: expected 'struct statx *' but argument is of type 'struct statx *'
> int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf)
> ^~~~~~~~~
> ././sysroot/x86/include/sys.h: In function 'stat':
> ././sysroot/x86/include/sys.h:971:15: error: storage size of 'statx' isn't known
> struct statx statx;
> ^~~~~
> ././sysroot/x86/include/sys.h:974:60: error: 'STATX_BASIC_STATS' undeclared (first use in this function)
> ret = __sysret(sys_statx(AT_FDCWD, path, AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx));
> ^~~~~~~~~~~~~~~~~
> ././sysroot/x86/include/sys.h:974:60: note: each undeclared identifier is reported only once for each function it appears in
>
> I finally found that it's due to the lack of -Isysroot/x86/include, so
> it used to get linux includes from those provided by glibc and these ones
> were missing statx since packaged for an older kernel.
>

So, your local glibc may be older than 2.28 (The one we mentioned in the
commit message who supports statx)? mine 2.31 glibc is ok:

$ ldd --version
ldd (Ubuntu GLIBC 2.31-0ubuntu9.2) 2.31
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.

// anyone of the following commands work
$ echo -e "int test_stat(const char *p, struct stat *b) { return stat(p,b); }\n" | gcc -c -o test.o -xc - -nostdlib -include sysroot/x86/include/nolibc.h
$ echo -e "int test_stat(const char *p, struct stat *b) { return stat(p,b); }\n" | gcc -c -o test.o -xc - -nostdlib -Isysroot/x86/include -include ../../../include/nolibc/nolibc.h
$ echo -e "int test_stat(const char *p, struct stat *b) { return stat(p,b); }\n" | gcc -c -o test.o -xc - -nostdlib -include ../../../include/nolibc/nolibc.h

For older Linux systems without a newer libc may really require the
installation of the linux sysroot (linux/uapi).

In Ubuntu 20.04, the "struct statx" is provided by the linux-libc-dev
package:

$ dpkg -S /usr/include/linux/
linux-libc-dev:amd64: /usr/include/linux
$ dpkg -l | grep linux-libc-dev
ii linux-libc-dev:amd64 5.4.0-88.99 amd64 Linux Kernel Headers for development
ii linux-libc-dev-arm64-cross 5.4.0-59.65cross1 all Linux Kernel Headers for development (for cross-compiling)
ii linux-libc-dev-armel-cross 5.4.0-59.65cross1 all Linux Kernel Headers for development (for cross-compiling)
ii linux-libc-dev-i386-cross 5.4.0-59.65cross1 all Linux Kernel Headers for development (for cross-compiling)
ii linux-libc-dev-riscv64-cross 5.4.0-21.25cross1 all Linux Kernel Headers for development (for cross-compiling)
$ grep "struct statx" -ur /usr/include/linux/
/usr/include/linux/stat.h: * Timestamp structure for the timestamps in struct statx.
/usr/include/linux/stat.h:struct statx_timestamp {
/usr/include/linux/stat.h:struct statx {
/usr/include/linux/stat.h: struct statx_timestamp stx_atime; /* Last access time */
/usr/include/linux/stat.h: struct statx_timestamp stx_btime; /* File creation time */
/usr/include/linux/stat.h: struct statx_timestamp stx_ctime; /* Last attribute change time */
/usr/include/linux/stat.h: struct statx_timestamp stx_mtime; /* Last data modification time */
/usr/include/linux/stat.h: * Query request/result mask for statx() and struct statx::stx_mask.
/usr/include/linux/stat.h:#define STATX__RESERVED 0x80000000U /* Reserved for future struct statx expansion */

This may be relative to glibc version, it is a dep of libc package:

Package: libc6-dev
Source: glibc
Version: 2.36-9
Architecture: amd64
Maintainer: GNU Libc Maintainers <[email protected]>
Installed-Size: 11954
Depends: libc6 (= 2.36-9), libc-dev-bin (= 2.36-9), linux-libc-dev, libcrypt-dev, libnsl-dev, rpcsvc-proto

> I knew that sooner or later I'd have to reinstall this machine but I
> can't get out of my head that to date I have yet not been convinced by
> the absolute necessity of this modification which is progressively adding
> more burden :-/ Time will tell...
>

This may also let us think about the removing of <linux/xxx.h> from our
nolibc headers? just like musl does ;-)

$ grep "include <linux" -ur ../../../include/nolibc/
../../../include/nolibc/stdlib.h:#include <linux/auxvec.h>
../../../include/nolibc/sys.h:#include <linux/fs.h>
../../../include/nolibc/sys.h:#include <linux/loop.h>
../../../include/nolibc/sys.h:#include <linux/time.h>
../../../include/nolibc/sys.h:#include <linux/auxvec.h>
../../../include/nolibc/sys.h:#include <linux/fcntl.h> /* for O_* and AT_* */
../../../include/nolibc/sys.h:#include <linux/stat.h> /* for statx() */
../../../include/nolibc/sys.h:#include <linux/prctl.h>
../../../include/nolibc/types.h:#include <linux/mman.h>
../../../include/nolibc/types.h:#include <linux/reboot.h> /* for LINUX_REBOOT_* */
../../../include/nolibc/types.h:#include <linux/stat.h>
../../../include/nolibc/types.h:#include <linux/time.h>

If simply put all of them to types.h, it may be too much, a new "sys/"
directory with almost the same Linux type files may be required, but as
an in-kernel libc, this duplication may be a "big" issue too, so, adding
minimal required macros and structs in types.h may be another choice.

After removing the duplicated ones, it is not that much:

../../../include/nolibc/stdlib.h:#include <linux/auxvec.h>
../../../include/nolibc/sys.h:#include <linux/fs.h>
../../../include/nolibc/sys.h:#include <linux/loop.h>
../../../include/nolibc/sys.h:#include <linux/time.h>
../../../include/nolibc/sys.h:#include <linux/fcntl.h> /* for O_* and AT_* */
../../../include/nolibc/sys.h:#include <linux/stat.h> /* for statx() */
../../../include/nolibc/sys.h:#include <linux/prctl.h>
../../../include/nolibc/types.h:#include <linux/mman.h>
../../../include/nolibc/types.h:#include <linux/reboot.h> /* for LINUX_REBOOT_* */

The required new macros and structs may be around 100-300 lines? but it may
help to avoid the installation of sysroot completely and also avoid the cross
including the linux-libc-dev package used by glibc?

Best regards,
Zhangjin

> Cheers,
> Willy

2023-07-16 07:07:31

by Willy Tarreau

[permalink] [raw]
Subject: Re: [PATCH v4 00/18] tools/nolibc: shrink arch support

On Sun, Jul 16, 2023 at 09:17:44AM +0800, Zhangjin Wu wrote:
> > I finally found that it's due to the lack of -Isysroot/x86/include, so
> > it used to get linux includes from those provided by glibc and these ones
> > were missing statx since packaged for an older kernel.
> >
>
> So, your local glibc may be older than 2.28 (The one we mentioned in the
> commit message who supports statx)? mine 2.31 glibc is ok:

Oh definitely! It's a 2.23, and on another machine I'm having a 2.27
on an ubuntu 18 but it was built against a more recent kernel so its
linux/stat.h has the required entries, and on another one I'm having
a 2.17 which was built against a 3.10 kernel.

> For older Linux systems without a newer libc may really require the
> installation of the linux sysroot (linux/uapi).

Yes. My point was that it wasn't very hard to already spot breakage
on existing code built on existing setups.

> > I knew that sooner or later I'd have to reinstall this machine but I
> > can't get out of my head that to date I have yet not been convinced by
> > the absolute necessity of this modification which is progressively adding
> > more burden :-/ Time will tell...
> >
>
> This may also let us think about the removing of <linux/xxx.h> from our
> nolibc headers? just like musl does ;-)
>
> $ grep "include <linux" -ur ../../../include/nolibc/
> ../../../include/nolibc/stdlib.h:#include <linux/auxvec.h>
> ../../../include/nolibc/sys.h:#include <linux/fs.h>
> ../../../include/nolibc/sys.h:#include <linux/loop.h>
> ../../../include/nolibc/sys.h:#include <linux/time.h>
> ../../../include/nolibc/sys.h:#include <linux/auxvec.h>
> ../../../include/nolibc/sys.h:#include <linux/fcntl.h> /* for O_* and AT_* */
> ../../../include/nolibc/sys.h:#include <linux/stat.h> /* for statx() */
> ../../../include/nolibc/sys.h:#include <linux/prctl.h>
> ../../../include/nolibc/types.h:#include <linux/mman.h>
> ../../../include/nolibc/types.h:#include <linux/reboot.h> /* for LINUX_REBOOT_* */
> ../../../include/nolibc/types.h:#include <linux/stat.h>
> ../../../include/nolibc/types.h:#include <linux/time.h>
>
> If simply put all of them to types.h, it may be too much, a new "sys/"
> directory with almost the same Linux type files may be required, but as
> an in-kernel libc, this duplication may be a "big" issue too, so, adding
> minimal required macros and structs in types.h may be another choice.
(...)
> The required new macros and structs may be around 100-300 lines? but it may
> help to avoid the installation of sysroot completely and also avoid the cross
> including the linux-libc-dev package used by glibc?

No, really, that's what we used to do previously. If you remember we
recently removed lots of structs and defines from various files because
they used to regularly conflict with linux/foo.h (that we can't prevent
users from including), while not always being 100% up-to-date. It's
particularly annoying when there are typedefs for example because it's
difficult to detect them, and if you redefine them you end up with build
errors. We should only keep that for absolute necessity. In fact, maybe
we could have these few ones precisely for statx, right after including
linux/stat.h (which is supposed to provide them):

#ifndef STATX_BASIC_STATS
/* pre-4.10 linux uapi headers present, missing statx that we need */
#define STATX_BASIC_STATS xxx
struct statx {
...
};
#endif

I may give this a try to see if it's sufficient to fix the build on
these machines. But it's not critical anyway. I might try once I'm
bored of seeing build failures.

Cheers,
Willy