[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: (E)GLIBC: inline syscalls



On Wed, Jun 17, 2009 at 08:07:58AM +0200, Petr Salinger wrote:
>> The GNU/kFreeBSD port of the GNU libc uses normal syscalls (each syscall
>> is mapped to a function), while the GNU/Linux version only uses inline
>> syscalls (each syscall is mapped to asm inline code). The difference
>> mainly comes from the fact that the FreeBSD kernel is also using the
>> architecture ABI convention for the syscalls, while the Linux kernel
>> uses its own convention.
>
> Unfortunately, there is one more problem, the signaling of failure
> of a function and how to set up errno.
>
> The Linux syscals return negative value between -1 and -4095,
> the errno is this value negated.
> The FreeBSD syscalls sets carry flag and return value is directly errno.
> I have not found a way, how I can from gcc inline asm correctly test
> carry flag using some specification of a register.
> We have to put the check in one block of inline asm.

It something possible using the setb asm instruction, this is the code 
I use for amd64:

| # undef INLINE_SYSCALL
| # define INLINE_SYSCALL(name, nr, args...) \
|   ({                                                                          \
|     INTERNAL_SYSCALL_DECL (err);                                              \
|     unsigned long int resultvar = INTERNAL_SYSCALL (name, err, nr, args);     \
|     if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (resultvar, err), 0))      \
|       {                                                                       \
|         __set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, err));                \
|         resultvar = (unsigned long int) -1;                                   \
|       }                                                                       \
|     (long int) resultvar; })
| 
| # undef INTERNAL_SYSCALL_DECL
| # define INTERNAL_SYSCALL_DECL(err) unsigned char err
| 
| # define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
|   ({                                                                          \
|     unsigned long int resultvar;                                              \
|     LOAD_ARGS_##nr (args)                                                     \
|     LOAD_REGS_##nr                                                            \
|     asm volatile (                                                            \
|     ASM_LOAD_ARGS_##nr (args)                                                 \
|     "syscall\n\t"                                                             \
|     ASM_RESTORE_ARGS_##nr                                                     \
|     "setb %1\n\t"                                                             \
|     : "=a" (resultvar), "=q" (err)                                            \
|     : "0" (name) ASM_ARGS_##nr : "memory", "cc", "rcx", "r11" ASM_CLOBBER_##nr); \
|     (long int) resultvar; })
| # undef INTERNAL_SYSCALL
| # define INTERNAL_SYSCALL(name, err, nr, args...) \
|   INTERNAL_SYSCALL_NCS (SYS_##name, err, nr, ##args)

With this patch and the other needed parts, the testsuite passes
successfully on amd64.

The setb function can also be used on i386. My problem is related on how
to pass the arguments and put them on the stack, especially when they
are more than 3 or 4.

>> For i386 the situation is more complex. We need to pass up to 8
>> arguments to a syscall (especially when passing 64-bit values in
>> two arguments), which is exactly the number of registers we have on
>> this CPU. And they should in fine all be passed on the stack.
>>
>> Does anyone has an idea of a technical solution (not gcc version
>> dependent) to get this working on i386? Does anyone has an opinion to
>> share about that?
>
> There are two different macros INTERNAL_SYSCALL and INLINE_SYSCALL.
> It remains to persuade Ulrich Drepper to distinct between them :-(

Unfortunately he his not someone easy to convince...

> There is only limited number of INTERNAL_SYSCALL invocations,
> which really might need direct inline asm. We could provide
>
> #define INTERNAL_SYSCALL(name, err, nr, args...) INTERNAL_SYSCALL_##name(err,args...)
>
> and provide only limited set of such entry point. The main problem is how 
> in general detect whether an argument is 64bit value. For each function  
> name we would know.

The calls to INLINE_SYSCALL is not the part that worries me the most. It's
rather the code between #ifdef HAVE_INLINED_SYSCALLS in the elf/
directory. Not something we can workaround easily from our ports/sysdeps/
directory.

-- 
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net


Reply to: