]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
S390: Fix relocation of _nl_current_LC_CATETORY_used in static build. [BZ #19860]
authorStefan Liebler <stli@linux.vnet.ibm.com>
Tue, 28 Jun 2016 10:23:35 +0000 (12:23 +0200)
committerStefan Liebler <stli@linux.vnet.ibm.com>
Tue, 28 Jun 2016 10:28:53 +0000 (12:28 +0200)
With shared libc, all locale categories are always loaded.
For static libc they aren't, but there exist a weak
_nl_current_LC_CATEGORY_used symbol for each category.
If the category is used, the locale/lc-CATEGORY.o is linked in
where _NL_CURRENT_DEFINE (LC_CATEGORY) defines and sets the
_nl_current_LC_CATEGORY_used symbol to one.

As reported by Marcin
"Bug 18960 - s390: _nl_locale_subfreeres uses larl opcode on misaligned symbol"
(https://sourceware.org/bugzilla/show_bug.cgi?id=18960)
In function _nl_locale_subfreeres (locale/setlocale.c) for each category
a check - &_nl_current_LC_CATEGORY_used != 0 - decides whether the category
is used or not.
There is also a second usage with the same mechanism in function __uselocale
(locale/uselocale.c).

On s390 a larl instruction with R_390_PC32DBL relocation is used to
get the address of _nl_current_LC_CATEGORY_used symbols. As larl loads the
address relative in halfwords and the code is always 2-byte aligned,
larl can only load even addresses.
At the end, the relocated address is always zero and never one.

Marcins patch (see bugzilla) uses the following declaration in locale/setlocale.c:
extern char _nl_current_##category##_used __attribute__((__aligned__(1)));
In function _nl_locale_subfreeres all categories are checked and therefore gcc
is now building an array of addresses in rodata section with an R_390_64
relocation for every address. This array is loaded with larl instruction and
each address is accessed by index.
This fixes only the usage in _nl_locale_subfreeres. Each user has to add the
alignment attribute.

This patch set the _nl_current_LC_CATEGORY_used symbols to two instead of one.
This way gcc can use larl instruction and the check against zero works on
every usage.

ChangeLog:

[BZ #19860]
* locale/localeinfo.h (_NL_CURRENT_DEFINE):
Set _nl_current_LC_CATEGORY_used to two instead of one.

ChangeLog
locale/localeinfo.h

index 3990d5a72fd0818090657fb9b8f08f892f5ff5bb..932ec5b7a9c05d8e228123eb79a1d8e24f4584b0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2016-06-28  Stefan Liebler  <stli@linux.vnet.ibm.com>
+
+       [BZ #19860]
+       * locale/localeinfo.h (_NL_CURRENT_DEFINE):
+       Set _nl_current_LC_CATEGORY_used to two instead of one.
+
 2016-06-27  Aurelien Jarno  <aurelien@aurel32.net>
 
        * sysdeps/mips/tst-mode-switch-1.c (main): Converted to ...
index 94627f37e4bea9dba6b4b272fafd9551b646caef..1f4da920d144eecf99348ddb3768fc72d268d8f5 100644 (file)
@@ -260,12 +260,15 @@ extern __thread struct __locale_data *const *_nl_current_##category \
 #define _NL_CURRENT_WORD(category, item) \
   ((uint32_t) (*_nl_current_##category)->values[_NL_ITEM_INDEX (item)].word)
 
-/* This is used in lc-CATEGORY.c to define _nl_current_CATEGORY.  */
+/* This is used in lc-CATEGORY.c to define _nl_current_CATEGORY.  The symbol
+   _nl_current_CATEGORY_used is set to a value unequal to zero to mark this
+   category as used.  On S390 the used relocation to load the symbol address
+   can only handle even addresses.  */
 #define _NL_CURRENT_DEFINE(category) \
   __thread struct __locale_data *const *_nl_current_##category \
     attribute_hidden = &_nl_global_locale.__locales[category]; \
   asm (".globl " __SYMBOL_PREFIX "_nl_current_" #category "_used\n" \
-       _NL_CURRENT_DEFINE_ABS (_nl_current_##category##_used, 1));
+       _NL_CURRENT_DEFINE_ABS (_nl_current_##category##_used, 2));
 #ifdef HAVE_ASM_SET_DIRECTIVE
 # define _NL_CURRENT_DEFINE_ABS(sym, val) ".set " #sym ", " #val
 #else