diff mbox

[ARM] PR target/68059 libgcc should not use __write for printing fatal error

Message ID 563B4BD8.7000509@arm.com
State New
Headers show

Commit Message

Szabolcs Nagy Nov. 5, 2015, 12:30 p.m. UTC
libgcc/config/arm/linux-atomic-64bit.c uses __write to print an error
message if the 64bit xchg method is not available in the kernel.

__write is not part of the public libc abi.  Since this code is only
run on linux the write syscall can be invoked directly.

And __builtin_trap is a simpler way to crash than abort.

The new behaviour on a linux kernel before v3.1:

# ./a.out
A newer kernel is required to run this binary. (__kernel_cmpxchg64 helper)
Illegal instruction

OK for trunk and backporting?

libgcc/ChangeLog:

2015-11-05  Szabolcs Nagy  <szabolcs.nagy@arm.com>

	PR target/68059
	* config/arm/linux-atomic-64bit.c (__write): Remove declaration.
	(abort): Likewise.
	(linux_write): Define.

Comments

Richard Earnshaw Nov. 5, 2015, 3:59 p.m. UTC | #1
On 05/11/15 12:30, Szabolcs Nagy wrote:
> libgcc/config/arm/linux-atomic-64bit.c uses __write to print an error
> message if the 64bit xchg method is not available in the kernel.
> 
> __write is not part of the public libc abi.  Since this code is only
> run on linux the write syscall can be invoked directly.
> 
> And __builtin_trap is a simpler way to crash than abort.
> 
> The new behaviour on a linux kernel before v3.1:
> 
> # ./a.out
> A newer kernel is required to run this binary. (__kernel_cmpxchg64 helper)
> Illegal instruction
> 
> OK for trunk and backporting?

__morestack_fail in generic-morestack.c now uses writev().  Is there
some reason we can't do the same?

R.

