This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH, rs6000] ELFv2 ABI 2/8: Remove function descriptors
- From: "Ulrich Weigand" <uweigand at de dot ibm dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 11 Nov 2013 15:41:48 +0100 (CET)
- Subject: [PATCH, rs6000] ELFv2 ABI 2/8: Remove function descriptors
- Authentication-results: sourceware.org; auth=none
Hello,
this patch adds the first major feature of the ELFv2 ABI: removal
of function descriptors.
In the current ABI, it is the responsibility of a caller to set
up the TOC pointer needed by the callee by loading the correct
value into r2. This typically happens in one of these ways:
- For a direct function call within the same module, caller and
callee share the same TOC, so r2 already contains the correct
value.
- For a direct function call to a function in another module,
the linker will interpose a PLT stub which reloads r2 to be
appropriate for the callee, with help from ld.so.
- For an indirect function call, the "function pointer" points
to function descriptor that holds the target function address
as well as the appropriate TOC value (and a static chain
value for nested functions). The caller must load those
values up before transfering control to the callee.
With the new ABI, it is the responsibility of the callee to
set up its own TOC pointer. This has a number of advantages,
in particular for a callee that doesn't actually need a TOC,
and makes the function pointer call sequence more effective
by avoiding pipeline hazards.
However, it remains true that with the PowerPC ISA, it is
difficult to actually establish addressability to the TOC
without any outside help. To avoid introducing new performance
regressions, the new ABI instead provides a dual entry point
scheme.
Any function that needs a TOC may provide two entry points:
- The first ("global") entry point is intended to called via
indirect calls. It expects r12 to be set up to point to
the entry point address itself. (Since in order to perform
an indirect call, the address must be loaded into some GPR
anyway, this does not impose a substantial impact on the
caller ...) Code at the global entry point is expected
to load up r2 with the appropriate TOC value for this
function (and it may use the r12 value to compute that),
and then fall through to the local entry point.
- The second ("local") entry point expects r2 to be set up
to the current TOC, much like an entry point in the current
ABI does. However, it must not expect r12 to hold any
particular value. This means that a local direct function
call within the same module can be done via a simple "bl"
instruction just as today. Note that the linker will
automatically direct a "bl func" to the *local* entry
point associated with the symbol "func"; not the global one.
If local and global entry points coincide, the function may
expect no particular value in either r12 or r2; this can be
used by functions that do not need a TOC.
There exists just one single ELF symbol for both local and
global entry points; its symbol value refers to the global
entry point, and flag bits in ELF st_other encode the
offset from there to the local entry point. The compiler
emits a .localentry directive to announce this location
to the assembler, which will encode it as appropriate.
This patch implements all aspects needed for this scheme:
- Emit ".abiversion 2" assembler directive to help the assembler
and linker understand the ABI implemented in this file.
- Remove all handling of function descriptors / .opd section /
dot symbols for the ELFv2 ABI.
- Output a global entry point prologue and local entry point
marker for functions that use the TOC.
- Implement the ELFv2 function pointer call sequence.
- Use trampolines to handle nested functions, just like on
32-bit (including marking the stack as executable).
- No longer scan for the old ABI indirect call sequence in
linux-unwind.h.
- Update assembler code to the new ABI:
- gcc/config/rs6000/ppc-asm.h (used by libgcc and elsewhere)
- lititm/config/powerpc/sjlj.S
- gcc/testsuite/gcc.target/powerpc/ppc64-abi-dfp-1.c
In addition, some related changes are necessary:
- Move the code generating the call to _mcount for -mprofile-kernel
from output_function_profiler to rs6000_output_function_prologue,
since this call must happen at the local entry point, not the
global entry point.
- Disable (now useless) tests for -mpointers-to-nested-functions.
- Fix the libstc++ extract_symvers.in script to ignore markers
emitted by readelf --symbols that indicate local entry points.
- Fix the "gotest" script to no longer expect function symbols
to reside in the data segment. (I understand this last bit
needs to go into the Go repository first ...)
Bye,
Ulrich
gcc/ChangeLog:
2013-11-11 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
* config/rs6000/rs6000.c (machine_function): New member
r2_setup_needed.
(rs6000_emit_prologue): Set r2_setup_needed if necessary.
(rs6000_output_mi_thunk): Set r2_setup_needed.
(rs6000_output_function_prologue): Output global entry point
prologue and local entry point marker if needed for ABI_ELFv2.
Output -mprofile-kernel code here.
(output_function_profiler): Do not output -mprofile-kernel
code here; moved to rs6000_output_function_prologue.
(rs6000_file_start): Output ".abiversion 2" for ABI_ELFv2.
(rs6000_emit_move): Do not handle dot symbols for ABI_ELFv2.
(rs6000_output_function_entry): Likewise.
(rs6000_assemble_integer): Likewise.
(rs6000_elf_encode_section_info): Likewise.
(rs6000_elf_declare_function_name): Do not create dot symbols
or .opd section for ABI_ELFv2.
(rs6000_trampoline_size): Update for ABI_ELFv2 trampolines.
(rs6000_trampoline_init): Likewise.
(rs6000_elf_file_end): Call file_end_indicate_exec_stack
for ABI_ELFv2.
(rs6000_call_aix): Handle ELFv2 indirect calls. Do not check
for function descriptors in ABI_ELFv2.
* config/rs6000/rs6000.md ("*call_indirect_aix<mode>"): Support
on ABI_AIX only, not ABI_ELFv2.
("*call_value_indirect_aix<mode>"): Likewise.
("*call_indirect_elfv2<mode>"): New pattern.
("*call_value_indirect_elfv2<mode>"): Likewise.
* config/rs6000/predicates.md ("symbol_ref_operand"): Do not
check for function descriptors in ABI_ELFv2.
("current_file_function_operand"): Likewise.
* config/rs6000/ppc-asm.h [__powerpc64__ && _CALL_ELF == 2]:
(toc): Undefine.
(FUNC_NAME): Define ELFv2 variant.
(JUMP_TARGET): Likewise.
(FUNC_START): Likewise.
(HIDDEN_FUNC): Likewise.
(FUNC_END): Likeiwse.
libitm/ChangeLog:
2013-11-11 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
* config/powerpc/sjlj.S [__powerpc64__ && _CALL_ELF == 2]:
(FUNC): Define ELFv2 variant.
(END): Likewise.
(HIDDEN): Likewise.
(CALL): Likewise.
(BASE): Likewise.
(LR_SAVE): Likewise.
libgcc/ChangeLog:
2013-11-11 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
Alan Modra <amodra@gmail.com>
* config/rs6000/tramp.S [__powerpc64__ && _CALL_ELF == 2]:
(trampoline_initial): Provide ELFv2 variant.
(__trampoline_setup): Likewise.
* config/rs6000/linux-unwind.h (frob_update_context): Do not
check for AIX indirect function call sequence if _CALL_ELF == 2.
gcc/testsuite/ChangeLog:
2013-11-11 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
* gcc.target/powerpc/ppc64-abi-dfp-1.c (FUNC_START): New macro.
(WRAPPER): Use it.
* gcc.target/powerpc/no-r11-1.c: Skip on powerpc_elfv2.
* gcc.target/powerpc/no-r11-2.c: Skip on powerpc_elfv2.
* gcc.target/powerpc/no-r11-3.c: Skip on powerpc_elfv2.
libstdc++/ChangeLog:
2013-11-11 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
* scripts/extract_symvers.in: Ignore <localentry: > fields
in readelf --symbols output.
Index: gcc/gcc/config/rs6000/rs6000.c
===================================================================
--- gcc.orig/gcc/config/rs6000/rs6000.c
+++ gcc/gcc/config/rs6000/rs6000.c
@@ -140,6 +140,8 @@ typedef struct GTY(()) machine_function
64-bits wide and is allocated early enough so that the offset
does not overflow the 16-bit load/store offset field. */
rtx sdmode_stack_slot;
+ /* Flag if r2 setup is needed with ELFv2 ABI. */
+ bool r2_setup_needed;
} machine_function;
/* Support targetm.vectorize.builtin_mask_for_load. */
@@ -4762,6 +4764,9 @@ rs6000_file_start (void)
putc ('\n', file);
}
+ if (DEFAULT_ABI == ABI_ELFv2)
+ fprintf (file, "\t.abiversion 2\n");
+
if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2
|| (TARGET_ELF && flag_pic == 2))
{
@@ -8282,7 +8287,7 @@ rs6000_emit_move (rtx dest, rtx source,
/* If this is a function address on -mcall-aixdesc,
convert it to the address of the descriptor. */
- if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
+ if (DEFAULT_ABI == ABI_AIX
&& GET_CODE (operands[1]) == SYMBOL_REF
&& XSTR (operands[1], 0)[0] == '.')
{
@@ -16678,13 +16683,13 @@ rs6000_output_function_entry (FILE *file
gcc_unreachable ();
case ABI_AIX:
- case ABI_ELFv2:
if (DOT_SYMBOLS)
putc ('.', file);
else
ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "L.");
break;
+ case ABI_ELFv2:
case ABI_V4:
case ABI_DARWIN:
break;
@@ -17482,7 +17487,7 @@ rs6000_assemble_integer (rtx x, unsigned
itself. */
else if (GET_CODE (x) == SYMBOL_REF
&& XSTR (x, 0)[0] == '.'
- && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2))
+ && DEFAULT_ABI == ABI_AIX)
{
const char *name = XSTR (x, 0);
while (*name == '.')
@@ -21582,6 +21587,17 @@ rs6000_emit_prologue (void)
#define NOT_INUSE(R) do {} while (0)
#endif
+ if (DEFAULT_ABI == ABI_ELFv2)
+ {
+ cfun->machine->r2_setup_needed = df_regs_ever_live_p (TOC_REGNUM);
+
+ /* With -mminimal-toc we may generate an extra use of r2 below. */
+ if (!TARGET_SINGLE_PIC_BASE
+ && TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
+ cfun->machine->r2_setup_needed = true;
+ }
+
+
if (flag_stack_usage_info)
current_function_static_stack_size = info->total_size;
@@ -22458,6 +22474,45 @@ rs6000_output_function_prologue (FILE *f
}
}
+ /* ELFv2 ABI r2 setup code and local entry point. This must follow
+ immediately after the global entry point label. */
+ if (DEFAULT_ABI == ABI_ELFv2 && cfun->machine->r2_setup_needed)
+ {
+ const char *name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
+
+ fprintf (file, "0:\taddis 2,12,.TOC.-0b@ha\n");
+ fprintf (file, "\taddi 2,2,.TOC.-0b@l\n");
+
+ fputs ("\t.localentry\t", file);
+ assemble_name (file, name);
+ fputs (",.-", file);
+ assemble_name (file, name);
+ fputs ("\n", file);
+ }
+
+ /* Output -mprofile-kernel code. This needs to be done here instead of
+ in output_function_profile since it must go after the ELFv2 ABI
+ local entry point. */
+ if (TARGET_PROFILE_KERNEL)
+ {
+ gcc_assert (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2);
+ gcc_assert (!TARGET_32BIT);
+
+ asm_fprintf (file, "\tmflr %s\n", reg_names[0]);
+ asm_fprintf (file, "\tstd %s,16(%s)\n", reg_names[0], reg_names[1]);
+
+ if (cfun->static_chain_decl != NULL)
+ {
+ asm_fprintf (file, "\tstd %s,24(%s)\n",
+ reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
+ fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
+ asm_fprintf (file, "\tld %s,24(%s)\n",
+ reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
+ }
+ else
+ fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
+ }
+
rs6000_pic_labelno++;
}
@@ -23825,6 +23880,12 @@ rs6000_output_mi_thunk (FILE *file, tree
SIBLING_CALL_P (insn) = 1;
emit_barrier ();
+ /* Ensure we have a global entry point for the thunk. ??? We could
+ avoid that if the target routine doesn't need a global entry point,
+ but we do not know whether this is the case at this point. */
+ if (DEFAULT_ABI == ABI_ELFv2)
+ cfun->machine->r2_setup_needed = true;
+
/* Run just enough of rest_of_compilation to get the insns emitted.
There's not really enough bulk here to make other passes such as
instruction scheduling worth while. Note that use_thunk calls
@@ -24646,28 +24707,7 @@ output_function_profiler (FILE *file, in
case ABI_AIX:
case ABI_ELFv2:
case ABI_DARWIN:
- if (!TARGET_PROFILE_KERNEL)
- {
- /* Don't do anything, done in output_profile_hook (). */
- }
- else
- {
- gcc_assert (!TARGET_32BIT);
-
- asm_fprintf (file, "\tmflr %s\n", reg_names[0]);
- asm_fprintf (file, "\tstd %s,16(%s)\n", reg_names[0], reg_names[1]);
-
- if (cfun->static_chain_decl != NULL)
- {
- asm_fprintf (file, "\tstd %s,24(%s)\n",
- reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
- fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
- asm_fprintf (file, "\tld %s,24(%s)\n",
- reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
- }
- else
- fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
- }
+ /* Don't do anything, done in output_profile_hook (). */
break;
}
}
@@ -26600,10 +26640,14 @@ rs6000_trampoline_size (void)
gcc_unreachable ();
case ABI_AIX:
- case ABI_ELFv2:
ret = (TARGET_32BIT) ? 12 : 24;
break;
+ case ABI_ELFv2:
+ gcc_assert (!TARGET_32BIT);
+ ret = 32;
+ break;
+
case ABI_DARWIN:
case ABI_V4:
ret = (TARGET_32BIT) ? 40 : 48;
@@ -26632,7 +26676,6 @@ rs6000_trampoline_init (rtx m_tramp, tre
/* Under AIX, just build the 3 word function descriptor */
case ABI_AIX:
- case ABI_ELFv2:
{
rtx fnmem, fn_reg, toc_reg;
@@ -26660,6 +26703,7 @@ rs6000_trampoline_init (rtx m_tramp, tre
break;
/* Under V.4/eabi/darwin, __trampoline_setup does the real work. */
+ case ABI_ELFv2:
case ABI_DARWIN:
case ABI_V4:
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__trampoline_setup"),
@@ -27032,7 +27076,7 @@ rs6000_elf_encode_section_info (tree dec
if (first
&& TREE_CODE (decl) == FUNCTION_DECL
&& !TARGET_AIX
- && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2))
+ && DEFAULT_ABI == ABI_AIX)
{
rtx sym_ref = XEXP (rtl, 0);
size_t len = strlen (XSTR (sym_ref, 0));
@@ -27602,7 +27646,7 @@ rs6000_elf_asm_out_destructor (rtx symbo
void
rs6000_elf_declare_function_name (FILE *file, const char *name, tree decl)
{
- if (TARGET_64BIT)
+ if (TARGET_64BIT && DEFAULT_ABI != ABI_ELFv2)
{
fputs ("\t.section\t\".opd\",\"aw\"\n\t.align 3\n", file);
ASM_OUTPUT_LABEL (file, name);
@@ -27652,7 +27696,7 @@ rs6000_elf_declare_function_name (FILE *
ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
- if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
+ if (DEFAULT_ABI == ABI_AIX)
{
const char *desc_name, *orig_name;
@@ -27697,7 +27741,7 @@ rs6000_elf_file_end (void)
}
#endif
#if defined (POWERPC_LINUX) || defined (POWERPC_FREEBSD)
- if (TARGET_32BIT)
+ if (TARGET_32BIT || DEFAULT_ABI == ABI_ELFv2)
file_end_indicate_exec_stack ();
#endif
}
@@ -30672,7 +30716,7 @@ rs6000_call_aix (rtx value, rtx func_des
/* Handle indirect calls. */
if (GET_CODE (func_desc) != SYMBOL_REF
- || !SYMBOL_REF_FUNCTION_P (func_desc))
+ || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (func_desc)))
{
/* Save the TOC into its reserved slot before the call,
and prepare to restore it after the call. */
@@ -30693,38 +30737,49 @@ rs6000_call_aix (rtx value, rtx func_des
emit_move_insn (stack_toc_mem, toc_reg);
}
- /* 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. */
-
- /* Load up address of the actual function. */
- func_desc = force_reg (Pmode, func_desc);
- func_addr = gen_reg_rtx (Pmode);
- emit_move_insn (func_addr, gen_rtx_MEM (Pmode, func_desc));
-
- /* Prepare to load the TOC of the called function. Note that the
- TOC load must happen immediately before the actual call so
- that unwinding the TOC registers works correctly. See the
- comment in frob_update_context. */
- rtx func_toc_offset = GEN_INT (GET_MODE_SIZE (Pmode));
- rtx func_toc_mem = gen_rtx_MEM (Pmode,
- gen_rtx_PLUS (Pmode, func_desc,
- 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)
- {
- rtx sc_reg = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
- rtx func_sc_offset = GEN_INT (2 * GET_MODE_SIZE (Pmode));
- rtx func_sc_mem = gen_rtx_MEM (Pmode,
- gen_rtx_PLUS (Pmode, func_desc,
- func_sc_offset));
- emit_move_insn (sc_reg, func_sc_mem);
- abi_reg = sc_reg;
+ if (DEFAULT_ABI == ABI_ELFv2)
+ {
+ /* A function pointer in the ELFv2 ABI is just a plain address, but
+ the ABI requires it to be loaded into r12 before the call. */
+ func_addr = gen_rtx_REG (Pmode, 12);
+ emit_move_insn (func_addr, func_desc);
+ abi_reg = func_addr;
+ }
+ else
+ {
+ /* 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. */
+
+ /* Load up address of the actual function. */
+ func_desc = force_reg (Pmode, func_desc);
+ func_addr = gen_reg_rtx (Pmode);
+ emit_move_insn (func_addr, gen_rtx_MEM (Pmode, func_desc));
+
+ /* Prepare to load the TOC of the called function. Note that the
+ TOC load must happen immediately before the actual call so
+ that unwinding the TOC registers works correctly. See the
+ comment in frob_update_context. */
+ rtx func_toc_offset = GEN_INT (GET_MODE_SIZE (Pmode));
+ rtx func_toc_mem = gen_rtx_MEM (Pmode,
+ gen_rtx_PLUS (Pmode, func_desc,
+ 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)
+ {
+ rtx sc_reg = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
+ rtx func_sc_offset = GEN_INT (2 * GET_MODE_SIZE (Pmode));
+ rtx func_sc_mem = gen_rtx_MEM (Pmode,
+ gen_rtx_PLUS (Pmode, func_desc,
+ func_sc_offset));
+ emit_move_insn (sc_reg, func_sc_mem);
+ abi_reg = sc_reg;
+ }
}
}
else
Index: gcc/gcc/config/rs6000/rs6000.md
===================================================================
--- gcc.orig/gcc/config/rs6000/rs6000.md
+++ gcc/gcc/config/rs6000/rs6000.md
@@ -12490,7 +12490,7 @@
(use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
(set (reg:P TOC_REGNUM) (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
(clobber (reg:P LR_REGNO))]
- "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
+ "DEFAULT_ABI == ABI_AIX"
"<ptrload> 2,%2\;b%T0l\;<ptrload> 2,%3"
[(set_attr "type" "jmpreg")
(set_attr "length" "12")])
@@ -12502,11 +12502,36 @@
(use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
(set (reg:P TOC_REGNUM) (match_operand:P 4 "memory_operand" "<ptrm>,<ptrm>"))
(clobber (reg:P LR_REGNO))]
- "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
+ "DEFAULT_ABI == ABI_AIX"
"<ptrload> 2,%3\;b%T1l\;<ptrload> 2,%4"
[(set_attr "type" "jmpreg")
(set_attr "length" "12")])
+;; Call to indirect functions with the ELFv2 ABI.
+;; Operand0 is the addresss of the function to call
+;; Operand2 is the stack location to hold the current TOC pointer
+
+(define_insn "*call_indirect_elfv2<mode>"
+ [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
+ (match_operand 1 "" "g,g"))
+ (set (reg:P TOC_REGNUM) (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
+ (clobber (reg:P LR_REGNO))]
+ "DEFAULT_ABI == ABI_ELFv2"
+ "b%T0l\;<ptrload> 2,%2"
+ [(set_attr "type" "jmpreg")
+ (set_attr "length" "8")])
+
+(define_insn "*call_value_indirect_elfv2<mode>"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
+ (match_operand 2 "" "g,g")))
+ (set (reg:P TOC_REGNUM) (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
+ (clobber (reg:P LR_REGNO))]
+ "DEFAULT_ABI == ABI_ELFv2"
+ "b%T1l\;<ptrload> 2,%3"
+ [(set_attr "type" "jmpreg")
+ (set_attr "length" "8")])
+
;; Call subroutine returning any type.
(define_expand "untyped_call"
Index: gcc/gcc/config/rs6000/predicates.md
===================================================================
--- gcc.orig/gcc/config/rs6000/predicates.md
+++ gcc/gcc/config/rs6000/predicates.md
@@ -1018,8 +1018,7 @@
(define_predicate "symbol_ref_operand"
(and (match_code "symbol_ref")
(match_test "(mode == VOIDmode || GET_MODE (op) == mode)
- && ((DEFAULT_ABI != ABI_AIX && DEFAULT_ABI != ABI_ELFv2)
- || SYMBOL_REF_FUNCTION_P (op))")))
+ && (DEFAULT_ABI != ABI_AIX || SYMBOL_REF_FUNCTION_P (op))")))
;; Return 1 if op is an operand that can be loaded via the GOT.
;; or non-special register register field no cr0
@@ -1049,8 +1048,7 @@
;; this file.
(define_predicate "current_file_function_operand"
(and (match_code "symbol_ref")
- (match_test "((DEFAULT_ABI != ABI_AIX && DEFAULT_ABI != ABI_ELFv2)
- || SYMBOL_REF_FUNCTION_P (op))
+ (match_test "(DEFAULT_ABI != ABI_AIX || SYMBOL_REF_FUNCTION_P (op))
&& ((SYMBOL_REF_LOCAL_P (op)
&& ((DEFAULT_ABI != ABI_AIX
&& DEFAULT_ABI != ABI_ELFv2)
Index: gcc/gcc/config/rs6000/ppc-asm.h
===================================================================
--- gcc.orig/gcc/config/rs6000/ppc-asm.h
+++ gcc/gcc/config/rs6000/ppc-asm.h
@@ -256,7 +256,30 @@ see the files COPYING3 and COPYING.RUNTI
* the real function with one or two leading periods respectively.
*/
-#if defined (__powerpc64__)
+#if defined(__powerpc64__) && _CALL_ELF == 2
+
+/* Defining "toc" above breaks @toc in assembler code. */
+#undef toc
+
+#define FUNC_NAME(name) GLUE(__USER_LABEL_PREFIX__,name)
+#define JUMP_TARGET(name) FUNC_NAME(name)
+#define FUNC_START(name) \
+ .type FUNC_NAME(name),@function; \
+ .globl FUNC_NAME(name); \
+FUNC_NAME(name): \
+0: addis 2,12,(.TOC.-0b)@ha; \
+ addi 2,2,(.TOC.-0b)@l; \
+ .localentry FUNC_NAME(name),.-FUNC_NAME(name)
+
+#define HIDDEN_FUNC(name) \
+ FUNC_START(name) \
+ .hidden FUNC_NAME(name);
+
+#define FUNC_END(name) \
+ .size FUNC_NAME(name),.-FUNC_NAME(name)
+
+#elif defined (__powerpc64__)
+
#define FUNC_NAME(name) GLUE(.,name)
#define JUMP_TARGET(name) FUNC_NAME(name)
#define FUNC_START(name) \
Index: gcc/libitm/config/powerpc/sjlj.S
===================================================================
--- gcc.orig/libitm/config/powerpc/sjlj.S
+++ gcc/libitm/config/powerpc/sjlj.S
@@ -26,7 +26,26 @@
#include "asmcfi.h"
-#if defined(__powerpc64__) && defined(__ELF__)
+#if defined(__powerpc64__) && _CALL_ELF == 2
+.macro FUNC name
+ .globl \name
+ .type \name, @function
+\name:
+0: addis 2,12,(.TOC.-0b)@ha
+ addi 2,2,(.TOC.-0b)@l
+ .localentry \name, . - \name
+.endm
+.macro END name
+ .size \name, . - \name
+.endm
+.macro HIDDEN name
+ .hidden \name
+.endm
+.macro CALL name
+ bl \name
+ nop
+.endm
+#elif defined(__powerpc64__) && defined(__ELF__)
.macro FUNC name
.globl \name, .\name
.section ".opd","aw"
@@ -117,6 +136,9 @@ _$0:
#if defined(_CALL_AIXDESC)
# define BASE 6*WS
# define LR_SAVE 2*WS
+#elif _CALL_ELF == 2
+# define BASE 6*WS
+# define LR_SAVE 2*WS
#elif defined(_CALL_SYSV)
# define BASE 2*WS
# define LR_SAVE 1*WS
Index: gcc/libgcc/config/rs6000/tramp.S
===================================================================
--- gcc.orig/libgcc/config/rs6000/tramp.S
+++ gcc/libgcc/config/rs6000/tramp.S
@@ -116,4 +116,70 @@ FUNC_END(__trampoline_setup)
#endif
+#elif _CALL_ELF == 2
+ .type trampoline_initial,@object
+ .align 3
+trampoline_initial:
+ ld r11,.Lchain(r12)
+ ld r12,.Lfunc(r12)
+ mtctr r12
+ bctr
+.Lfunc = .-trampoline_initial
+ .quad 0 /* will be replaced with function address */
+.Lchain = .-trampoline_initial
+ .quad 0 /* will be replaced with static chain */
+
+trampoline_size = .-trampoline_initial
+ .size trampoline_initial,trampoline_size
+
+
+/* R3 = stack address to store trampoline */
+/* R4 = length of trampoline area */
+/* R5 = function address */
+/* R6 = static chain */
+
+ .pushsection ".toc","aw"
+.LC0:
+ .quad trampoline_initial-8
+ .popsection
+
+FUNC_START(__trampoline_setup)
+ addis 7,2,.LC0@toc@ha
+ ld 7,.LC0@toc@l(7) /* trampoline address -8 */
+
+ li r8,trampoline_size /* verify that the trampoline is big enough */
+ cmpw cr1,r8,r4
+ srwi r4,r4,3 /* # doublewords to move */
+ addi r9,r3,-8 /* adjust pointer for stdu */
+ mtctr r4
+ blt cr1,.Labort
+
+ /* Copy the instructions to the stack */
+.Lmove:
+ ldu r10,8(r7)
+ stdu r10,8(r9)
+ bdnz .Lmove
+
+ /* Store correct function and static chain */
+ std r5,.Lfunc(r3)
+ std r6,.Lchain(r3)
+
+ /* Now flush both caches */
+ mtctr r4
+.Lcache:
+ icbi 0,r3
+ dcbf 0,r3
+ addi r3,r3,8
+ bdnz .Lcache
+
+ /* Finally synchronize things & return */
+ sync
+ isync
+ blr
+
+.Labort:
+ bl JUMP_TARGET(abort)
+ nop
+FUNC_END(__trampoline_setup)
+
#endif
Index: gcc/libgcc/config/rs6000/linux-unwind.h
===================================================================
--- gcc.orig/libgcc/config/rs6000/linux-unwind.h
+++ gcc/libgcc/config/rs6000/linux-unwind.h
@@ -317,6 +317,8 @@ frob_update_context (struct _Unwind_Cont
= (unsigned int *) _Unwind_GetGR (context, R_LR);
if (insn && *insn == 0xE8410028)
_Unwind_SetGRPtr (context, 2, context->cfa + 40);
+#if _CALL_ELF != 2
+ /* ELFv2 does not use this function pointer call sequence. */
else if (pc[0] == 0x4E800421
&& pc[1] == 0xE8410028)
{
@@ -327,6 +329,7 @@ frob_update_context (struct _Unwind_Cont
_Unwind_Word sp = _Unwind_GetGR (context, 1);
_Unwind_SetGRPtr (context, 2, (void *)(sp + 40));
}
+#endif
}
}
#endif
Index: gcc/gcc/testsuite/gcc.target/powerpc/ppc64-abi-dfp-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.target/powerpc/ppc64-abi-dfp-1.c
+++ gcc/gcc/testsuite/gcc.target/powerpc/ppc64-abi-dfp-1.c
@@ -33,15 +33,27 @@ reg_parms_t gparms;
/* Wrapper to save the GPRs and FPRs and then jump to the real function. */
+#if _CALL_ELF != 2
+#define FUNC_START(NAME) \
+ "\t.globl\t" NAME "\n\t" \
+ ".section \".opd\",\"aw\"\n\t" \
+ ".align 3\n" \
+ NAME ":\n\t" \
+ ".quad .L." NAME ",.TOC.@tocbase,0\n\t" \
+ ".text\n\t" \
+ ".type " NAME ", @function\n" \
+ ".L." NAME ":\n\t"
+#else
+#define FUNC_START(NAME) \
+ "\t.globl\t" NAME "\n\t" \
+ ".text\n\t" \
+ NAME ":\n" \
+ "0:\taddis 2,12,(.TOC.-0b)@ha\n\t" \
+ "addi 2,2,(.TOC.-0b)@l\n\t" \
+ ".localentry " NAME ",.-" NAME "\n\t"
+#endif
#define WRAPPER(NAME) \
-__asm__ ("\t.globl\t" #NAME "_asm\n\t" \
- ".section \".opd\",\"aw\"\n\t" \
- ".align 3\n" \
- #NAME "_asm:\n\t" \
- ".quad .L." #NAME "_asm,.TOC.@tocbase,0\n\t" \
- ".text\n\t" \
- ".type " #NAME "_asm, @function\n" \
- ".L." #NAME "_asm:\n\t" \
+__asm__ (FUNC_START (#NAME "_asm") \
"ld 11,gparms@got(2)\n\t" \
"std 3,0(11)\n\t" \
"std 4,8(11)\n\t" \
Index: gcc/gcc/testsuite/gcc.target/powerpc/no-r11-1.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.target/powerpc/no-r11-1.c
+++ gcc/gcc/testsuite/gcc.target/powerpc/no-r11-1.c
@@ -1,5 +1,6 @@
/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
/* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */
+/* { dg-skip-if "" { powerpc_elfv2 } { "*" } { "" } } */
/* { dg-options "-O2 -mno-pointers-to-nested-functions" } */
int
Index: gcc/gcc/testsuite/gcc.target/powerpc/no-r11-2.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.target/powerpc/no-r11-2.c
+++ gcc/gcc/testsuite/gcc.target/powerpc/no-r11-2.c
@@ -1,5 +1,6 @@
/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
/* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */
+/* { dg-skip-if "" { powerpc_elfv2 } { "*" } { "" } } */
/* { dg-options "-O2 -mpointers-to-nested-functions" } */
int
Index: gcc/gcc/testsuite/gcc.target/powerpc/no-r11-3.c
===================================================================
--- gcc.orig/gcc/testsuite/gcc.target/powerpc/no-r11-3.c
+++ gcc/gcc/testsuite/gcc.target/powerpc/no-r11-3.c
@@ -1,5 +1,6 @@
/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
/* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */
+/* { dg-skip-if "" { powerpc_elfv2 } { "*" } { "" } } */
/* { dg-options "-O2 -mno-pointers-to-nested-functions" } */
extern void ext_call (int (func) (void));
Index: gcc/libstdc++-v3/scripts/extract_symvers.in
===================================================================
--- gcc.orig/libstdc++-v3/scripts/extract_symvers.in
+++ gcc/libstdc++-v3/scripts/extract_symvers.in
@@ -53,6 +53,7 @@ SunOS)
# present on Solaris.
${readelf} ${lib} |\
sed -e 's/ \[<other>: [A-Fa-f0-9]*\] //' -e '/\.dynsym/,/^$/p;d' |\
+ sed -e 's/ \[<localentry>: [0-9]*\] //' |\
egrep -v ' (LOCAL|UND) ' |\
egrep -v ' (_DYNAMIC|_GLOBAL_OFFSET_TABLE_|_PROCEDURE_LINKAGE_TABLE_|_edata|_end|_etext)$' |\
sed -e 's/ <processor specific>: / <processor_specific>:_/g' |\
Index: gcc/libgo/testsuite/gotest
===================================================================
--- gcc.orig/libgo/testsuite/gotest
+++ gcc/libgo/testsuite/gotest
@@ -369,7 +369,7 @@ localname() {
{
text="T"
case "$GOARCH" in
- ppc64) text="D" ;;
+ ppc64) text="[TD]" ;;
esac
symtogo='sed -e s/_test/XXXtest/ -e s/.*_\([^_]*\.\)/\1/ -e s/XXXtest/_test/'
--
Dr. Ulrich Weigand
GNU/Linux compilers and toolchain
Ulrich.Weigand@de.ibm.com