The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: Willy Tarreau <w@1wt.eu>
To: Ammar Faizi <ammarfaizi2@gnuweeb.org>
Cc: "Thomas Weißschuh" <linux@weissschuh.net>, linux-kernel@vger.kernel.org
Subject: Re: [PATCH 3/3] tools/nolibc: x86_64: wrap asm functions in functions
Date: Sat, 10 Aug 2024 21:45:45 +0200	[thread overview]
Message-ID: <20240810194545.GA5065@1wt.eu> (raw)
In-Reply-To: <Zre8cPOKetof24nJ@biznet-home.integral.gnuweeb.org>

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

  reply	other threads:[~2024-08-10 19:45 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
2024-08-10 20:10               ` Ammar Faizi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240810194545.GA5065@1wt.eu \
    --to=w@1wt.eu \
    --cc=ammarfaizi2@gnuweeb.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@weissschuh.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox