Re: [PATCH] compiler.h: Specify correct attribute for .rodata..c_jump_table

From: Tiezhu Yang
Date: Thu Feb 13 2025 - 21:23:23 EST


On 02/14/2025 02:54 AM, Josh Poimboeuf wrote:
On Thu, Feb 13, 2025 at 08:38:22PM +0800, Tiezhu Yang wrote:
Based on the above analysis, in order to avoid changing the behavior of
GNU assembler and silence the GNU assembler warning, is it possible to
rename ".rodata..c_jump_table" to ".c_jump_table"?

Yeah, though for the final vmlinux link we'd still need it to end up in
.rodata so it remains read-only at runtime.

So we'd basically just have to add it to the RO_DATA() macro in
include/asm-generic/vmlinux.lds.h.

Does it still work if we call it ..rodata.c_jump_table or so? Then we
could just add "*(..rodata.*) to RO_DATA(). That would be somewhat less
surprising, and would also create a standard way for other code to do
the same thing by prefixing with "..rodata.".

"..rodata.c_jump_table" works well with GCC and Clang,
there is no assembler warning for GCC and the section
name is normal for Clang.

I have a draft diff, I will do more test and send it
as a formal patch once the other patches are landed
because this patch depends on them.

The code looks something like this:

-- >8 --
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 02a4adb4a999..0af80d6627fa 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -457,7 +457,7 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
. = ALIGN((align)); \
.rodata : AT(ADDR(.rodata) - LOAD_OFFSET) { \
__start_rodata = .; \
- *(.rodata) *(.rodata.*) \
+ *(.rodata) *(.rodata.*) *(..rodata.*) \
SCHED_DATA \
RO_AFTER_INIT_DATA /* Read only after init */ \
. = ALIGN(8); \
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 200fd3c5bc70..9b56788bf3f1 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -110,7 +110,8 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
/* Unreachable code */
#ifdef CONFIG_OBJTOOL
/* Annotate a C jump table to allow objtool to follow the code flow */
-#define __annotate_jump_table __section(".rodata..c_jump_table,\"a\",@progbits #")
+#define __annotate_jump_table __section("..rodata.c_jump_table")
+#endif
#else /* !CONFIG_OBJTOOL */
#define __annotate_jump_table
#endif /* CONFIG_OBJTOOL */
diff --git a/tools/objtool/arch/loongarch/special.c b/tools/objtool/arch/loongarch/special.c
index 27c6473608f3..d3e10ad3a9bf 100644
--- a/tools/objtool/arch/loongarch/special.c
+++ b/tools/objtool/arch/loongarch/special.c
@@ -131,7 +131,7 @@ static struct reloc *find_reloc_of_rodata_c_jump_table(struct section *sec,
if (reloc_offset(reloc) > offset)
break;

- if (!strncmp(reloc->sym->sec->name, ".rodata..c_jump_table", 21)) {
+ if (!strncmp(reloc->sym->sec->name, "..rodata.c_jump_table", 21)) {
*table_size = 0;
return reloc;
}
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 7174dcb7496e..a8b67b4c5726 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -2482,12 +2482,13 @@ static void mark_rodata(struct objtool_file *file)
*
* - .rodata: can contain GCC switch tables
* - .rodata.<func>: same, if -fdata-sections is being used
- * - .rodata..c_jump_table: contains C annotated jump tables
+ * - ..rodata.c_jump_table: contains C annotated jump tables
*
* .rodata.str1.* sections are ignored; they don't contain jump tables.
*/
for_each_sec(file, sec) {
- if (!strncmp(sec->name, ".rodata", 7) &&
+ if ((!strncmp(sec->name, ".rodata", 7) ||
+ !strncmp(sec->name, "..rodata", 8)) &&
!strstr(sec->name, ".str1.")) {
sec->rodata = true;
found = true;
diff --git a/tools/objtool/include/objtool/special.h b/tools/objtool/include/objtool/special.h
index e7ee7ffccefd..34acf4ae5fab 100644
--- a/tools/objtool/include/objtool/special.h
+++ b/tools/objtool/include/objtool/special.h
@@ -10,7 +10,7 @@
#include <objtool/check.h>
#include <objtool/elf.h>

-#define C_JUMP_TABLE_SECTION ".rodata..c_jump_table"
+#define C_JUMP_TABLE_SECTION "..rodata.c_jump_table"

struct special_alt {
struct list_head list;

Thanks,
Tiezhu