v5 -> v6: * still use "addr_global" as we don't have a better name. * add a test case with -mno-explicit-relocs.
-- >8 -- A linker script and/or a section attribute may locate a local object in some way unexpected by the code model, leading to a link failure. This happens when the Linux kernel loads a module with "local" per-CPU variables. Add an attribute to explicitly mark an variable with the address unlimited by the code model so we would be able to work around such problems. gcc/ChangeLog: * config/loongarch/loongarch.cc (loongarch_attribute_table): New attribute table. (TARGET_ATTRIBUTE_TABLE): Define the target hook. (loongarch_handle_addr_global_attribute): New static function. (loongarch_classify_symbol): Return SYMBOL_GOT_DISP for SYMBOL_REF_DECL with addr_global attribute. (loongarch_use_anchors_for_symbol_p): New static function. (TARGET_USE_ANCHORS_FOR_SYMBOL_P): Define the target hook. * doc/extend.texi (Variable Attributes): Document new LoongArch specific attribute. gcc/testsuite/ChangeLog: * gcc.target/loongarch/attr-addr_global-1.c: New test. * gcc.target/loongarch/attr-addr_global-2.c: New test. --- gcc/config/loongarch/loongarch.cc | 63 +++++++++++++++++++ gcc/doc/extend.texi | 17 +++++ .../gcc.target/loongarch/attr-addr_global-1.c | 29 +++++++++ .../gcc.target/loongarch/attr-addr_global-2.c | 29 +++++++++ 4 files changed, 138 insertions(+) create mode 100644 gcc/testsuite/gcc.target/loongarch/attr-addr_global-1.c create mode 100644 gcc/testsuite/gcc.target/loongarch/attr-addr_global-2.c diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index 79687340dfd..978e66ed549 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -1643,6 +1643,15 @@ loongarch_classify_symbol (const_rtx x) && !loongarch_symbol_binds_local_p (x)) return SYMBOL_GOT_DISP; + if (SYMBOL_REF_P (x)) + { + tree decl = SYMBOL_REF_DECL (x); + /* An addr_global symbol may be out of the +/- 2GiB range around + the PC, so we have to use GOT. */ + if (decl && lookup_attribute ("addr_global", DECL_ATTRIBUTES (decl))) + return SYMBOL_GOT_DISP; + } + return SYMBOL_PCREL; } @@ -6068,6 +6077,54 @@ loongarch_starting_frame_offset (void) return crtl->outgoing_args_size; } +static tree +loongarch_handle_addr_global_attribute (tree *node, tree name, tree, int, + bool *no_add_attrs) +{ + tree decl = *node; + if (TREE_CODE (decl) == VAR_DECL) + { + if (DECL_CONTEXT (decl) + && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL + && !TREE_STATIC (decl)) + { + error_at (DECL_SOURCE_LOCATION (decl), + "%qE attribute cannot be specified for local " + "variables", name); + *no_add_attrs = true; + } + } + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + return NULL_TREE; +} + +static const struct attribute_spec loongarch_attribute_table[] = +{ + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, + affects_type_identity, handler, exclude } */ + { "addr_global", 0, 0, true, false, false, false, + loongarch_handle_addr_global_attribute, NULL }, + /* The last attribute spec is set to be NULL. */ + {} +}; + +bool +loongarch_use_anchors_for_symbol_p (const_rtx symbol) +{ + tree decl = SYMBOL_REF_DECL (symbol); + + /* An addr_global attribute indicates the linker may move the symbol away, + so the use of anchor may cause relocation overflow. */ + if (decl && lookup_attribute ("addr_global", DECL_ATTRIBUTES (decl))) + return false; + + return default_use_anchors_for_symbol_p (symbol); +} + /* Initialize the GCC target structure. */ #undef TARGET_ASM_ALIGNED_HI_OP #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t" @@ -6256,6 +6313,12 @@ loongarch_starting_frame_offset (void) #undef TARGET_HAVE_SPECULATION_SAFE_VALUE #define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE loongarch_attribute_table + +#undef TARGET_USE_ANCHORS_FOR_SYMBOL_P +#define TARGET_USE_ANCHORS_FOR_SYMBOL_P loongarch_use_anchors_for_symbol_p + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-loongarch.h" diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 7fe7f8817cd..b1173e15c7c 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -7314,6 +7314,7 @@ attributes. * Blackfin Variable Attributes:: * H8/300 Variable Attributes:: * IA-64 Variable Attributes:: +* LoongArch Variable Attributes:: * M32R/D Variable Attributes:: * MeP Variable Attributes:: * Microsoft Windows Variable Attributes:: @@ -8098,6 +8099,22 @@ defined by shared libraries. @end table +@node LoongArch Variable Attributes +@subsection LoongArch Variable Attributes + +One attribute is currently defined for the LoongArch. + +@table @code +@item addr_global +@cindex @code{addr_global} variable attribute, LoongArch +Use this attribute on the LoongArch to mark an object possible to be +located anywhere in the address space by the linker, so its address is +unlimited by the local data section range specified by the code model even +if the object is defined locally. This attribute is mostly useful if a +@code{section} attribute and/or a linker script will place the object +somewhere unexpected by the code model. +@end table + @node M32R/D Variable Attributes @subsection M32R/D Variable Attributes diff --git a/gcc/testsuite/gcc.target/loongarch/attr-addr_global-1.c b/gcc/testsuite/gcc.target/loongarch/attr-addr_global-1.c new file mode 100644 index 00000000000..c1553713d9d --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/attr-addr_global-1.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-mexplicit-relocs -mcmodel=normal -O2" } */ +/* { dg-final { scan-assembler-not "%pc" } } */ +/* { dg-final { scan-assembler-times "%got_pc_hi20" 3 } } */ + +/* addr_global attribute should mark x and y possibly outside of the local + data range defined by the code model, so GOT should be used instead of + PC-relative. */ + +int x __attribute__((addr_global)); +int y __attribute__((addr_global)); + +int +test(void) +{ + return x + y; +} + +/* The following will be used for kernel per-cpu storage implemention. */ + +register char *per_cpu_base __asm__("r21"); +static int counter __attribute__((section(".data..percpu"), addr_global)); + +void +inc_counter(void) +{ + int *ptr = (int *)(per_cpu_base + (long)&counter); + (*ptr)++; +} diff --git a/gcc/testsuite/gcc.target/loongarch/attr-addr_global-2.c b/gcc/testsuite/gcc.target/loongarch/attr-addr_global-2.c new file mode 100644 index 00000000000..708f163975f --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/attr-addr_global-2.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-mno-explicit-relocs -mcmodel=normal -O2" } */ +/* { dg-final { scan-assembler-not "la.local" } } */ +/* { dg-final { scan-assembler-times "la.global" 3 } } */ + +/* addr_global attribute should mark x and y possibly outside of the local + data range defined by the code model, so GOT should be used instead of + PC-relative. */ + +int x __attribute__((addr_global)); +int y __attribute__((addr_global)); + +int +test(void) +{ + return x + y; +} + +/* The following will be used for kernel per-cpu storage implemention. */ + +register char *per_cpu_base __asm__("r21"); +static int counter __attribute__((section(".data..percpu"), addr_global)); + +void +inc_counter(void) +{ + int *ptr = (int *)(per_cpu_base + (long)&counter); + (*ptr)++; +} -- 2.37.2