* [PATCH 0/3] tools/nolibc: LTO compatibility
@ 2024-08-10 10:54 Thomas Weißschuh
2024-08-10 10:54 ` [PATCH 1/3] tools/nolibc: crt: mark _start_c() as used Thomas Weißschuh
` (2 more replies)
0 siblings, 3 replies; 15+ messages in thread
From: Thomas Weißschuh @ 2024-08-10 10:54 UTC (permalink / raw)
To: Willy Tarreau; +Cc: Ammar Faizi, linux-kernel, Thomas Weißschuh
A few tiny bugfixes and refactoring to provide compatibility with GCCs
and clangs -flto.
$ CFLAGS_EXTRA=-flto ./run-tests.sh -m user -l
i386: 195 test(s): 193 passed, 2 skipped, 0 failed => status: warning
x86_64: 195 test(s): 193 passed, 2 skipped, 0 failed => status: warning
arm64: 195 test(s): 193 passed, 2 skipped, 0 failed => status: warning
arm: 195 test(s): 193 passed, 2 skipped, 0 failed => status: warning
mips32le: 195 test(s): 192 passed, 3 skipped, 0 failed => status: warning
mips32be: 195 test(s): 192 passed, 3 skipped, 0 failed => status: warning
ppc: 195 test(s): 192 passed, 3 skipped, 0 failed => status: warning
ppc64: 195 test(s): 192 passed, 3 skipped, 0 failed => status: warning
ppc64le: 195 test(s): 192 passed, 3 skipped, 0 failed => status: warning
riscv: 195 test(s): 192 passed, 3 skipped, 0 failed => status: warning
s390: 195 test(s): 192 passed, 3 skipped, 0 failed => status: warning
loongarch: 195 test(s): 192 passed, 3 skipped, 0 failed => status: warning
$ CFLAGS_EXTRA=-flto ./run-tests.sh -m user
i386: 195 test(s): 191 passed, 2 skipped, 2 failed => status: failure
x86_64: 195 test(s): 191 passed, 2 skipped, 2 failed => status: failure
arm64: 195 test(s): 191 passed, 2 skipped, 2 failed => status: failure
arm: 195 test(s): 191 passed, 2 skipped, 2 failed => status: failure
mips32le: 195 test(s): 190 passed, 3 skipped, 2 failed => status: failure
mips32be: 195 test(s): 190 passed, 3 skipped, 2 failed => status: failure
ppc: 195 test(s): 191 passed, 2 skipped, 2 failed => status: failure
ppc64: 195 test(s): 191 passed, 2 skipped, 2 failed => status: failure
ppc64le: 195 test(s): 191 passed, 2 skipped, 2 failed => status: failure
riscv: 195 test(s): 191 passed, 2 skipped, 2 failed => status: failure
s390: 195 test(s): 190 passed, 3 skipped, 2 failed => status: failure
loongarch: 195 test(s): 190 passed, 3 skipped, 2 failed => status: failure
Note that on GCC two tests always fail, as with -fLTO the constructor
order is inverted, for which nolibc-test contains two testcases.
See [0].
This series depends on the nolibc LLVM support.
[0] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103080
[1] https://lore.kernel.org/lkml/20240807-nolibc-llvm-v2-0-c20f2f5fc7c2@weissschuh.net/
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
Thomas Weißschuh (3):
tools/nolibc: crt: mark _start_c() as used
tools/nolibc: stackprotector: mark implicitly used symbols as used
tools/nolibc: x86_64: wrap asm functions in functions
tools/include/nolibc/arch-x86_64.h | 80 +++++++++++++++++++----------------
tools/include/nolibc/crt.h | 2 +-
tools/include/nolibc/stackprotector.h | 4 +-
3 files changed, 47 insertions(+), 39 deletions(-)
---
base-commit: 6164f3d0f577a2ab82b8235129fd20b2142e03b1
change-id: 20240728-nolibc-lto-331813b72a0b
Best regards,
--
Thomas Weißschuh <linux@weissschuh.net>
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH 1/3] tools/nolibc: crt: mark _start_c() as used 2024-08-10 10:54 [PATCH 0/3] tools/nolibc: LTO compatibility Thomas Weißschuh @ 2024-08-10 10:54 ` Thomas Weißschuh 2024-08-10 10:54 ` [PATCH 2/3] tools/nolibc: stackprotector: mark implicitly used symbols " Thomas Weißschuh 2024-08-10 10:54 ` [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions Thomas Weißschuh 2 siblings, 0 replies; 15+ messages in thread From: Thomas Weißschuh @ 2024-08-10 10:54 UTC (permalink / raw) To: Willy Tarreau; +Cc: Ammar Faizi, linux-kernel, Thomas Weißschuh During LTO the reference from the asm startup code to the _start_c() function is not visible and _start_c() is removed. This will then lead to errors during linking. As _start_c() is indeed always used, mark it as such. Signed-off-by: Thomas Weißschuh <linux@weissschuh.net> --- tools/include/nolibc/crt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h index 43b551468c2a..161557e6650d 100644 --- a/tools/include/nolibc/crt.h +++ b/tools/include/nolibc/crt.h @@ -22,7 +22,7 @@ extern void (*const __init_array_end[])(void) __attribute__((weak)); extern void (*const __fini_array_start[])(void) __attribute__((weak)); extern void (*const __fini_array_end[])(void) __attribute__((weak)); -__attribute__((weak)) +__attribute__((weak,used)) void _start_c(long *sp) { long argc; -- 2.46.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 2/3] tools/nolibc: stackprotector: mark implicitly used symbols as used 2024-08-10 10:54 [PATCH 0/3] tools/nolibc: LTO compatibility Thomas Weißschuh 2024-08-10 10:54 ` [PATCH 1/3] tools/nolibc: crt: mark _start_c() as used Thomas Weißschuh @ 2024-08-10 10:54 ` Thomas Weißschuh 2024-08-10 10:54 ` [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions Thomas Weißschuh 2 siblings, 0 replies; 15+ messages in thread From: Thomas Weißschuh @ 2024-08-10 10:54 UTC (permalink / raw) To: Willy Tarreau; +Cc: Ammar Faizi, linux-kernel, Thomas Weißschuh During LTO the references from the compiler-generated prologue and epilogues to the stack protector symbols are not visible and the symbols are removed. This will then lead to errors during linking. As those symbols are already #ifdeffed-out if unused mark them as "used" to prevent their removal. Signed-off-by: Thomas Weißschuh <linux@weissschuh.net> --- tools/include/nolibc/stackprotector.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/include/nolibc/stackprotector.h b/tools/include/nolibc/stackprotector.h index 13f1d0e60387..1d0d5259ec41 100644 --- a/tools/include/nolibc/stackprotector.h +++ b/tools/include/nolibc/stackprotector.h @@ -18,7 +18,7 @@ * triggering stack protector errors themselves */ -__attribute__((weak,noreturn,section(".text.nolibc_stack_chk"))) +__attribute__((weak,used,noreturn,section(".text.nolibc_stack_chk"))) void __stack_chk_fail(void) { pid_t pid; @@ -34,7 +34,7 @@ void __stack_chk_fail_local(void) __stack_chk_fail(); } -__attribute__((weak,section(".data.nolibc_stack_chk"))) +__attribute__((weak,used,section(".data.nolibc_stack_chk"))) uintptr_t __stack_chk_guard; static __no_stack_protector void __stack_chk_init(void) -- 2.46.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions 2024-08-10 10:54 [PATCH 0/3] tools/nolibc: LTO compatibility Thomas Weißschuh 2024-08-10 10:54 ` [PATCH 1/3] tools/nolibc: crt: mark _start_c() as used Thomas Weißschuh 2024-08-10 10:54 ` [PATCH 2/3] tools/nolibc: stackprotector: mark implicitly used symbols " Thomas Weißschuh @ 2024-08-10 10:54 ` Thomas Weißschuh 2024-08-10 12:12 ` Ammar Faizi 2 siblings, 1 reply; 15+ messages in thread From: Thomas Weißschuh @ 2024-08-10 10:54 UTC (permalink / raw) To: Willy Tarreau; +Cc: Ammar Faizi, linux-kernel, Thomas Weißschuh The bare asm usage does not work well together with LTO. It leads to errors: /tmp/ccIHTYT6.s: Assembler messages: /tmp/ccIHTYT6.s:36: Error: symbol `memmove' is already defined /tmp/ccIHTYT6.s:37: Error: symbol `memcpy' is already defined /tmp/ccIHTYT6.s:46: Error: symbol `.Lbackward_copy' is already defined /tmp/ccIHTYT6.s:54: Error: symbol `memset' is already defined Wrap the asm in naked functions, which leads to the same object code but avoids the errors. Signed-off-by: Thomas Weißschuh <linux@weissschuh.net> --- tools/include/nolibc/arch-x86_64.h | 80 +++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/tools/include/nolibc/arch-x86_64.h b/tools/include/nolibc/arch-x86_64.h index 3c3b703d9b0c..efbea173fb74 100644 --- a/tools/include/nolibc/arch-x86_64.h +++ b/tools/include/nolibc/arch-x86_64.h @@ -174,45 +174,53 @@ void __attribute__((weak, noreturn)) __nolibc_naked __no_stack_protector _start( } #define NOLIBC_ARCH_HAS_MEMMOVE -void *memmove(void *dst, const void *src, size_t len); +__attribute__((weak,unused,section(".text.nolibc_memmove"))) +__nolibc_naked __no_stack_protector +void *memmove(void *dst __attribute__((unused)), + const void *src __attribute__((unused)), + size_t len __attribute__((unused))) +{ + __asm__ volatile ( + "movq %rdx, %rcx\n\t" + "movq %rdi, %rax\n\t" + "movq %rdi, %rdx\n\t" + "subq %rsi, %rdx\n\t" + "cmpq %rcx, %rdx\n\t" + "jb .Lbackward_copy\n\t" + "rep movsb\n\t" + "retq\n" + ".Lbackward_copy:" + "leaq -1(%rdi, %rcx, 1), %rdi\n\t" + "leaq -1(%rsi, %rcx, 1), %rsi\n\t" + "std\n\t" + "rep movsb\n\t" + "cld\n\t" + "retq\n" + ); + __nolibc_naked_epilogue(); +} #define NOLIBC_ARCH_HAS_MEMCPY -void *memcpy(void *dst, const void *src, size_t len); +static __inline__ void *memcpy(void *dst, const void *src, size_t len) +{ + return memmove(dst, src, len); +} #define NOLIBC_ARCH_HAS_MEMSET -void *memset(void *dst, int c, size_t len); - -__asm__ ( -".section .text.nolibc_memmove_memcpy\n" -".weak memmove\n" -".weak memcpy\n" -"memmove:\n" -"memcpy:\n" - "movq %rdx, %rcx\n\t" - "movq %rdi, %rax\n\t" - "movq %rdi, %rdx\n\t" - "subq %rsi, %rdx\n\t" - "cmpq %rcx, %rdx\n\t" - "jb .Lbackward_copy\n\t" - "rep movsb\n\t" - "retq\n" -".Lbackward_copy:" - "leaq -1(%rdi, %rcx, 1), %rdi\n\t" - "leaq -1(%rsi, %rcx, 1), %rsi\n\t" - "std\n\t" - "rep movsb\n\t" - "cld\n\t" - "retq\n" - -".section .text.nolibc_memset\n" -".weak memset\n" -"memset:\n" - "xchgl %eax, %esi\n\t" - "movq %rdx, %rcx\n\t" - "pushq %rdi\n\t" - "rep stosb\n\t" - "popq %rax\n\t" - "retq\n" -); +__attribute__((weak,unused,section(".text.nolibc_memset"))) +__nolibc_naked __no_stack_protector +void *memset(void *dst __attribute__((unused)), int c __attribute__((unused)), + size_t len __attribute__((unused))) +{ + __asm__ volatile ( + "xchgl %eax, %esi\n\t" + "movq %rdx, %rcx\n\t" + "pushq %rdi\n\t" + "rep stosb\n\t" + "popq %rax\n\t" + "retq\n" + ); + __nolibc_naked_epilogue(); +} #endif /* _NOLIBC_ARCH_X86_64_H */ -- 2.46.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions 2024-08-10 10:54 ` [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions Thomas Weißschuh @ 2024-08-10 12:12 ` Ammar Faizi 2024-08-10 12:37 ` Thomas Weißschuh 0 siblings, 1 reply; 15+ messages in thread From: Ammar Faizi @ 2024-08-10 12:12 UTC (permalink / raw) To: Thomas Weißschuh; +Cc: Willy Tarreau, linux-kernel On Sat, Aug 10, 2024 at 12:54:46PM +0200, Thomas Weißschuh wrote: > +__attribute__((weak,unused,section(".text.nolibc_memmove"))) > +__nolibc_naked __no_stack_protector > +void *memmove(void *dst __attribute__((unused)), > + const void *src __attribute__((unused)), > + size_t len __attribute__((unused))) > +{ > + __asm__ volatile ( > + "movq %rdx, %rcx\n\t" > + "movq %rdi, %rax\n\t" > + "movq %rdi, %rdx\n\t" > + "subq %rsi, %rdx\n\t" > + "cmpq %rcx, %rdx\n\t" > + "jb .Lbackward_copy\n\t" > + "rep movsb\n\t" > + "retq\n" > + ".Lbackward_copy:" > + "leaq -1(%rdi, %rcx, 1), %rdi\n\t" > + "leaq -1(%rsi, %rcx, 1), %rsi\n\t" > + "std\n\t" > + "rep movsb\n\t" > + "cld\n\t" > + "retq\n" > + ); > + __nolibc_naked_epilogue(); > +} NAK for this patch. This approach appears highly dangerous, particularly when the compiler inlines the call. When using inline assembly within a function, it's crucial to define proper constraints and a clobber list to ensure the arguments are correctly bound to the inline assembly. Moreover, as it stands, there is no indication to the compiler that the inline assembly modifies registers such as %rax, %rdi, %rsi, %rdx, %rcx, or "memory", which could lead to unpredictable behavior. Unfortunately, I can't spend more time on this right now as I'm currently traveling. I'll get back to it later when I'm in transit. -- Ammar Faizi ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions 2024-08-10 12:12 ` Ammar Faizi @ 2024-08-10 12:37 ` Thomas Weißschuh 2024-08-10 14:35 ` Willy Tarreau 0 siblings, 1 reply; 15+ messages in thread From: Thomas Weißschuh @ 2024-08-10 12:37 UTC (permalink / raw) To: Ammar Faizi; +Cc: Willy Tarreau, linux-kernel On 2024-08-10 19:12:25+0000, Ammar Faizi wrote: > On Sat, Aug 10, 2024 at 12:54:46PM +0200, Thomas Weißschuh wrote: > > +__attribute__((weak,unused,section(".text.nolibc_memmove"))) > > +__nolibc_naked __no_stack_protector > > +void *memmove(void *dst __attribute__((unused)), > > + const void *src __attribute__((unused)), > > + size_t len __attribute__((unused))) > > +{ > > + __asm__ volatile ( > > + "movq %rdx, %rcx\n\t" > > + "movq %rdi, %rax\n\t" > > + "movq %rdi, %rdx\n\t" > > + "subq %rsi, %rdx\n\t" > > + "cmpq %rcx, %rdx\n\t" > > + "jb .Lbackward_copy\n\t" > > + "rep movsb\n\t" > > + "retq\n" > > + ".Lbackward_copy:" > > + "leaq -1(%rdi, %rcx, 1), %rdi\n\t" > > + "leaq -1(%rsi, %rcx, 1), %rsi\n\t" > > + "std\n\t" > > + "rep movsb\n\t" > > + "cld\n\t" > > + "retq\n" > > + ); > > + __nolibc_naked_epilogue(); > > +} > > NAK for this patch. Thanks for the feedback! (I'm not an assembler programmer, so regard my notes with a grain of salt) > This approach appears highly dangerous, particularly when the compiler > inlines the call. When using inline assembly within a function, it's > crucial to define proper constraints and a clobber list to ensure the > arguments are correctly bound to the inline assembly. Aren't the constraints a feature of Extended Asm? This is a Basic Asm block. Indeed naked functions only support Basic Asm, so there is no way to explicitly bind arguments to their registers. Looking at the object code for various on both gcc and clang show always the same object code. (Although GCC adds a "ud2" after the "ret") > Moreover, as it stands, there is no indication to the compiler that the > inline assembly modifies registers such as %rax, %rdi, %rsi, %rdx, %rcx, > or "memory", which could lead to unpredictable behavior. > Unfortunately, I can't spend more time on this right now as I'm > currently traveling. I'll get back to it later when I'm in transit. There is no urgency on this, I'll wait on your further feedback. Thanks again, Thomas ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions 2024-08-10 12:37 ` Thomas Weißschuh @ 2024-08-10 14:35 ` Willy Tarreau 2024-08-10 16:04 ` Thomas Weißschuh 0 siblings, 1 reply; 15+ messages in thread From: Willy Tarreau @ 2024-08-10 14:35 UTC (permalink / raw) To: Thomas Weißschuh; +Cc: Ammar Faizi, linux-kernel Hi Thomas, On Sat, Aug 10, 2024 at 02:37:19PM +0200, Thomas Weißschuh wrote: > On 2024-08-10 19:12:25+0000, Ammar Faizi wrote: > > On Sat, Aug 10, 2024 at 12:54:46PM +0200, Thomas Weißschuh wrote: > > > +__attribute__((weak,unused,section(".text.nolibc_memmove"))) > > > +__nolibc_naked __no_stack_protector > > > +void *memmove(void *dst __attribute__((unused)), > > > + const void *src __attribute__((unused)), > > > + size_t len __attribute__((unused))) > > > +{ > > > + __asm__ volatile ( > > > + "movq %rdx, %rcx\n\t" > > > + "movq %rdi, %rax\n\t" > > > + "movq %rdi, %rdx\n\t" > > > + "subq %rsi, %rdx\n\t" > > > + "cmpq %rcx, %rdx\n\t" > > > + "jb .Lbackward_copy\n\t" > > > + "rep movsb\n\t" > > > + "retq\n" > > > + ".Lbackward_copy:" > > > + "leaq -1(%rdi, %rcx, 1), %rdi\n\t" > > > + "leaq -1(%rsi, %rcx, 1), %rsi\n\t" > > > + "std\n\t" > > > + "rep movsb\n\t" > > > + "cld\n\t" > > > + "retq\n" > > > + ); > > > + __nolibc_naked_epilogue(); > > > +} > > > > NAK for this patch. > > Thanks for the feedback! > > (I'm not an assembler programmer, so regard my notes with a grain of salt) > > > This approach appears highly dangerous, particularly when the compiler > > inlines the call. When using inline assembly within a function, it's > > crucial to define proper constraints and a clobber list to ensure the > > arguments are correctly bound to the inline assembly. > > Aren't the constraints a feature of Extended Asm? > This is a Basic Asm block. > Indeed naked functions only support Basic Asm, so there is no way to > explicitly bind arguments to their registers. That's indeed what is said in GNU docs, but a quick test with gcc 9 and 11 shows me that both accept both naked and extended asm. However clang doesn't seem happy about it. The problem here is dual: - first, the naked attribute can be emulated if not supported by the compiler and we'll only have optimize(-Os,-fomit-frame-pointer), and in this case the compiler does not respect well the registers (I'm seeing bad code being emitted in callers if I mark the function static for example). - second, nothing prevents the compiler from inlining that function and in this case, as Ammar says, we have no control over what registers arguments will be placed into since the main purpose of inlining precisely is to build optimal code that limits register moves. However, in my tests, it appears that when marked naked, the compiler never inlines it and even emits a warning if I try to mark it inline, saying it was already noinline. So maybe naked implies noinline. In any case, depending on the availability of naked, we have two clearly different layouts to deal with :-/ We could imagine not marking it naked and keeping the optimize(Os...) stuff only, then using extended asm like in other functions maybe. Otherwise this could require two versions, which is less fun. > Looking at the object code for various on both gcc and clang show always > the same object code. > (Although GCC adds a "ud2" after the "ret") It *seems* so as well for me but in the not-really-naked case, you really have zero control over it. Also one thing it does to me in the not-naked-case is that registers are not saved by the caller and are clobbered by the asm statement: void *memmove2(void *dst __attribute__((unused)), void *src __attribute__((unused)), size_t len __attribute__((unused))) { memmove(dst, src, len); memmove(src, dst, len); return 0; } Gives me this with the naked attribute: 0000000000000025 <memmove2>: 25: 55 push %rbp 26: 48 89 f5 mov %rsi,%rbp 29: 50 push %rax 2a: 48 89 14 24 mov %rdx,(%rsp) 2e: e8 00 00 00 00 callq 33 <memmove2+0xe> 33: 48 8b 14 24 mov (%rsp),%rdx 37: 48 89 ef mov %rbp,%rdi 3a: 48 89 c6 mov %rax,%rsi 3d: e8 00 00 00 00 callq 42 <memmove2+0x1d> 42: 31 c0 xor %eax,%eax 44: 5a pop %rdx 45: 5d pop %rbp 46: c3 retq But the alternate form (optimize(-Os...)): 0000000000000024 <memmove2>: 24: 49 89 f0 mov %rsi,%r8 27: e8 00 00 00 00 callq 2c <memmove2+0x8> 2c: 48 89 fe mov %rdi,%rsi 2f: 4c 89 c7 mov %r8,%rdi 32: e8 00 00 00 00 callq 37 <memmove2+0x13> 37: 31 c0 xor %eax,%eax 39: c3 retq See how rdi and rdx were expected to be preserved after the first call but were not? This was with gcc-9.5 (which supports naked but it's for illustration purposes of the risk of leaving unconstrained asm like this). I also managed to get clang to complain about the .Lbackward_copy label being already defined, but I don't know how I managed to do it. I think we should not leave it as a global label like this and instead just use the regular numbered labels if the asm is inlined. Also I'm wondering why there are errors about memcpy and memmove being already defined with -flto, because these ones are marked "weak". Maybe we need to add something else, that gcc emits with the functions when using lto ? Just my two cents, Willy ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions 2024-08-10 14:35 ` Willy Tarreau @ 2024-08-10 16:04 ` Thomas Weißschuh 2024-08-10 16:45 ` Thomas Weißschuh 2024-08-10 19:16 ` Ammar Faizi 0 siblings, 2 replies; 15+ messages in thread From: Thomas Weißschuh @ 2024-08-10 16:04 UTC (permalink / raw) To: Willy Tarreau; +Cc: Ammar Faizi, linux-kernel On 2024-08-10 16:35:56+0000, Willy Tarreau wrote: > On Sat, Aug 10, 2024 at 02:37:19PM +0200, Thomas Weißschuh wrote: > > On 2024-08-10 19:12:25+0000, Ammar Faizi wrote: > > > On Sat, Aug 10, 2024 at 12:54:46PM +0200, Thomas Weißschuh wrote: > > > > +__attribute__((weak,unused,section(".text.nolibc_memmove"))) > > > > +__nolibc_naked __no_stack_protector > > > > +void *memmove(void *dst __attribute__((unused)), > > > > + const void *src __attribute__((unused)), > > > > + size_t len __attribute__((unused))) > > > > +{ > > > > + __asm__ volatile ( > > > > + "movq %rdx, %rcx\n\t" > > > > + "movq %rdi, %rax\n\t" > > > > + "movq %rdi, %rdx\n\t" > > > > + "subq %rsi, %rdx\n\t" > > > > + "cmpq %rcx, %rdx\n\t" > > > > + "jb .Lbackward_copy\n\t" > > > > + "rep movsb\n\t" > > > > + "retq\n" > > > > + ".Lbackward_copy:" > > > > + "leaq -1(%rdi, %rcx, 1), %rdi\n\t" > > > > + "leaq -1(%rsi, %rcx, 1), %rsi\n\t" > > > > + "std\n\t" > > > > + "rep movsb\n\t" > > > > + "cld\n\t" > > > > + "retq\n" > > > > + ); > > > > + __nolibc_naked_epilogue(); > > > > +} > > > > > > NAK for this patch. > > > > Thanks for the feedback! > > > > (I'm not an assembler programmer, so regard my notes with a grain of salt) > > > > > This approach appears highly dangerous, particularly when the compiler > > > inlines the call. When using inline assembly within a function, it's > > > crucial to define proper constraints and a clobber list to ensure the > > > arguments are correctly bound to the inline assembly. > > > > Aren't the constraints a feature of Extended Asm? > > This is a Basic Asm block. > > Indeed naked functions only support Basic Asm, so there is no way to > > explicitly bind arguments to their registers. > > That's indeed what is said in GNU docs, but a quick test with gcc 9 and 11 > shows me that both accept both naked and extended asm. However clang doesn't > seem happy about it. > > The problem here is dual: > - first, the naked attribute can be emulated if not supported by the > compiler and we'll only have optimize(-Os,-fomit-frame-pointer), and > in this case the compiler does not respect well the registers (I'm > seeing bad code being emitted in callers if I mark the function > static for example). Ack. Would it help to mark the function as non-inlineable? > - second, nothing prevents the compiler from inlining that function > and in this case, as Ammar says, we have no control over what > registers arguments will be placed into since the main purpose of > inlining precisely is to build optimal code that limits register > moves. However, in my tests, it appears that when marked naked, > the compiler never inlines it and even emits a warning if I try > to mark it inline, saying it was already noinline. So maybe naked > implies noinline. I did not manage yet to get it inlined. With __attribute__((always_inline)) gcc even gives: sysroot/x86_64/include/arch.h:214:1: error: ignoring attribute 'always_inline' because it conflicts with attribute 'noinline' [-Werror=attributes] > In any case, depending on the availability of naked, we have two clearly > different layouts to deal with :-/ Indeed... > We could imagine not marking it naked and keeping the optimize(Os...) > stuff only, then using extended asm like in other functions maybe. > Otherwise this could require two versions, which is less fun. Note: __attribute__((naked)) on gcc x86_64 is supported since gcc 8.1. > > Looking at the object code for various on both gcc and clang show always > > the same object code. > > (Although GCC adds a "ud2" after the "ret") > > It *seems* so as well for me but in the not-really-naked case, you > really have zero control over it. Also one thing it does to me in the > not-naked-case is that registers are not saved by the caller and are > clobbered by the asm statement: > > void *memmove2(void *dst __attribute__((unused)), > void *src __attribute__((unused)), > size_t len __attribute__((unused))) > { > memmove(dst, src, len); > memmove(src, dst, len); > return 0; > } > > Gives me this with the naked attribute: > 0000000000000025 <memmove2>: > 25: 55 push %rbp > 26: 48 89 f5 mov %rsi,%rbp > 29: 50 push %rax > 2a: 48 89 14 24 mov %rdx,(%rsp) > 2e: e8 00 00 00 00 callq 33 <memmove2+0xe> > 33: 48 8b 14 24 mov (%rsp),%rdx > 37: 48 89 ef mov %rbp,%rdi > 3a: 48 89 c6 mov %rax,%rsi > 3d: e8 00 00 00 00 callq 42 <memmove2+0x1d> > 42: 31 c0 xor %eax,%eax > 44: 5a pop %rdx > 45: 5d pop %rbp > 46: c3 retq > > But the alternate form (optimize(-Os...)): > 0000000000000024 <memmove2>: > 24: 49 89 f0 mov %rsi,%r8 > 27: e8 00 00 00 00 callq 2c <memmove2+0x8> > 2c: 48 89 fe mov %rdi,%rsi > 2f: 4c 89 c7 mov %r8,%rdi > 32: e8 00 00 00 00 callq 37 <memmove2+0x13> > 37: 31 c0 xor %eax,%eax > 39: c3 retq > > See how rdi and rdx were expected to be preserved after the first call > but were not? This was with gcc-9.5 (which supports naked but it's for > illustration purposes of the risk of leaving unconstrained asm like this). To be honest, I don't see it. Not enough asm experience I guess, but I'll look at it some more. > I also managed to get clang to complain about the .Lbackward_copy label > being already defined, but I don't know how I managed to do it. I think > we should not leave it as a global label like this and instead just use > the regular numbered labels if the asm is inlined. Ack, this was easy to fix. > Also I'm wondering why there are errors about memcpy and memmove being > already defined with -flto, because these ones are marked "weak". Maybe > we need to add something else, that gcc emits with the functions when > using lto ? I think normally .weak would only be resolved by the linker. What happens here is that the assembler is already presented with duplicate definitions which it is not prepared to handle. (See below for an example) It works on gcc without -flto and on clang with and without -flto. It seems like a compiler bug to me. If you agree I'll open a ticket against GCC. Then we can fix only the label to make it work on clang and wait for a fixed GCC. Example: $ cat a.c #include "func.h" int main(void) { return 0; } $ cat b.c #include "func.h" $ cat func.h __asm__( ".weak foo\n" "foo:\n" "retq\n" ); $ gcc -flto -save-temps a.c b.c ./a.ltrans0.ltrans.s: Assembler messages: ./a.ltrans0.ltrans.s:28: Error: symbol `foo' is already defined lto-wrapper: fatal error: gcc returned 1 exit status compilation terminated. /usr/bin/ld: error: lto-wrapper failed collect2: error: ld returned 1 exit status $ cat ./a.ltrans0.ltrans.s .file "<artificial>" .text #APP .weak foo foo: retq #NO_APP .globl main .type main, @function main: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl $0, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size main, .-main #APP .weak foo foo: retq .ident "GCC: (GNU) 14.2.1 20240805" .section .note.GNU-stack,"",@progbits ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions 2024-08-10 16:04 ` Thomas Weißschuh @ 2024-08-10 16:45 ` Thomas Weißschuh 2024-08-10 17:00 ` Willy Tarreau 2024-08-10 19:16 ` Ammar Faizi 1 sibling, 1 reply; 15+ messages in thread From: Thomas Weißschuh @ 2024-08-10 16:45 UTC (permalink / raw) To: Willy Tarreau; +Cc: Ammar Faizi, linux-kernel On 2024-08-10 18:04:36+0000, Thomas Weißschuh wrote: > On 2024-08-10 16:35:56+0000, Willy Tarreau wrote: <snip> > > Also I'm wondering why there are errors about memcpy and memmove being > > already defined with -flto, because these ones are marked "weak". Maybe > > we need to add something else, that gcc emits with the functions when > > using lto ? > > I think normally .weak would only be resolved by the linker. > What happens here is that the assembler is already presented with > duplicate definitions which it is not prepared to handle. > (See below for an example) > > It works on gcc without -flto and on clang with and without -flto. > It seems like a compiler bug to me. If you agree I'll open a ticket > against GCC. > Then we can fix only the label to make it work on clang and wait for a > fixed GCC. Iff we really want to support it, we could do use naked where available and fall back to toplevel asm otherwise. This should work on newer compilers and older ones without -flto. It looks horrible though. #define NOLIBC_ARCH_HAS_MEMSET void *memset(void *dst, int c, size_t len); #if __nolibc_has_attribute(naked) __attribute__((weak,naked)) void *memset(void *dst __attribute__((unused)), int c __attribute__((unused)), size_t len __attribute__((unused))) { #else __asm__ ( ".section .text.nolibc_memset\n" ".weak memset\n" "memset:\n" ); #endif __asm__ ( "xchgl %eax, %esi\n\t" "movq %rdx, %rcx\n\t" "pushq %rdi\n\t" "rep stosb\n\t" "popq %rax\n\t" "retq\n" ); #if __nolibc_has_attribute(naked) } #endif (Or some impenetrable macro wrapper abstraction thereof) The memcpy / memmove combination could be split up into one real function and one C inline wrapper and then the same pattern would apply. But to be honest I'd be fine with not supporting -flto on GCC. Thomas ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions 2024-08-10 16:45 ` Thomas Weißschuh @ 2024-08-10 17:00 ` Willy Tarreau 2024-08-12 17:01 ` Thomas Weißschuh 0 siblings, 1 reply; 15+ messages in thread From: Willy Tarreau @ 2024-08-10 17:00 UTC (permalink / raw) To: Thomas Weißschuh; +Cc: Ammar Faizi, linux-kernel On Sat, Aug 10, 2024 at 06:45:19PM +0200, Thomas Weißschuh wrote: > Iff we really want to support it, we could do use naked where available > and fall back to toplevel asm otherwise. > This should work on newer compilers and older ones without -flto. > It looks horrible though. > > #define NOLIBC_ARCH_HAS_MEMSET > void *memset(void *dst, int c, size_t len); > > #if __nolibc_has_attribute(naked) > > __attribute__((weak,naked)) > void *memset(void *dst __attribute__((unused)), int c __attribute__((unused)), size_t len __attribute__((unused))) { > > #else > > __asm__ ( > ".section .text.nolibc_memset\n" > ".weak memset\n" > "memset:\n" > ); > > #endif > > __asm__ ( > "xchgl %eax, %esi\n\t" > "movq %rdx, %rcx\n\t" > "pushq %rdi\n\t" > "rep stosb\n\t" > "popq %rax\n\t" > "retq\n" > ); > > #if __nolibc_has_attribute(naked) > } > #endif > > (Or some impenetrable macro wrapper abstraction thereof) One dangerous part above is that the compiler can reorder toplevel asm statements, so having a label in one and the code in another may result in random bugs. > The memcpy / memmove combination could be split up into one real > function and one C inline wrapper and then the same pattern would apply. > > But to be honest I'd be fine with not supporting -flto on GCC. That could also be a reasonable solution. The primary goal of nolibc is to make it easy for developers to develop tests, and for those who want to create pre-boot code to do so. By nature this code is prone to bugs. If it becomes totally unreadable for very unlikely cases, it will cause issues that are hard to debug by the users themselves. It's sure that supporting a variety of compilers and setups is great, but we should keep in mind the maintainability goal when thinking about this. I think that LTO will mostly be used for testing, and in this case I think it's totally reasonable to restrict the choice of compatible compilers. Willy ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions 2024-08-10 17:00 ` Willy Tarreau @ 2024-08-12 17:01 ` Thomas Weißschuh 2024-08-12 19:38 ` Willy Tarreau 0 siblings, 1 reply; 15+ messages in thread From: Thomas Weißschuh @ 2024-08-12 17:01 UTC (permalink / raw) To: Willy Tarreau; +Cc: Ammar Faizi, linux-kernel On 2024-08-10 19:00:30+0000, Willy Tarreau wrote: > On Sat, Aug 10, 2024 at 06:45:19PM +0200, Thomas Weißschuh wrote: > > Iff we really want to support it, we could do use naked where available > > and fall back to toplevel asm otherwise. > > This should work on newer compilers and older ones without -flto. > > It looks horrible though. > > > > #define NOLIBC_ARCH_HAS_MEMSET > > void *memset(void *dst, int c, size_t len); > > > > #if __nolibc_has_attribute(naked) > > > > __attribute__((weak,naked)) > > void *memset(void *dst __attribute__((unused)), int c __attribute__((unused)), size_t len __attribute__((unused))) { > > > > #else > > > > __asm__ ( > > ".section .text.nolibc_memset\n" > > ".weak memset\n" > > "memset:\n" > > ); > > > > #endif > > > > __asm__ ( > > "xchgl %eax, %esi\n\t" > > "movq %rdx, %rcx\n\t" > > "pushq %rdi\n\t" > > "rep stosb\n\t" > > "popq %rax\n\t" > > "retq\n" > > ); > > > > #if __nolibc_has_attribute(naked) > > } > > #endif > > > > (Or some impenetrable macro wrapper abstraction thereof) > > One dangerous part above is that the compiler can reorder toplevel asm > statements, so having a label in one and the code in another may result > in random bugs. Indeed, let's scratch that then. > > The memcpy / memmove combination could be split up into one real > > function and one C inline wrapper and then the same pattern would apply. > > > > But to be honest I'd be fine with not supporting -flto on GCC. > > That could also be a reasonable solution. The primary goal of nolibc > is to make it easy for developers to develop tests, and for those who > want to create pre-boot code to do so. By nature this code is prone to > bugs. If it becomes totally unreadable for very unlikely cases, it will > cause issues that are hard to debug by the users themselves. It's sure > that supporting a variety of compilers and setups is great, but we should > keep in mind the maintainability goal when thinking about this. I think > that LTO will mostly be used for testing, and in this case I think it's > totally reasonable to restrict the choice of compatible compilers. IMO LTO is useful for nolibc to reduce the size of the generated binaries. For example the custom function sections that then can be combined with --gc-sections to get rid of unused functions is all implicit in LTO. And on top of that it can perform other size optimizations. But the complications for GCC are not worth it. And there seem general with LTO on GCC anyways as evidenced by the constructor and duplicate-asm bugs. After this discussion I think we should also change the __nolibc_naked attribute back to __nolibc_entrypoint as it was before. It is indeed not a replacement for a proper "naked". What do you think about me rewriting the existing commits on nolibc-next to fix this up? Thomas ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions 2024-08-12 17:01 ` Thomas Weißschuh @ 2024-08-12 19:38 ` Willy Tarreau 0 siblings, 0 replies; 15+ messages in thread From: Willy Tarreau @ 2024-08-12 19:38 UTC (permalink / raw) To: Thomas Weißschuh; +Cc: Ammar Faizi, linux-kernel Hi Thomas, On Mon, Aug 12, 2024 at 07:01:26PM +0200, Thomas Weißschuh wrote: > > > The memcpy / memmove combination could be split up into one real > > > function and one C inline wrapper and then the same pattern would apply. > > > > > > But to be honest I'd be fine with not supporting -flto on GCC. > > > > That could also be a reasonable solution. The primary goal of nolibc > > is to make it easy for developers to develop tests, and for those who > > want to create pre-boot code to do so. By nature this code is prone to > > bugs. If it becomes totally unreadable for very unlikely cases, it will > > cause issues that are hard to debug by the users themselves. It's sure > > that supporting a variety of compilers and setups is great, but we should > > keep in mind the maintainability goal when thinking about this. I think > > that LTO will mostly be used for testing, and in this case I think it's > > totally reasonable to restrict the choice of compatible compilers. > > IMO LTO is useful for nolibc to reduce the size of the generated binaries. > For example the custom function sections that then can be combined with > --gc-sections to get rid of unused functions is all implicit in LTO. > And on top of that it can perform other size optimizations. Well, probably, but my experience of it till now has been quite negative, between stuff that doesn't build and stuff that takes ages to link on a single core, for most of the time tiny to no gain at all :-/ But I admit that in our case here at least we shouldn't witness long link times. > But the complications for GCC are not worth it. > And there seem general with LTO on GCC anyways as evidenced by the > constructor and duplicate-asm bugs. Yes, and the trouble it will cause will result in a lot of head-scratching for those affected. > After this discussion I think we should also change the __nolibc_naked > attribute back to __nolibc_entrypoint as it was before. > It is indeed not a replacement for a proper "naked". Indeed, it sort of emulates it but does not have the exact same properties as we've seen. > What do you think about me rewriting the existing commits on nolibc-next > to fix this up? I'm obviously fine with this :-) Thank you! Willy ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions 2024-08-10 16:04 ` Thomas Weißschuh 2024-08-10 16:45 ` Thomas Weißschuh @ 2024-08-10 19:16 ` Ammar Faizi 2024-08-10 19:45 ` Willy Tarreau 1 sibling, 1 reply; 15+ messages in thread From: Ammar Faizi @ 2024-08-10 19:16 UTC (permalink / raw) To: Thomas Weißschuh; +Cc: Willy Tarreau, linux-kernel On Sat, Aug 10, 2024 at 06:04:36PM +0200, Thomas Weißschuh wrote: > On 2024-08-10 16:35:56+0000, Willy Tarreau wrote: > > See how rdi and rdx were expected to be preserved after the first call > > but were not? This was with gcc-9.5 (which supports naked but it's for > > illustration purposes of the risk of leaving unconstrained asm like this). > > To be honest, I don't see it. Not enough asm experience I guess, but > I'll look at it some more. Let me shed some light on what is going wrong in that form. First, let's revisit the System V ABI x86-64 calling convention: - %rdi holds the 1st argument - %rsi holds the 2nd argument - %rdx holds the 3rd argument - %rax is used for the return value Take a look at the assembly code that Willy sent. The second memmove() call is receiving incorrect arguments from the previous memmove() call. The issue arises because your memmove() function doesn't inform the compiler that it modifies %rdi and %rdx. As far as the compiler is concerned, your memmove() function: Does not alter any registers. Consequently, the compiler assumes that the values in %rdi and %rdx remain unchanged after the memmove() function returns. With this assumption, and since memmove() is within the same translation unit as the caller, the compiler optimizes the register moves without preserving the values in %rdi and %rdx. To properly inform the compiler that certain registers are being modified, you need to use constraints and a clobber list. Here's an example (note: this is untested, only compiled on Godbolt): Link: https://godbolt.org/z/WTz1nvn1h ``` void *memmove(void *dst, const void *src, size_t len) { void *rax; __asm__ goto volatile ( "movq %%rdx, %%rcx\n\t" "movq %%rdi, %%rax\n\t" "movq %%rdi, %%rdx\n\t" "subq %%rsi, %%rdx\n\t" "cmpq %%rcx, %%rdx\n\t" "jb .Lbackward_copy\n\t" "rep movsb\n\t" "jmp %[out]\n\t" ".Lbackward_copy:\n\t" "leaq -1(%%rdi, %%rcx, 1), %%rdi\n\t" "leaq -1(%%rsi, %%rcx, 1), %%rsi\n\t" "std\n\t" "rep movsb\n\t" "cld" : "+D"(dst), "+S"(src), "+c"(len), "=a"(rax) : : "rdx", "memory", "cc" : out ); out: return rax; } ``` This approach helps the compiler correctly handle the register modifications, ensuring that the generated code behaves as expected. Notes: constraints (binding C variables): - "+D": Read and Write %rdi - "+S": Read and Write %rsi - "+c": Read and Write %rcx - "=a": Write %rax clobber list: - "rdx": Write %rdx - "memory": Read and Write memory (pointed to by dst and src) - "cc": Write %rflags (This might be optional for x86-64) I believe we can do better code than that. I can't pull Linux git tree as well for now. I'll be fully available for work on Tuesday morning (13 August 2024). -- Ammar Faizi ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions 2024-08-10 19:16 ` Ammar Faizi @ 2024-08-10 19:45 ` Willy Tarreau 2024-08-10 20:10 ` Ammar Faizi 0 siblings, 1 reply; 15+ messages in thread From: Willy Tarreau @ 2024-08-10 19:45 UTC (permalink / raw) To: Ammar Faizi; +Cc: Thomas Weißschuh, linux-kernel Hi Ammar, On Sun, Aug 11, 2024 at 02:16:00AM +0700, Ammar Faizi wrote: > On Sat, Aug 10, 2024 at 06:04:36PM +0200, Thomas Weißschuh wrote: > > On 2024-08-10 16:35:56+0000, Willy Tarreau wrote: > > > See how rdi and rdx were expected to be preserved after the first call > > > but were not? This was with gcc-9.5 (which supports naked but it's for > > > illustration purposes of the risk of leaving unconstrained asm like this). > > > > To be honest, I don't see it. Not enough asm experience I guess, but > > I'll look at it some more. > > Let me shed some light on what is going wrong in that form. > > First, let's revisit the System V ABI x86-64 calling convention: > > - %rdi holds the 1st argument > - %rsi holds the 2nd argument > - %rdx holds the 3rd argument > - %rax is used for the return value > > Take a look at the assembly code that Willy sent. The second memmove() > call is receiving incorrect arguments from the previous memmove() call. > > The issue arises because your memmove() function doesn't inform the > compiler that it modifies %rdi and %rdx. As far as the compiler is > concerned, your memmove() function: > > Does not alter any registers. > > Consequently, the compiler assumes that the values in %rdi and %rdx > remain unchanged after the memmove() function returns. With this > assumption, and since memmove() is within the same translation unit as > the caller, the compiler optimizes the register moves without preserving > the values in %rdi and %rdx. > > To properly inform the compiler that certain registers are being > modified, you need to use constraints and a clobber list. Here's an > example (note: this is untested, only compiled on Godbolt): > > Link: https://godbolt.org/z/WTz1nvn1h > > ``` > void *memmove(void *dst, const void *src, size_t len) > { > void *rax; > > __asm__ goto volatile ( > "movq %%rdx, %%rcx\n\t" > "movq %%rdi, %%rax\n\t" > "movq %%rdi, %%rdx\n\t" > "subq %%rsi, %%rdx\n\t" > "cmpq %%rcx, %%rdx\n\t" > "jb .Lbackward_copy\n\t" > "rep movsb\n\t" > "jmp %[out]\n\t" > ".Lbackward_copy:\n\t" > "leaq -1(%%rdi, %%rcx, 1), %%rdi\n\t" > "leaq -1(%%rsi, %%rcx, 1), %%rsi\n\t" > "std\n\t" > "rep movsb\n\t" > "cld" > : "+D"(dst), "+S"(src), "+c"(len), "=a"(rax) > : > : "rdx", "memory", "cc" > : out > ); > > out: > return rax; > } > ``` > > This approach helps the compiler correctly handle the register > modifications, ensuring that the generated code behaves as expected. > > Notes: > > constraints (binding C variables): > - "+D": Read and Write %rdi > - "+S": Read and Write %rsi > - "+c": Read and Write %rcx > - "=a": Write %rax > > clobber list: > - "rdx": Write %rdx > - "memory": Read and Write memory (pointed to by dst and src) > - "cc": Write %rflags (This might be optional for x86-64) > > I believe we can do better code than that. I can't pull Linux git tree > as well for now. I'll be fully available for work on Tuesday morning > (13 August 2024). The constraints are trivial, the problem is that they're not supposed to be used in a naked function. I tried, as you can guess. gcc accepted them without complaining but clang not at all. However what's interesting is that the compiler being aware of our unability to inform it about the clobber list, it did consider everything clobbered and saved the registers in the caller in this case. That does make sense, otherwise it would be impossible to use asm in naked functions. However we need to restrict this use case to true naked functions, not the ones we were doing ourselves before the existence of the naked attribute. Willy ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions 2024-08-10 19:45 ` Willy Tarreau @ 2024-08-10 20:10 ` Ammar Faizi 0 siblings, 0 replies; 15+ messages in thread From: Ammar Faizi @ 2024-08-10 20:10 UTC (permalink / raw) To: Willy Tarreau; +Cc: Thomas Weißschuh, linux-kernel On Sat, Aug 10, 2024 at 09:45:45PM +0200, Willy Tarreau wrote: > The constraints are trivial, the problem is that they're not supposed to > be used in a naked function. I tried, as you can guess. gcc accepted > them without complaining but clang not at all. However what's interesting > is that the compiler being aware of our unability to inform it about the > clobber list, it did consider everything clobbered and saved the registers > in the caller in this case. That does make sense, otherwise it would be > impossible to use asm in naked functions. However we need to restrict > this use case to true naked functions, not the ones we were doing ourselves > before the existence of the naked attribute. Ah, I get it now. Apparently, my ignorance of naked functions led to, well, not knowing about naked functions. I didn't know about the naked attribute. Yeah, clang indeed throws errors while GCC does not: ``` <source>:24:10: error: parameter references not allowed in naked functions 24 | : "+D"(dst), "+S"(src), "+c"(len), "=a"(rax) | ^ <source>:4:16: note: attribute is here 4 | __attribute__((naked)) | ^ <source>:7:2: error: non-ASM statement in naked function is not supported 7 | void *rax; | ^ <source>:4:16: note: attribute is here 4 | __attribute__((naked)) | ^ 2 errors generated. Compiler returned: 1 ``` For now, I'll wait for your discussion with Thomas to resolve this issue. And yes, I agree that we should find a solution that doesn't require maintaining two different versions. -- Ammar Faizi ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2024-08-12 19:38 UTC | newest] Thread overview: 15+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-08-10 10:54 [PATCH 0/3] tools/nolibc: LTO compatibility Thomas Weißschuh 2024-08-10 10:54 ` [PATCH 1/3] tools/nolibc: crt: mark _start_c() as used Thomas Weißschuh 2024-08-10 10:54 ` [PATCH 2/3] tools/nolibc: stackprotector: mark implicitly used symbols " Thomas Weißschuh 2024-08-10 10:54 ` [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions Thomas Weißschuh 2024-08-10 12:12 ` Ammar Faizi 2024-08-10 12:37 ` Thomas Weißschuh 2024-08-10 14:35 ` Willy Tarreau 2024-08-10 16:04 ` Thomas Weißschuh 2024-08-10 16:45 ` Thomas Weißschuh 2024-08-10 17:00 ` Willy Tarreau 2024-08-12 17:01 ` Thomas Weißschuh 2024-08-12 19:38 ` Willy Tarreau 2024-08-10 19:16 ` Ammar Faizi 2024-08-10 19:45 ` Willy Tarreau 2024-08-10 20:10 ` Ammar Faizi
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox