From patchwork Sun Dec 23 20:27:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aurelien Jarno X-Patchwork-Id: 1018083 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-98757-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=aurel32.net Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="hXI9lCKg"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43NDT52ZDKz9sDr for ; Mon, 24 Dec 2018 07:28:08 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id :mime-version:content-transfer-encoding; q=dns; s=default; b=FYL OErqcSxzngABuq4jXr33p7STE5TdnMxk7lcuESScCUGQCMGjHsgvx3zikxpkR6EA z1Zxrq5vSa1d2klgwvNoTCCiIRIjL6gPL9t49KxoxPaDRDhdoI+mh5St0kefeROp 9taZXpm/JNSonydqC7jd65zKAJ5sWvzYNjjG372E= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id :mime-version:content-transfer-encoding; s=default; bh=E14xziVAF fSg5tasmtYV+EU5MtY=; b=hXI9lCKgiiAGkDlfo06wNQa6Zfxth9o7VihC1l8xu Aue3a0PTJlu7CbTCa7sGm2NHmOcAtQ6GLZdKqxww/Ty+8F75+Z4VrB3R5Hutx0zm OahDxAG5EmC/WaeWosXBu9xzMlXBjVdYM3xFA76JrTqs1/Lflgx+onff4N5wrKYW J0= Received: (qmail 90044 invoked by alias); 23 Dec 2018 20:28:02 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 90030 invoked by uid 89); 23 Dec 2018 20:28:02 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.4 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, KAM_NUMSUBJECT autolearn=ham version=3.3.2 spammy=specifying, operand, notably, initializer X-HELO: hall.aurel32.net From: Aurelien Jarno To: libc-alpha@sourceware.org Cc: Aurelien Jarno Subject: [PATCH] ARM: fix kernel assisted atomics with GCC 8 Date: Sun, 23 Dec 2018 21:27:55 +0100 Message-Id: <20181223202755.6189-1-aurelien@aurel32.net> MIME-Version: 1.0 The pre-ARMv7 CPUs are missing atomic compare and exchange and/or barrier instructions. Therefore those are implemented using kernel assistance, calling a kernel function at a specific address, and passing the arguments in the r0 to r4 registers. This is done by specifying registers for local variables. The a_ptr variable is placed in the r2 register and declared with __typeof (mem). According to the GCC documentation on local register variables, if mem is a constant pointer, the compiler may substitute the variable with its initializer in asm statements, which may cause the corresponding operand to appear in a different register. This happens in __libc_start_main with the pointer to the thread counter for static binaries (but not the shared ones): # ifdef SHARED unsigned int *ptr = __libc_pthread_functions.ptr_nthreads; # ifdef PTR_DEMANGLE PTR_DEMANGLE (ptr); # endif # else extern unsigned int __nptl_nthreads __attribute ((weak)); unsigned int *const ptr = &__nptl_nthreads; # endif This causes static binaries using threads to crash when the GNU libc is built with GCC 8 and most notably tst-cancel21-static. To fix that, use the same trick than for the volatile qualifier, defining a_ptr as a union. Changelog: * sysdeps/unix/sysv/linux/arm/atomic-machine.h (__arm_assisted_compare_and_exchange_val_32_acq): Use uint32_t rather than __typeof (...) for the a_ptr variable. --- ChangeLog | 6 ++++++ sysdeps/unix/sysv/linux/arm/atomic-machine.h | 18 +++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 881808dead..b242ea67b5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2018-12-23 Aurelien Jarno + + * sysdeps/unix/sysv/linux/arm/atomic-machine.h + (__arm_assisted_compare_and_exchange_val_32_acq): Use uint32_t rather + than __typeof (...) for the a_ptr variable. + 2018-12-21 Joseph Myers [BZ #24023] diff --git a/sysdeps/unix/sysv/linux/arm/atomic-machine.h b/sysdeps/unix/sysv/linux/arm/atomic-machine.h index ad165274d8..a5d244e65e 100644 --- a/sysdeps/unix/sysv/linux/arm/atomic-machine.h +++ b/sysdeps/unix/sysv/linux/arm/atomic-machine.h @@ -49,16 +49,23 @@ declarations of A_OLDVAL et al because when NEWVAL or OLDVAL is of the form *PTR and PTR has a 'volatile ... *' type, then __typeof (*PTR) has a 'volatile ...' type and this triggers -Wvolatile-register-var to - complain about 'register volatile ... asm ("reg")'. */ + complain about 'register volatile ... asm ("reg")'. + + We use the same union trick in the declaration of A_PTR because when + MEM is of the from *PTR and PTR has a 'const ... *' type, then __typeof + (*PTR) has a 'const ...' type and this enables the compiler to substitute + the variable with its initializer in asm statements, which may cause the + corresponding operand to appear in a different register. */ #ifdef __thumb2__ /* Thumb-2 has ldrex/strex. However it does not have barrier instructions, so we still need to use the kernel helper. */ # define __arm_assisted_compare_and_exchange_val_32_acq(mem, newval, oldval) \ - ({ union { __typeof (oldval) a; uint32_t v; } oldval_arg = { .a = (oldval) };\ + ({ union { __typeof (mem) a; uint32_t v; } mem_arg = { .a = (mem) }; \ + union { __typeof (oldval) a; uint32_t v; } oldval_arg = { .a = (oldval) };\ union { __typeof (newval) a; uint32_t v; } newval_arg = { .a = (newval) };\ register uint32_t a_oldval asm ("r0"); \ register uint32_t a_newval asm ("r1") = newval_arg.v; \ - register __typeof (mem) a_ptr asm ("r2") = (mem); \ + register uint32_t a_ptr asm ("r2") = mem_arg.v; \ register uint32_t a_tmp asm ("r3"); \ register uint32_t a_oldval2 asm ("r4") = oldval_arg.v; \ __asm__ __volatile__ \ @@ -79,11 +86,12 @@ (__typeof (oldval)) a_tmp; }) #else # define __arm_assisted_compare_and_exchange_val_32_acq(mem, newval, oldval) \ - ({ union { __typeof (oldval) a; uint32_t v; } oldval_arg = { .a = (oldval) };\ + ({ union { __typeof (mem) a; uint32_t v; } mem_arg = { .a = (mem) }; \ + union { __typeof (oldval) a; uint32_t v; } oldval_arg = { .a = (oldval) };\ union { __typeof (newval) a; uint32_t v; } newval_arg = { .a = (newval) };\ register uint32_t a_oldval asm ("r0"); \ register uint32_t a_newval asm ("r1") = newval_arg.v; \ - register __typeof (mem) a_ptr asm ("r2") = (mem); \ + register uint32_t a_ptr asm ("r2") = mem_arg.v; \ register uint32_t a_tmp asm ("r3"); \ register uint32_t a_oldval2 asm ("r4") = oldval_arg.v; \ __asm__ __volatile__ \