2019-05-19 15:08:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2017-08-19 20:17:02 +03:00
static struct resword {
const char * name ;
int token ;
} keywords [ ] = {
export.h, genksyms: do not make genksyms calculate CRC of trimmed symbols
Arnd Bergmann reported false-positive modpost warnings detected by his
randconfig testing of linux-next.
Actually, this happens under the combination of CONFIG_MODVERSIONS
and CONFIG_TRIM_UNUSED_KSYMS since commit 15bfc2348d54 ("modpost:
check for static EXPORT_SYMBOL* functions").
For example, arch/arm/config/multi_v7_defconfig + CONFIG_MODVERSIONS
+ CONFIG_TRIM_UNUSED_KSYMS produces the following false-positives:
WARNING: "__lshrdi3" [vmlinux] is a static (unknown)
WARNING: "__ashrdi3" [vmlinux] is a static (unknown)
WARNING: "__aeabi_lasr" [vmlinux] is a static (unknown)
WARNING: "__aeabi_llsr" [vmlinux] is a static (unknown)
WARNING: "ftrace_set_clr_event" [vmlinux] is a static (unknown)
WARNING: "__muldi3" [vmlinux] is a static (unknown)
WARNING: "__aeabi_ulcmp" [vmlinux] is a static (unknown)
WARNING: "__ucmpdi2" [vmlinux] is a static (unknown)
WARNING: "__aeabi_lmul" [vmlinux] is a static (unknown)
WARNING: "__bswapsi2" [vmlinux] is a static (unknown)
WARNING: "__bswapdi2" [vmlinux] is a static (unknown)
WARNING: "__ashldi3" [vmlinux] is a static (unknown)
WARNING: "__aeabi_llsl" [vmlinux] is a static (unknown)
The root cause of the problem is not in the modpost, but in the
implementation of CONFIG_TRIM_UNUSED_KSYMS.
If there is at least one untrimmed symbol in the file, genksyms is
invoked to calculate CRC of *all* the exported symbols in that file
even if some of them have been trimmed due to no caller existing.
As a result, .tmp_*.ver files contain CRC of trimmed symbols, thus
unneeded, orphan __crc* symbols are added to objects. It had been
harmless until recently.
With commit 15bfc2348d54 ("modpost: check for static EXPORT_SYMBOL*
functions"), it is now harmful because the bogus __crc* symbols make
modpost call sym_update_crc() to add the symbols to the hash table,
but there is no one that clears the ->is_static member.
I gave Fixes to the first commit that uncovered the issue, but the
potential problem has long existed since commit f235541699bc
("export.h: allow for per-symbol configurable EXPORT_SYMBOL()").
Fixes: 15bfc2348d54 ("modpost: check for static EXPORT_SYMBOL* functions")
Reported-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Tested-by: Arnd Bergmann <arnd@arndb.de>
2019-09-09 13:53:17 +03:00
{ " __GENKSYMS_EXPORT_SYMBOL " , EXPORT_SYMBOL_KEYW } ,
2017-08-19 20:17:02 +03:00
{ " __asm " , ASM_KEYW } ,
{ " __asm__ " , ASM_KEYW } ,
{ " __attribute " , ATTRIBUTE_KEYW } ,
{ " __attribute__ " , ATTRIBUTE_KEYW } ,
{ " __const " , CONST_KEYW } ,
{ " __const__ " , CONST_KEYW } ,
{ " __extension__ " , EXTENSION_KEYW } ,
{ " __inline " , INLINE_KEYW } ,
{ " __inline__ " , INLINE_KEYW } ,
{ " __signed " , SIGNED_KEYW } ,
{ " __signed__ " , SIGNED_KEYW } ,
{ " __typeof " , TYPEOF_KEYW } ,
{ " __typeof__ " , TYPEOF_KEYW } ,
{ " __volatile " , VOLATILE_KEYW } ,
{ " __volatile__ " , VOLATILE_KEYW } ,
{ " __builtin_va_list " , VA_LIST_KEYW } ,
2019-06-18 16:10:48 +03:00
{ " __int128 " , BUILTIN_INT_KEYW } ,
{ " __int128_t " , BUILTIN_INT_KEYW } ,
{ " __uint128_t " , BUILTIN_INT_KEYW } ,
2020-08-15 04:38:15 +03:00
// According to rth, c99 defines "_Bool", "__restrict", "__restrict__", "restrict". KAO
2017-08-19 20:17:02 +03:00
{ " _Bool " , BOOL_KEYW } ,
2020-08-15 04:38:15 +03:00
{ " __restrict " , RESTRICT_KEYW } ,
2017-08-19 20:17:02 +03:00
{ " __restrict__ " , RESTRICT_KEYW } ,
{ " restrict " , RESTRICT_KEYW } ,
{ " asm " , ASM_KEYW } ,
2020-12-01 18:20:18 +03:00
// c11 keywords that can be used at module scope
{ " _Static_assert " , STATIC_ASSERT_KEYW } ,
2017-08-19 20:17:02 +03:00
// attribute commented out in modutils 2.4.2. People are using 'attribute' as a
// field name which breaks the genksyms parser. It is not a gcc keyword anyway.
// KAO. },
// { "attribute", ATTRIBUTE_KEYW },
{ " auto " , AUTO_KEYW } ,
{ " char " , CHAR_KEYW } ,
{ " const " , CONST_KEYW } ,
{ " double " , DOUBLE_KEYW } ,
{ " enum " , ENUM_KEYW } ,
{ " extern " , EXTERN_KEYW } ,
{ " float " , FLOAT_KEYW } ,
{ " inline " , INLINE_KEYW } ,
{ " int " , INT_KEYW } ,
{ " long " , LONG_KEYW } ,
{ " register " , REGISTER_KEYW } ,
{ " short " , SHORT_KEYW } ,
{ " signed " , SIGNED_KEYW } ,
{ " static " , STATIC_KEYW } ,
{ " struct " , STRUCT_KEYW } ,
{ " typedef " , TYPEDEF_KEYW } ,
{ " typeof " , TYPEOF_KEYW } ,
{ " union " , UNION_KEYW } ,
{ " unsigned " , UNSIGNED_KEYW } ,
{ " void " , VOID_KEYW } ,
{ " volatile " , VOLATILE_KEYW } ,
} ;
# define NR_KEYWORDS (sizeof(keywords) / sizeof(struct resword))
static int is_reserved_word ( register const char * str , register unsigned int len )
{
int i ;
for ( i = 0 ; i < NR_KEYWORDS ; i + + ) {
struct resword * r = keywords + i ;
int l = strlen ( r - > name ) ;
if ( len = = l & & ! memcmp ( str , r - > name , len ) )
return r - > token ;
}
return - 1 ;
}