[backport from gcc-4.7.2 r191137 ] Date: Mon, 10 Sep 2012 11:20:05 -0700 From: Richard Henderson Subject: [alpha] Fix GPREL16 relocation error building glibc List-Archive: There's an access within glibc wherein we've forced an important global variable into the .sdata section (so that accesses to its members can use 16-bit relocations), but an array access gets constant-folded such that we produce an offset well well outside of a 16-bit range. A test case that must be visually inspected looks like the following. I'm not certain how to turn this into a portable link-time test. But considering that other ports also handle SYMBOL_REF_SMALL_DATA, it does seem like something portable would be nice. Ideas? Or should I just drop this in as an alpha specific test? extern int x[10] __attribute__((visibility("hidden"), section(".sdata"))); int foo(int y) { return x[y-100000]; } Committed the patch itself to mainline and 4.7 branch. gcc/ 2012-09-10 Richard Henderson * config/alpha/predicates.md (small_symbolic_operand): Disallow large offsets. --- gcc-4.6.3/gcc/config/alpha/predicates.md.~1~ 2010-11-21 09:18:31.000000000 +0100 +++ gcc-4.6.3/gcc/config/alpha/predicates.md 2012-09-15 14:12:02.000000000 +0200 @@ -330,26 +330,50 @@ (define_predicate "local_symbolic_operan (define_predicate "small_symbolic_operand" (match_code "const,symbol_ref") { + HOST_WIDE_INT ofs = 0, max_ofs = 0; + if (! TARGET_SMALL_DATA) - return 0; + return false; if (GET_CODE (op) == CONST && GET_CODE (XEXP (op, 0)) == PLUS && CONST_INT_P (XEXP (XEXP (op, 0), 1))) - op = XEXP (XEXP (op, 0), 0); + { + ofs = INTVAL (XEXP (XEXP (op, 0), 1)); + op = XEXP (XEXP (op, 0), 0); + } if (GET_CODE (op) != SYMBOL_REF) - return 0; + return false; /* ??? There's no encode_section_info equivalent for the rtl constant pool, so SYMBOL_FLAG_SMALL never gets set. */ if (CONSTANT_POOL_ADDRESS_P (op)) - return GET_MODE_SIZE (get_pool_mode (op)) <= g_switch_value; + { + max_ofs = GET_MODE_SIZE (get_pool_mode (op)); + if (max_ofs > g_switch_value) + return false; + } + else if (SYMBOL_REF_LOCAL_P (op) + && SYMBOL_REF_SMALL_P (op) + && !SYMBOL_REF_WEAK (op) + && !SYMBOL_REF_TLS_MODEL (op)) + { + if (SYMBOL_REF_DECL (op)) + max_ofs = tree_low_cst (DECL_SIZE_UNIT (SYMBOL_REF_DECL (op)), 1); + } + else + return false; - return (SYMBOL_REF_LOCAL_P (op) - && SYMBOL_REF_SMALL_P (op) - && !SYMBOL_REF_WEAK (op) - && !SYMBOL_REF_TLS_MODEL (op)); + /* Given that we know that the GP is always 8 byte aligned, we can + always adjust by 7 without overflowing. */ + if (max_ofs < 8) + max_ofs = 8; + + /* Since we know this is an object in a small data section, we know the + entire section is addressable via GP. We don't know where the section + boundaries are, but we know the entire object is within. */ + return IN_RANGE (ofs, 0, max_ofs - 1); }) ;; Return true if OP is a SYMBOL_REF or CONST referencing a variable