Hi Alan, On Tue, Nov 13, 2018 at 11:23:43PM +1030, Alan Modra wrote: > Finally, the point of the previous patches in this series, support for > inline PLT calls, keyed off -fno-plt. This emits code using new > relocations that tie all insns in the sequence together, so that the > linker can edit the sequence back to a direct call should the call > target turn out to be local. An example of ELFv2 code to call puts is > as follows: > > .reloc .,R_PPC64_PLTSEQ,puts > std 2,24(1) > .reloc .,R_PPC64_PLT16_HA,puts > addis 12,2,0 > .reloc .,R_PPC64_PLT16_LO_DS,puts > ld 12,0(12) > .reloc .,R_PPC64_PLTSEQ,puts > mtctr 12 > .reloc .,R_PPC64_PLTCALL,puts > bctrl > ld 2,24(1) > > "addis 12,2,puts@plt@ha" and "ld 12,puts@plt@l(12)" are also supported > by the assembler. gcc instead uses the explicit R_PPC64_PLT16_HA and > R_PPC64_PLT16_LO_DS relocs because when the call is to __tls_get_addr > an extra reloc is emitted at every place where one is shown above, to > specify the __tls_get_addr arg. The linker expects the extra reloc to > come first. .reloc enforces that ordering. > > The patch also changes code emitted for longcalls if the assembler > supports the new marker relocs, so that these too can be edited. One > side effect of longcalls using PLT16 relocs is that they can now be > resolved lazily by ld.so. > > I don't support lazy inline PLT calls for ELFv1, because ELFv1 would > need barriers to reliably load both the function address and toc > pointer from the PLT. ELFv1 -fno-plt uses the longcall sequence > instead, which isn't edited by GNU ld.
That all sounds great :-) Has this been tested with older binutils, too? > * config.in (HAVE_AS_PLTSEQ): Add. > * config/rs6000/predicates.md (indirect_call_operand): New. > * config/rs6000/rs6000-protos.h (rs6000_pltseq_template), > (rs6000_sibcall_sysv): Declare. > * config/rs6000/rs6000.c (init_cumulative_args): Set cookie > CALL_LONG for -fno-plt. > (print_operand <T, z, 0>): Handle UNSPEC_PLTSEQ. > (rs6000_indirect_call_template_1): Emit .reloc directives for > UNSPEC_PLTSEQ calls. > (rs6000_pltseq_template): New function. > (rs6000_longcall_ref): Add arg parameter. Use PLT16 insns if > relocs supported by assembler. Move SYMBOL_REF test to callers. > (rs6000_call_aix): Adjust rs6000_longcall_ref call. Package > insns in UNSPEC_PLTSEQ, preserving original func_desc. > (rs6000_call_sysv): Likewise. > (rs6000_sibcall_sysv): New function. > * config/rs6000/rs6000.h (HAVE_AS_PLTSEQ): Provide default. > * config/rs6000/rs6000.md (UNSPEC_PLTSEQ, UNSPEC_PLT16_HA, > UNSPEC_PLT16_LO): New. > (pltseq_tocsave, pltseq_plt16_ha, pltseq_plt16_lo, pltseq_mtctr): New. > (call_indirect_nonlocal_sysv): Don't differentiate zero from non-zero > cookie in constraints. Test explicitly for flags in length attr. > Handle unspec operand 1. > (call_value_indirect_nonlocal_sysv): Likewise. > (call_indirect_aix, call_value_indirect_aix): Handle unspec operand 1. > (call_indirect_elfv2, call_value_indirect_elfv2): Likewise. > (sibcall, sibcall_value): Use rs6000_sibcall_sysv. > (sibcall_indirect_nonlocal_sysv): New pattern. > (sibcall_value_indirect_nonlocal_sysv): Likewise. > (sibcall_nonlocal_sysv, sibcall_value_nonlocal_sysv): Remove indirect > call alternatives. > * configure.ac: Check for gas plt sequence marker support. > * configure: Regenerate. > @@ -10727,10 +10727,20 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree > fntype, > cum->nargs_prototype = n_named_args; > > /* Check for a longcall attribute. */ > - if ((!fntype && rs6000_default_long_calls) > - || (fntype > - && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)) > - && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))) > + if (((!fntype && rs6000_default_long_calls) > + || (fntype > + && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)) > + && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))) > + || (DEFAULT_ABI != ABI_DARWIN > + && !(fndecl > + && !DECL_EXTERNAL (fndecl) > + && !DECL_WEAK (fndecl) > + && (*targetm.binds_local_p) (fndecl)) > + && (flag_plt > + ? (fntype > + && lookup_attribute ("noplt", TYPE_ATTRIBUTES (fntype))) > + : !(fntype > + && lookup_attribute ("plt", TYPE_ATTRIBUTES (fntype)))))) > cum->call_cookie |= CALL_LONG; Could you split this into a few cases? Maybe with some extra locals. It is hard to understand the code as it is. I mean like if (...) cum->call_cookie |= CALL_LONG; if (...) cum->call_cookie |= CALL_LONG; if (...) cum->call_cookie |= CALL_LONG; > +(define_insn "*sibcall_indirect_nonlocal_sysv<mode>" > + (set (attr "length") > + (cond [(and (and (match_test "!rs6000_speculate_indirect_jumps") > + (match_test "which_alternative != 1")) > + (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | > CALL_V4_CLEAR_FP_ARGS))")) > + (const_string "12") > + (ior (and (match_test "!rs6000_speculate_indirect_jumps") > + (match_test "which_alternative != 1")) > + (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | > CALL_V4_CLEAR_FP_ARGS))")) > + (const_string "8")] > + (const_string "4")))]) Please use set_attr_alternative for these. Looks fine modulo those nits. Okay for trunk. Thanks! Segher