Hi,
-mlongcall miscompiles nested functions with the AIX ABI. The problem is
that, when -mlongcall is in effect, rs6000_call_aix redirects all calls to:
/* Handle indirect calls. */
if (GET_CODE (func_desc) != SYMBOL_REF
|| (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (func_desc)))
and then
/* A function pointer under AIX is a pointer to a data area whose
first word contains the actual address of the function, whose
second word contains a pointer to its TOC, and whose third word
contains a value to place in the static chain register (r11).
Note that if we load the static chain, our "trampoline" need
not have any executable code. */
But, if the call was originally direct, no "trampoline" has been built, which
means that the value loaded into the static chain register is garbage. That's
sort of OK, except when the called function is nested because the static chain
register has already been loaded with the proper static chain value by the
generic code, so overwriting it with garbage breaks the program.
Tested on PowerPC/AIX, OK for the mainline?
2014-10-17 Eric Botcazou <ebotca...@adacore.com>
* config/rs6000/rs6000.c (rs6000_call_aix): For the AIX ABI, do not
load the static chain if the call was originally direct.
2014-10-17 Eric Botcazou <ebotca...@adacore.com>
* gcc.target/powerpc/longcall-2.c: New test.
--
Eric Botcazou
Index: config/rs6000/rs6000.c
===================================================================
--- config/rs6000/rs6000.c (revision 216252)
+++ config/rs6000/rs6000.c (working copy)
@@ -32568,6 +32568,8 @@ rs6000_legitimate_constant_p (enum machi
void
rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
{
+ const bool direct_call_p
+ = GET_CODE (func_desc) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (func_desc);
rtx toc_reg = gen_rtx_REG (Pmode, TOC_REGNUM);
rtx toc_load = NULL_RTX;
rtx toc_restore = NULL_RTX;
@@ -32636,8 +32638,11 @@ rs6000_call_aix (rtx value, rtx func_des
func_toc_offset));
toc_load = gen_rtx_USE (VOIDmode, func_toc_mem);
- /* If we have a static chain, load it up. */
- if (TARGET_POINTERS_TO_NESTED_FUNCTIONS)
+ /* If we have a static chain, load it up. But, if the call was
+ originally direct, the 3rd word has not been written since no
+ trampoline has been built, so we ought not to load it, lest we
+ override a static chain value. */
+ if (!direct_call_p && TARGET_POINTERS_TO_NESTED_FUNCTIONS)
{
rtx sc_reg = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
rtx func_sc_offset = GEN_INT (2 * GET_MODE_SIZE (Pmode));
/* { dg-do run } */
/* { dg-options "-mlongcall" } */
extern void abort (void);
#define VAL 12345678
int j = VAL;
void
bar (void)
{
if (j != VAL)
abort ();
}
int
main (void)
{
int i = VAL;
int foo (void)
{
if (i != VAL)
abort ();
}
foo ();
bar ();
return 0;
}