> 
> libgcc/ChangeLog:
> 
> 2015-11-05  Szabolcs Nagy  <szabolcs.nagy@arm.com>
> 
>     PR target/68059
>     * config/arm/linux-atomic-64bit.c (__write): Remove declaration.
>     (abort): Likewise.
>     (linux_write): Define.
> 
> arm_write_2.diff
> 
> 
> diff --git a/libgcc/config/arm/linux-atomic-64bit.c b/libgcc/config/arm/linux-atomic-64bit.c
> index cdf713c..aba3334 100644
> --- a/libgcc/config/arm/linux-atomic-64bit.c
> +++ b/libgcc/config/arm/linux-atomic-64bit.c
> @@ -33,9 +33,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>     kernels; we check for that in an init section and bail out rather
>     unceremoneously.  */
>  
> -extern unsigned int __write (int fd, const void *buf, unsigned int count);
> -extern void abort (void);
> -
>  /* Kernel helper for compare-and-exchange.  */
>  typedef int (__kernel_cmpxchg64_t) (const long long* oldval,
>  					const long long* newval,
> @@ -45,6 +42,19 @@ typedef int (__kernel_cmpxchg64_t) (const long long* oldval,
>  /* Kernel helper page version number.  */
>  #define __kernel_helper_version (*(unsigned int *)0xffff0ffc)
>  
> +static void
> +linux_write (int fd, const void *buf, unsigned int count)
> +{
> +	register long r7 asm ("r7") = 4; /* Linux __NR_write.  */
> +	register long r0 asm ("r0") = fd;
> +	register long r1 asm ("r1") = (long)buf;
> +	register long r2 asm ("r2") = count;
> +	asm volatile ("svc 0"
> +		:
> +		: "r" (r7), "r" (r0), "r" (r1), "r" (r2)
> +		: "memory");
> +}
> +
>  /* Check that the kernel has a new enough version at load.  */
>  static void __check_for_sync8_kernelhelper (void)
>  {
> @@ -53,11 +63,9 @@ static void __check_for_sync8_kernelhelper (void)
>        const char err[] = "A newer kernel is required to run this binary. "
>  				"(__kernel_cmpxchg64 helper)\n";
>        /* At this point we need a way to crash with some information
> -	 for the user - I'm not sure I can rely on much else being
> -	 available at this point, so do the same as generic-morestack.c
> -	 write () and abort ().  */
> -      __write (2 /* stderr.  */, err, sizeof (err));
> -      abort ();
> +	 for the user.  */
> +      linux_write (2 /* stderr.  */, err, sizeof (err));
> +      __builtin_trap ();
>      }
>  };
>  
>
Szabolcs Nagy Nov. 5, 2015, 4:25 p.m. UTC | #2
On 05/11/15 15:59, Richard Earnshaw wrote:
> On 05/11/15 12:30, Szabolcs Nagy wrote:
>> libgcc/config/arm/linux-atomic-64bit.c uses __write to print an error
>> message if the 64bit xchg method is not available in the kernel.
>>
>> __write is not part of the public libc abi.  Since this code is only
>> run on linux the write syscall can be invoked directly.
>>
>> And __builtin_trap is a simpler way to crash than abort.
>>
>> The new behaviour on a linux kernel before v3.1:
>>
>> # ./a.out
>> A newer kernel is required to run this binary. (__kernel_cmpxchg64 helper)
>> Illegal instruction
>>
>> OK for trunk and backporting?
>
> __morestack_fail in generic-morestack.c now uses writev().  Is there
> some reason we can't do the same?
>

both write and writev should be part of libc abi on linux.

they are not in the iso c namespace so standard conforming
user code can override them, but we are trying to report a
fatal error with best effort, so that might not be an issue.

i can just s/__write/write/ if that's preferred (or use writev)
and then no inline asm syscall magic is necessary.

i just want to avoid the symbol reference that is potentially
not available in the libc (i'm not sure if the 64bit builtin
atomics are supposed to work in freestanding mode or if
dynamic linking to libgcc should work without a crash on
old kernels).

>> libgcc/ChangeLog:
>>
>> 2015-11-05  Szabolcs Nagy  <szabolcs.nagy@arm.com>
>>
>>      PR target/68059
>>      * config/arm/linux-atomic-64bit.c (__write): Remove declaration.
>>      (abort): Likewise.
>>      (linux_write): Define.
>>
>> arm_write_2.diff
>>
>>
>> diff --git a/libgcc/config/arm/linux-atomic-64bit.c b/libgcc/config/arm/linux-atomic-64bit.c
>> index cdf713c..aba3334 100644
>> --- a/libgcc/config/arm/linux-atomic-64bit.c
>> +++ b/libgcc/config/arm/linux-atomic-64bit.c
>> @@ -33,9 +33,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>>      kernels; we check for that in an init section and bail out rather
>>      unceremoneously.  */
>>
>> -extern unsigned int __write (int fd, const void *buf, unsigned int count);
>> -extern void abort (void);
>> -
>>   /* Kernel helper for compare-and-exchange.  */
>>   typedef int (__kernel_cmpxchg64_t) (const long long* oldval,
>>   					const long long* newval,
>> @@ -45,6 +42,19 @@ typedef int (__kernel_cmpxchg64_t) (const long long* oldval,
>>   /* Kernel helper page version number.  */
>>   #define __kernel_helper_version (*(unsigned int *)0xffff0ffc)
>>
>> +static void
>> +linux_write (int fd, const void *buf, unsigned int count)
>> +{
>> +	register long r7 asm ("r7") = 4; /* Linux __NR_write.  */
>> +	register long r0 asm ("r0") = fd;
>> +	register long r1 asm ("r1") = (long)buf;
>> +	register long r2 asm ("r2") = count;
>> +	asm volatile ("svc 0"
>> +		:
>> +		: "r" (r7), "r" (r0), "r" (r1), "r" (r2)
>> +		: "memory");
>> +}
>> +
>>   /* Check that the kernel has a new enough version at load.  */
>>   static void __check_for_sync8_kernelhelper (void)
>>   {
>> @@ -53,11 +63,9 @@ static void __check_for_sync8_kernelhelper (void)
>>         const char err[] = "A newer kernel is required to run this binary. "
>>   				"(__kernel_cmpxchg64 helper)\n";
>>         /* At this point we need a way to crash with some information
>> -	 for the user - I'm not sure I can rely on much else being
>> -	 available at this point, so do the same as generic-morestack.c
>> -	 write () and abort ().  */
>> -      __write (2 /* stderr.  */, err, sizeof (err));
>> -      abort ();
>> +	 for the user.  */
>> +      linux_write (2 /* stderr.  */, err, sizeof (err));
>> +      __builtin_trap ();
>>       }
>>   };
>>
>>
>
diff mbox

Patch

diff --git a/libgcc/config/arm/linux-atomic-64bit.c b/libgcc/config/arm/linux-atomic-64bit.c
index cdf713c..aba3334 100644
--- a/libgcc/config/arm/linux-atomic-64bit.c
+++ b/libgcc/config/arm/linux-atomic-64bit.c
@@ -33,9 +33,6 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    kernels; we check for that in an init section and bail out rather
    unceremoneously.  */
 
-extern unsigned int __write (int fd, const void *buf, unsigned int count);
-extern void abort (void);
-
 /* Kernel helper for compare-and-exchange.  */
 typedef int (__kernel_cmpxchg64_t) (const long long* oldval,
 					const long long* newval,
@@ -45,6 +42,19 @@  typedef int (__kernel_cmpxchg64_t) (const long long* oldval,
 /* Kernel helper page version number.  */
 #define __kernel_helper_version (*(unsigned int *)0xffff0ffc)
 
+static void
+linux_write (int fd, const void *buf, unsigned int count)
+{
+	register long r7 asm ("r7") = 4; /* Linux __NR_write.  */
+	register long r0 asm ("r0") = fd;
+	register long r1 asm ("r1") = (long)buf;
+	register long r2 asm ("r2") = count;
+	asm volatile ("svc 0"
+		:
+		: "r" (r7), "r" (r0), "r" (r1), "r" (r2)
+		: "memory");
+}
+
 /* Check that the kernel has a new enough version at load.  */
 static void __check_for_sync8_kernelhelper (void)
 {
@@ -53,11 +63,9 @@  static void __check_for_sync8_kernelhelper (void)
       const char err[] = "A newer kernel is required to run this binary. "
 				"(__kernel_cmpxchg64 helper)\n";
       /* At this point we need a way to crash with some information
-	 for the user - I'm not sure I can rely on much else being
-	 available at this point, so do the same as generic-morestack.c
-	 write () and abort ().  */
-      __write (2 /* stderr.  */, err, sizeof (err));
-      abort ();
+	 for the user.  */
+      linux_write (2 /* stderr.  */, err, sizeof (err));
+      __builtin_trap ();
     }
 };