powerpc Linux scv support and scv system call ABI proposal
Adhemerval Zanella
adhemerval.zanella at linaro.org
Fri Jan 31 22:30:45 AEDT 2020
On 30/01/2020 18:41, Segher Boessenkool wrote:
> Hi!
>
> On Thu, Jan 30, 2020 at 02:04:51PM -0300, Adhemerval Zanella wrote:
>> On 30/01/2020 10:50, Segher Boessenkool wrote:
>>> On Thu, Jan 30, 2020 at 01:03:53PM +0100, Florian Weimer wrote:
>>>>> This is why that *is* the only supported use. The documentation could
>>>>> use a touch-up, I think. Unless we still have problems here?
>>>>
>>>> I really don't know. GCC still has *some* support for the old behavior,
>>>> though.
>>>
>>> No. No support. It still does some of the same things, but that can
>>> change (and probably should). But this hasn't been supported since the
>>> dark ages, and the documentation has become gradually more explicit
>>> about it.
>>>
>>
>> I think this might be related to an odd sparc32 issue I am seeing with
>> newer clock_nanosleep. The expanded code is:
>>
>> --
>> register long err __asm__("g1"); // INTERNAL_SYSCALL_DECL (err)
>> r = ({ // r = INTERNAL_SYSCALL_CANCEL (...)
>> long int sc_ret;
>> if (SINGLE_THREAD_P)
>> sc_ret = INTERNAL_SYSCALL_CALL (__VA_ARGS__);
>> else
>> {
>> int sc_cancel_oldtype = __libc_enable_asynccancel ();
>> sc_ret = INTERNAL_SYSCALL_CALL (__VA_ARGS__); // It issues the syscall with the asm (...)
>> __librt_disable_asynccancel (sc_cancel_oldtype);
>> }
>> sc_ret;
>> });
>> if ((void) (val), __builtin_expect((err) != 0, 0)) // if (! INTERNAL_SYSCALL_ERROR_P (r, err))
>> return 0;
>> if ((-(val)) != ENOSYS) // if (INTERNAL_SYSCALL_ERRNO (r, err) != ENOSYS)
>> return ((-(val))); // return INTERNAL_SYSCALL_ERRNO (r, err);
>>
>> [...]
>>
>> r = ({ // r = INTERNAL_SYSCALL_CANCEL (...)
>> [...]
>> )}
>> if ((void) (val), __builtin_expect((err) != 0, 0)) // if (! INTERNAL_SYSCALL_ERROR_P (r, err))
>> {
>> [...]
>> }
>> return ((void) (val), __builtin_expect((err) != 0, 0)) // return (INTERNAL_SYSCALL_ERROR_P (r, err)
>> ? ((-(val))) : 0; // ? INTERNAL_SYSCALL_ERRNO (r, err) : 0);
>> --
>>
>> It requires that 'err' (assigned to 'g1')
>
> What do you mean by "assigned to g1"?
I meant 'err' being a local register variable.
>
>> be value propagated over
>> functions calls and over different scopes, which I take from your
>> explanation is not supported and fragile.
>
> You probably misundertand that, but let me ask: where is err assigned to
> at all in the code you quoted? I don't see it. Maybe it's hidden in some
> macro?
Indeed it was not explicit in the example code, it is burried in the
INTERNAL_SYSCALL_CALL macro which calls sparc-defined macros. For instance,
with 6 argument kernel syscall, it issues:
#define inline_syscall6(string,err,name,arg1,arg2,arg3,arg4,arg5,arg6) \
({ \
register long __o0 __asm__ ("o0") = (long)(arg1); \
register long __o1 __asm__ ("o1") = (long)(arg2); \
register long __o2 __asm__ ("o2") = (long)(arg3); \
register long __o3 __asm__ ("o3") = (long)(arg4); \
register long __o4 __asm__ ("o4") = (long)(arg5); \
register long __o5 __asm__ ("o5") = (long)(arg6); \
err = name; \
__asm __volatile (string : "=r" (err), "=r" (__o0) : \
"0" (err), "1" (__o0), "r" (__o1), \
"r" (__o2), "r" (__o3), "r" (__o4), \
"r" (__o5) : \
__SYSCALL_CLOBBERS); \
__o0; \
})
Where 'err' defined by 'INTERNAL_SYSCALL_DECL' should be the 'err' macro
argument.
>
> Or, maybe some asm writes to g1? This is explicitly not okay (quote
> from the GCC manual):
Yes, that's the case.
>
> Defining a register variable does not reserve the register. Other than
> when invoking the Extended 'asm', the contents of the specified register
> are not guaranteed. For this reason, the following uses are explicitly
> _not_ supported. If they appear to work, it is only happenstance, and
> may stop working as intended due to (seemingly) unrelated changes in
> surrounding code, or even minor changes in the optimization of a future
> version of gcc:
>
> * Passing parameters to or from Basic 'asm'
> * Passing parameters to or from Extended 'asm' without using input or
> output operands.
> * Passing parameters to or from routines written in assembler (or
> other languages) using non-standard calling conventions.
>
>> It also seems that if I
>> move the __libc_enable_* calls before 'err' initialization and after
>> its usage the code seems to works, but again it seems this usage
>> is not really supported on gcc.
>>
>> So it seems that the current usage of 'INTERNAL_SYSCALL_DECL' and
>> 'INTERNAL_SYSCALL_ERROR_P' are fragile if the architecture *does*
>> use the 'err' variable and it is defined a register alias (which
>> its the case only for sparc currently).
>>
>> Although a straightforward for sparc would be redefine
>> INTERNAL_SYSCALL_DECL to not use a register alias, I still think
>> we should just follow Linux kernel ABI convention where value in
>> the range between -4095 and -1 indicates an error and handle any
>> specific symbols that might not strictly follow it with an
>> arch-specific implementation (as we do for lseek on x32 and
>> mips64n32). It would allow cleanup a lot of code and avoid such
>> pitfalls.
>
> I don't really understand what you call a "register alias", either.
> (And i don't know the Sparc ABI well enough to help you with that).
I meant a register variable where its use 'after' the extended asm
is expected to use the define register.
More information about the Linuxppc-dev
mailing list