diff mbox series

[4/7] module: avoid code duplication in include/linux/export.h

Message ID 20190927093603.9140-5-yamada.masahiro@socionext.com
State Accepted
Commit c3a6cf19e695c8b0a9bf8b5933f863e12d878b7c
Headers show
Series module: various bug-fixes and clean-ups for module namespace | expand

Commit Message

Masahiro Yamada Sept. 27, 2019, 9:36 a.m. UTC
include/linux/export.h has lots of code duplication between
EXPORT_SYMBOL and EXPORT_SYMBOL_NS.

To improve the maintainability and readability, unify the
implementation.

When the symbol has no namespace, pass the empty string "" to
the 'ns' parameter.

The drawback of this change is, it grows the code size.
When the symbol has no namespace, sym->namespace was previously
NULL, but it is now am empty string "". So, it increases 1 byte
for every no namespace EXPORT_SYMBOL.

A typical kernel configuration has 10K exported symbols, so it
increases 10KB in rough estimation.

I did not come up with a good idea to refactor it without increasing
the code size.

I am not sure how big a deal it is, but at least include/linux/export.h
looks nicer.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

---

 include/linux/export.h | 100 +++++++++++++----------------------------
 kernel/module.c        |   2 +-
 2 files changed, 33 insertions(+), 69 deletions(-)

-- 
2.17.1

Comments

Masahiro Yamada Sept. 27, 2019, 9:58 a.m. UTC | #1
On Fri, Sep 27, 2019 at 6:37 PM Masahiro Yamada
<yamada.masahiro@socionext.com> wrote:
>

> include/linux/export.h has lots of code duplication between

> EXPORT_SYMBOL and EXPORT_SYMBOL_NS.

>

> To improve the maintainability and readability, unify the

> implementation.

>

> When the symbol has no namespace, pass the empty string "" to

> the 'ns' parameter.

>

> The drawback of this change is, it grows the code size.

> When the symbol has no namespace, sym->namespace was previously

> NULL, but it is now am empty string "". So, it increases 1 byte



Just a nit.
I meant "an empty string" instead of "am empty string".



> for every no namespace EXPORT_SYMBOL.

>

> A typical kernel configuration has 10K exported symbols, so it

> increases 10KB in rough estimation.

>

> I did not come up with a good idea to refactor it without increasing

> the code size.

>

> I am not sure how big a deal it is, but at least include/linux/export.h

> looks nicer.

>

> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

> ---

>

>  include/linux/export.h | 100 +++++++++++++----------------------------

>  kernel/module.c        |   2 +-

>  2 files changed, 33 insertions(+), 69 deletions(-)

>

> diff --git a/include/linux/export.h b/include/linux/export.h

> index 621158ecd2e2..55245a405a2f 100644

> --- a/include/linux/export.h

> +++ b/include/linux/export.h

> @@ -48,45 +48,28 @@ extern struct module __this_module;

>   * absolute relocations that require runtime processing on relocatable

>   * kernels.

>   */

> -#define __KSYMTAB_ENTRY_NS(sym, sec, ns)                               \

> +#define __KSYMTAB_ENTRY(sym, sec, ns)                                  \

>         __ADDRESSABLE(sym)                                              \

>         asm("   .section \"___ksymtab" sec "+" #sym "\", \"a\"  \n"     \

>             "   .balign 4                                       \n"     \

> -           "__ksymtab_" #ns NS_SEPARATOR #sym ":               \n"     \

> +           "__ksymtab_" ns NS_SEPARATOR #sym ":                \n"     \

>             "   .long   " #sym "- .                             \n"     \

>             "   .long   __kstrtab_" #sym "- .                   \n"     \

>             "   .long   __kstrtabns_" #sym "- .                 \n"     \

>             "   .previous                                       \n")

>

> -#define __KSYMTAB_ENTRY(sym, sec)                                      \

> -       __ADDRESSABLE(sym)                                              \

> -       asm("   .section \"___ksymtab" sec "+" #sym "\", \"a\"  \n"     \

> -           "   .balign 4                                       \n"     \

> -           "__ksymtab_" #sym ":                                \n"     \

> -           "   .long   " #sym "- .                             \n"     \

> -           "   .long   __kstrtab_" #sym "- .                   \n"     \

> -           "   .long   0                                       \n"     \

> -           "   .previous                                       \n")

> -

>  struct kernel_symbol {

>         int value_offset;

>         int name_offset;

>         int namespace_offset;

>  };

>  #else

> -#define __KSYMTAB_ENTRY_NS(sym, sec, ns)                               \

> -       static const struct kernel_symbol __ksymtab_##sym##__##ns       \

> -       asm("__ksymtab_" #ns NS_SEPARATOR #sym)                         \

> -       __attribute__((section("___ksymtab" sec "+" #sym), used))       \

> -       __aligned(sizeof(void *))                                       \

> -       = { (unsigned long)&sym, __kstrtab_##sym, __kstrtabns_##sym }

> -

> -#define __KSYMTAB_ENTRY(sym, sec)                                      \

> +#define __KSYMTAB_ENTRY(sym, sec, ns)                                  \

>         static const struct kernel_symbol __ksymtab_##sym               \

> -       asm("__ksymtab_" #sym)                                          \

> +       asm("__ksymtab_" ns NS_SEPARATOR #sym)                          \

>         __attribute__((section("___ksymtab" sec "+" #sym), used))       \

>         __aligned(sizeof(void *))                                       \

> -       = { (unsigned long)&sym, __kstrtab_##sym, NULL }

> +       = { (unsigned long)&sym, __kstrtab_##sym, __kstrtabns_##sym }

>

>  struct kernel_symbol {

>         unsigned long value;

> @@ -97,29 +80,21 @@ struct kernel_symbol {

>

>  #ifdef __GENKSYMS__

>

> -#define ___EXPORT_SYMBOL(sym,sec)      __GENKSYMS_EXPORT_SYMBOL(sym)

> -#define ___EXPORT_SYMBOL_NS(sym,sec,ns)        __GENKSYMS_EXPORT_SYMBOL(sym)

> +#define ___EXPORT_SYMBOL(sym, sec, ns) __GENKSYMS_EXPORT_SYMBOL(sym)

>

>  #else

>

> -#define ___export_symbol_common(sym, sec)                              \

> +/* For every exported symbol, place a struct in the __ksymtab section */

> +#define ___EXPORT_SYMBOL(sym, sec, ns)                         \

>         extern typeof(sym) sym;                                         \

>         __CRC_SYMBOL(sym, sec);                                         \

>         static const char __kstrtab_##sym[]                             \

>         __attribute__((section("__ksymtab_strings"), used, aligned(1))) \

> -       = #sym                                                          \

> -

> -/* For every exported symbol, place a struct in the __ksymtab section */

> -#define ___EXPORT_SYMBOL_NS(sym, sec, ns)                              \

> -       ___export_symbol_common(sym, sec);                              \

> +       = #sym;                                                         \

>         static const char __kstrtabns_##sym[]                           \

>         __attribute__((section("__ksymtab_strings"), used, aligned(1))) \

> -       = #ns;                                                          \

> -       __KSYMTAB_ENTRY_NS(sym, sec, ns)

> -

> -#define ___EXPORT_SYMBOL(sym, sec)                                     \

> -       ___export_symbol_common(sym, sec);                              \

> -       __KSYMTAB_ENTRY(sym, sec)

> +       = ns;                                                           \

> +       __KSYMTAB_ENTRY(sym, sec, ns)

>

>  #endif

>

> @@ -130,8 +105,7 @@ struct kernel_symbol {

>   * be reused in other execution contexts such as the UEFI stub or the

>   * decompressor.

>   */

> -#define __EXPORT_SYMBOL_NS(sym, sec, ns)

> -#define __EXPORT_SYMBOL(sym, sec)

> +#define __EXPORT_SYMBOL(sym, sec, ns)

>

>  #elif defined(CONFIG_TRIM_UNUSED_KSYMS)

>

> @@ -147,48 +121,38 @@ struct kernel_symbol {

>  #define __ksym_marker(sym)     \

>         static int __ksym_marker_##sym[0] __section(".discard.ksym") __used

>

> -#define __EXPORT_SYMBOL(sym, sec)                              \

> +#define __EXPORT_SYMBOL(sym, sec, ns)                          \

>         __ksym_marker(sym);                                     \

> -       __cond_export_sym(sym, sec, __is_defined(__KSYM_##sym))

> -#define __cond_export_sym(sym, sec, conf)                      \

> -       ___cond_export_sym(sym, sec, conf)

> -#define ___cond_export_sym(sym, sec, enabled)                  \

> -       __cond_export_sym_##enabled(sym, sec)

> -#define __cond_export_sym_1(sym, sec) ___EXPORT_SYMBOL(sym, sec)

> -#define __cond_export_sym_0(sym, sec) /* nothing */

> -

> -#define __EXPORT_SYMBOL_NS(sym, sec, ns)                               \

> -       __ksym_marker(sym);                                             \

> -       __cond_export_ns_sym(sym, sec, ns, __is_defined(__KSYM_##sym))

> -#define __cond_export_ns_sym(sym, sec, ns, conf)                       \

> -       ___cond_export_ns_sym(sym, sec, ns, conf)

> -#define ___cond_export_ns_sym(sym, sec, ns, enabled)                   \

> -       __cond_export_ns_sym_##enabled(sym, sec, ns)

> -#define __cond_export_ns_sym_1(sym, sec, ns) ___EXPORT_SYMBOL_NS(sym, sec, ns)

> -#define __cond_export_ns_sym_0(sym, sec, ns) /* nothing */

> +       __cond_export_sym(sym, sec, ns, __is_defined(__KSYM_##sym))

> +#define __cond_export_sym(sym, sec, ns, conf)                  \

> +       ___cond_export_sym(sym, sec, ns, conf)

> +#define ___cond_export_sym(sym, sec, ns, enabled)              \

> +       __cond_export_sym_##enabled(sym, sec, ns)

> +#define __cond_export_sym_1(sym, sec, ns) ___EXPORT_SYMBOL(sym, sec, ns)

> +#define __cond_export_sym_0(sym, sec, ns) /* nothing */

>

>  #else

>

> -#define __EXPORT_SYMBOL_NS(sym,sec,ns) ___EXPORT_SYMBOL_NS(sym,sec,ns)

> -#define __EXPORT_SYMBOL(sym,sec)       ___EXPORT_SYMBOL(sym,sec)

> +#define __EXPORT_SYMBOL(sym, sec, ns)  ___EXPORT_SYMBOL(sym, sec, ns)

>

>  #endif /* CONFIG_MODULES */

>

>  #ifdef DEFAULT_SYMBOL_NAMESPACE

> -#undef __EXPORT_SYMBOL

> -#define __EXPORT_SYMBOL(sym, sec)                              \

> -       __EXPORT_SYMBOL_NS(sym, sec, DEFAULT_SYMBOL_NAMESPACE)

> +#include <linux/stringify.h>

> +#define _EXPORT_SYMBOL(sym, sec)       __EXPORT_SYMBOL(sym, sec, __stringify(DEFAULT_SYMBOL_NAMESPACE))

> +#else

> +#define _EXPORT_SYMBOL(sym, sec)       __EXPORT_SYMBOL(sym, sec, "")

>  #endif

>

> -#define EXPORT_SYMBOL(sym)             __EXPORT_SYMBOL(sym, "")

> -#define EXPORT_SYMBOL_GPL(sym)         __EXPORT_SYMBOL(sym, "_gpl")

> -#define EXPORT_SYMBOL_GPL_FUTURE(sym)  __EXPORT_SYMBOL(sym, "_gpl_future")

> -#define EXPORT_SYMBOL_NS(sym, ns)      __EXPORT_SYMBOL_NS(sym, "", ns)

> -#define EXPORT_SYMBOL_NS_GPL(sym, ns)  __EXPORT_SYMBOL_NS(sym, "_gpl", ns)

> +#define EXPORT_SYMBOL(sym)             _EXPORT_SYMBOL(sym, "")

> +#define EXPORT_SYMBOL_GPL(sym)         _EXPORT_SYMBOL(sym, "_gpl")

> +#define EXPORT_SYMBOL_GPL_FUTURE(sym)  _EXPORT_SYMBOL(sym, "_gpl_future")

> +#define EXPORT_SYMBOL_NS(sym, ns)      __EXPORT_SYMBOL(sym, "", #ns)

> +#define EXPORT_SYMBOL_NS_GPL(sym, ns)  __EXPORT_SYMBOL(sym, "_gpl", #ns)

>

>  #ifdef CONFIG_UNUSED_SYMBOLS

> -#define EXPORT_UNUSED_SYMBOL(sym)      __EXPORT_SYMBOL(sym, "_unused")

> -#define EXPORT_UNUSED_SYMBOL_GPL(sym)  __EXPORT_SYMBOL(sym, "_unused_gpl")

> +#define EXPORT_UNUSED_SYMBOL(sym)      _EXPORT_SYMBOL(sym, "_unused")

> +#define EXPORT_UNUSED_SYMBOL_GPL(sym)  _EXPORT_SYMBOL(sym, "_unused_gpl")

>  #else

>  #define EXPORT_UNUSED_SYMBOL(sym)

>  #define EXPORT_UNUSED_SYMBOL_GPL(sym)

> diff --git a/kernel/module.c b/kernel/module.c

> index 32873bcce738..73f69ff86db5 100644

> --- a/kernel/module.c

> +++ b/kernel/module.c

> @@ -1399,7 +1399,7 @@ static int verify_namespace_is_imported(const struct load_info *info,

>         char *imported_namespace;

>

>         namespace = kernel_symbol_namespace(sym);

> -       if (namespace) {

> +       if (namespace && namespace[0]) {

>                 imported_namespace = get_modinfo(info, "import_ns");

>                 while (imported_namespace) {

>                         if (strcmp(namespace, imported_namespace) == 0)

> --

> 2.17.1

>



-- 
Best Regards
Masahiro Yamada
Rasmus Villemoes Sept. 27, 2019, 11:07 a.m. UTC | #2
On 27/09/2019 11.36, Masahiro Yamada wrote:
> include/linux/export.h has lots of code duplication between

> EXPORT_SYMBOL and EXPORT_SYMBOL_NS.

> 

> To improve the maintainability and readability, unify the

> implementation.

> 

> When the symbol has no namespace, pass the empty string "" to

> the 'ns' parameter.

> 

> The drawback of this change is, it grows the code size.

> When the symbol has no namespace, sym->namespace was previously

> NULL, but it is now am empty string "". So, it increases 1 byte

> for every no namespace EXPORT_SYMBOL.

> 

> A typical kernel configuration has 10K exported symbols, so it

> increases 10KB in rough estimation.

> 

> I did not come up with a good idea to refactor it without increasing

> the code size.


Can't we put the "aMS" flags on the __ksymtab_strings section? That
would make the empty strings free, and would also deduplicate the
USB_STORAGE string. And while almost per definition we don't have exact
duplicates among the names of exported symbols, we might have both a foo
and __foo, so that could save even more.

I don't know if we have it already, but we'd need each arch to tell us
what symbol to use for @ in @progbits (e.g. % for arm). It seems most
are fine with @, so maybe a generic version could be

#ifndef ARCH_SECTION_TYPE_CHAR
#define ARCH_SECTION_TYPE_CHAR "@"
#endif

and then it would be
section("__ksymtab_strings,\"aMS\","ARCH_SECTION_TYPE_CHAR"progbits,1")

But I don't know if any tooling relies on the strings not being
deduplicated.

Rasmus
Matthias Maennich Sept. 27, 2019, 12:36 p.m. UTC | #3
On Fri, Sep 27, 2019 at 01:07:33PM +0200, Rasmus Villemoes wrote:
>On 27/09/2019 11.36, Masahiro Yamada wrote:

>> include/linux/export.h has lots of code duplication between

>> EXPORT_SYMBOL and EXPORT_SYMBOL_NS.

>>

>> To improve the maintainability and readability, unify the

>> implementation.

>>

>> When the symbol has no namespace, pass the empty string "" to

>> the 'ns' parameter.

>>

>> The drawback of this change is, it grows the code size.

>> When the symbol has no namespace, sym->namespace was previously

>> NULL, but it is now am empty string "". So, it increases 1 byte

>> for every no namespace EXPORT_SYMBOL.

>>

>> A typical kernel configuration has 10K exported symbols, so it

>> increases 10KB in rough estimation.

>>

>> I did not come up with a good idea to refactor it without increasing

>> the code size.

>

>Can't we put the "aMS" flags on the __ksymtab_strings section? That

>would make the empty strings free, and would also deduplicate the

>USB_STORAGE string. And while almost per definition we don't have exact

>duplicates among the names of exported symbols, we might have both a foo

>and __foo, so that could save even more.


I was not aware of this possibility and I was a bit bothered that I was
not able to deduplicate the namespace strings in the PREL case. So, at
least I tried to avoid having the redundant empty strings in it. If this
approach solves the deduplication problem _and_ reduces the complexity
of the code, I am very much for it. I will only be able to look into
this next week.

>I don't know if we have it already, but we'd need each arch to tell us

>what symbol to use for @ in @progbits (e.g. % for arm). It seems most

>are fine with @, so maybe a generic version could be

>

>#ifndef ARCH_SECTION_TYPE_CHAR

>#define ARCH_SECTION_TYPE_CHAR "@"

>#endif

>

>and then it would be

>section("__ksymtab_strings,\"aMS\","ARCH_SECTION_TYPE_CHAR"progbits,1")

>

>But I don't know if any tooling relies on the strings not being

>deduplicated.


Matthias
Cheers,

>Rasmus
Jessica Yu Oct. 29, 2019, 7:19 p.m. UTC | #4
+++ Rasmus Villemoes [27/09/19 13:07 +0200]:
>On 27/09/2019 11.36, Masahiro Yamada wrote:

>> include/linux/export.h has lots of code duplication between

>> EXPORT_SYMBOL and EXPORT_SYMBOL_NS.

>>

>> To improve the maintainability and readability, unify the

>> implementation.

>>

>> When the symbol has no namespace, pass the empty string "" to

>> the 'ns' parameter.

>>

>> The drawback of this change is, it grows the code size.

>> When the symbol has no namespace, sym->namespace was previously

>> NULL, but it is now am empty string "". So, it increases 1 byte

>> for every no namespace EXPORT_SYMBOL.

>>

>> A typical kernel configuration has 10K exported symbols, so it

>> increases 10KB in rough estimation.

>>

>> I did not come up with a good idea to refactor it without increasing

>> the code size.

>

>Can't we put the "aMS" flags on the __ksymtab_strings section? That

>would make the empty strings free, and would also deduplicate the

>USB_STORAGE string. And while almost per definition we don't have exact

>duplicates among the names of exported symbols, we might have both a foo

>and __foo, so that could save even more.

>

>I don't know if we have it already, but we'd need each arch to tell us

>what symbol to use for @ in @progbits (e.g. % for arm). It seems most

>are fine with @, so maybe a generic version could be

>

>#ifndef ARCH_SECTION_TYPE_CHAR

>#define ARCH_SECTION_TYPE_CHAR "@"

>#endif

>

>and then it would be

>section("__ksymtab_strings,\"aMS\","ARCH_SECTION_TYPE_CHAR"progbits,1")


FWIW, I've just tinkered with this, and unfortunately the strings
don't get deduplicated for kernel modules :-(

Apparently ld does not do the deduplication for SHF_MERGE|SHF_STRINGS
sections for relocatable files (ld -r), which kernel modules are. See:

    https://sourceware.org/ml/binutils/2009-07/msg00291.html

But, the strings do get deduplicated for vmlinux. Not sure if we can
find a workaround for modules or if the benefit is significant enough
if it only for vmlinux.

Thanks,

Jessica
Rasmus Villemoes Oct. 29, 2019, 9:11 p.m. UTC | #5
On 29/10/2019 20.19, Jessica Yu wrote:
> +++ Rasmus Villemoes [27/09/19 13:07 +0200]:

>> On 27/09/2019 11.36, Masahiro Yamada wrote:

>>>

>>> A typical kernel configuration has 10K exported symbols, so it

>>> increases 10KB in rough estimation.

>>>

>>> I did not come up with a good idea to refactor it without increasing

>>> the code size.

>>

>> Can't we put the "aMS" flags on the __ksymtab_strings section? That

>> would make the empty strings free, and would also deduplicate the

>> USB_STORAGE string. And while almost per definition we don't have exact

>> duplicates among the names of exported symbols, we might have both a foo

>> and __foo, so that could save even more.

>>

>> I don't know if we have it already, but we'd need each arch to tell us

>> what symbol to use for @ in @progbits (e.g. % for arm). It seems most

>> are fine with @, so maybe a generic version could be

>>

>> #ifndef ARCH_SECTION_TYPE_CHAR

>> #define ARCH_SECTION_TYPE_CHAR "@"

>> #endif

>>

>> and then it would be

>> section("__ksymtab_strings,\"aMS\","ARCH_SECTION_TYPE_CHAR"progbits,1")

> 

> FWIW, I've just tinkered with this, and unfortunately the strings

> don't get deduplicated for kernel modules :-(

> 

> Apparently ld does not do the deduplication for SHF_MERGE|SHF_STRINGS

> sections for relocatable files (ld -r), which kernel modules are. See:

> 

>    https://sourceware.org/ml/binutils/2009-07/msg00291.html


I know <https://patches-gcc.linaro.org/patch/5858/> :)

> But, the strings do get deduplicated for vmlinux. Not sure if we can

> find a workaround for modules or if the benefit is significant enough

> if it only for vmlinux.


I think it's definitely worth if, even if it "only" benefits vmlinux for
now. And I still hope to revisit the --force-section-merge some day, but
it's very far down my priority list.

Rasmus
Jessica Yu Oct. 31, 2019, 10:13 a.m. UTC | #6
+++ Rasmus Villemoes [29/10/19 22:11 +0100]:
>On 29/10/2019 20.19, Jessica Yu wrote:

>> +++ Rasmus Villemoes [27/09/19 13:07 +0200]:

>>> On 27/09/2019 11.36, Masahiro Yamada wrote:

>>>>

>>>> A typical kernel configuration has 10K exported symbols, so it

>>>> increases 10KB in rough estimation.

>>>>

>>>> I did not come up with a good idea to refactor it without increasing

>>>> the code size.

>>>

>>> Can't we put the "aMS" flags on the __ksymtab_strings section? That

>>> would make the empty strings free, and would also deduplicate the

>>> USB_STORAGE string. And while almost per definition we don't have exact

>>> duplicates among the names of exported symbols, we might have both a foo

>>> and __foo, so that could save even more.

>>>

>>> I don't know if we have it already, but we'd need each arch to tell us

>>> what symbol to use for @ in @progbits (e.g. % for arm). It seems most

>>> are fine with @, so maybe a generic version could be

>>>

>>> #ifndef ARCH_SECTION_TYPE_CHAR

>>> #define ARCH_SECTION_TYPE_CHAR "@"

>>> #endif

>>>

>>> and then it would be

>>> section("__ksymtab_strings,\"aMS\","ARCH_SECTION_TYPE_CHAR"progbits,1")

>>

>> FWIW, I've just tinkered with this, and unfortunately the strings

>> don't get deduplicated for kernel modules :-(

>>

>> Apparently ld does not do the deduplication for SHF_MERGE|SHF_STRINGS

>> sections for relocatable files (ld -r), which kernel modules are. See:

>>

>>    https://sourceware.org/ml/binutils/2009-07/msg00291.html

>

>I know <https://patches-gcc.linaro.org/patch/5858/> :)


That is exactly what we need! :)

>> But, the strings do get deduplicated for vmlinux. Not sure if we can

>> find a workaround for modules or if the benefit is significant enough

>> if it only for vmlinux.

>

>I think it's definitely worth if, even if it "only" benefits vmlinux for

>now. And I still hope to revisit the --force-section-merge some day, but

>it's very far down my priority list.


Yeah, I think it's worth having too.

If you don't have any extra cycles at the moment, and it's far down
your priority list, do you mind if I take a look and maybe try to push
that patch of yours upstream again? I don't know how successful I'd
be, but now since it's especially relevant for namespaces, it's
definitely worth looking at again.

Thanks!

Jessica
Rasmus Villemoes Oct. 31, 2019, 11:03 a.m. UTC | #7
On 31/10/2019 11.13, Jessica Yu wrote:
> +++ Rasmus Villemoes [29/10/19 22:11 +0100]:

>> On 29/10/2019 20.19, Jessica Yu wrote:


>>> Apparently ld does not do the deduplication for SHF_MERGE|SHF_STRINGS

>>> sections for relocatable files (ld -r), which kernel modules are. See:

>>>

>>>    https://sourceware.org/ml/binutils/2009-07/msg00291.html

>>

>> I know <https://patches-gcc.linaro.org/patch/5858/> :)

> 

> That is exactly what we need! :)

> 

>>> But, the strings do get deduplicated for vmlinux. Not sure if we can

>>> find a workaround for modules or if the benefit is significant enough

>>> if it only for vmlinux.

>>

>> I think it's definitely worth if, even if it "only" benefits vmlinux for

>> now. And I still hope to revisit the --force-section-merge some day, but

>> it's very far down my priority list.

> 

> Yeah, I think it's worth having too.

> 

> If you don't have any extra cycles at the moment, and it's far down

> your priority list, do you mind if I take a look and maybe try to push

> that patch of yours upstream again? 


Knock yourself out :) IIRC, it did actually work for the powerpc I was
targeting, but I don't remember if that was just "readelf/objdump
inspection of the ELF files looks reasonable" or if I actually tried
loading the modules. I've pushed the patch to
https://github.com/Villemoes/binutils-gdb/commit/107b9302858fc5fc1a1690f4a36e1f80808ab421
so you don't have to copy-paste from a browser.

I don't know how successful I'd
> be, but now since it's especially relevant for namespaces, it's

> definitely worth looking at again.


Yeah, but even ignoring namespaces, it would be nice to have format
strings etc. deduplicated. Please keep me cc'ed on any progress you make.

Thanks,
Rasmus
Jessica Yu Oct. 31, 2019, 11:26 a.m. UTC | #8
+++ Rasmus Villemoes [31/10/19 12:03 +0100]:
>On 31/10/2019 11.13, Jessica Yu wrote:

>> +++ Rasmus Villemoes [29/10/19 22:11 +0100]:

>>> On 29/10/2019 20.19, Jessica Yu wrote:

>

>>>> Apparently ld does not do the deduplication for SHF_MERGE|SHF_STRINGS

>>>> sections for relocatable files (ld -r), which kernel modules are. See:

>>>>

>>>>    https://sourceware.org/ml/binutils/2009-07/msg00291.html

>>>

>>> I know <https://patches-gcc.linaro.org/patch/5858/> :)

>>

>> That is exactly what we need! :)

>>

>>>> But, the strings do get deduplicated for vmlinux. Not sure if we can

>>>> find a workaround for modules or if the benefit is significant enough

>>>> if it only for vmlinux.

>>>

>>> I think it's definitely worth if, even if it "only" benefits vmlinux for

>>> now. And I still hope to revisit the --force-section-merge some day, but

>>> it's very far down my priority list.

>>

>> Yeah, I think it's worth having too.

>>

>> If you don't have any extra cycles at the moment, and it's far down

>> your priority list, do you mind if I take a look and maybe try to push

>> that patch of yours upstream again?

>

>Knock yourself out :) IIRC, it did actually work for the powerpc I was

>targeting, but I don't remember if that was just "readelf/objdump

>inspection of the ELF files looks reasonable" or if I actually tried

>loading the modules. I've pushed the patch to

>https://github.com/Villemoes/binutils-gdb/commit/107b9302858fc5fc1a1690f4a36e1f80808ab421

>so you don't have to copy-paste from a browser.


Thanks a bunch!

>I don't know how successful I'd

>> be, but now since it's especially relevant for namespaces, it's

>> definitely worth looking at again.

>

>Yeah, but even ignoring namespaces, it would be nice to have format

>strings etc. deduplicated. Please keep me cc'ed on any progress you make.


Thanks, I'll keep you posted if I manage to get somewhere with it :)
diff mbox series

Patch

diff --git a/include/linux/export.h b/include/linux/export.h
index 621158ecd2e2..55245a405a2f 100644
--- a/include/linux/export.h
+++ b/include/linux/export.h
@@ -48,45 +48,28 @@  extern struct module __this_module;
  * absolute relocations that require runtime processing on relocatable
  * kernels.
  */
-#define __KSYMTAB_ENTRY_NS(sym, sec, ns)				\
+#define __KSYMTAB_ENTRY(sym, sec, ns)					\
 	__ADDRESSABLE(sym)						\
 	asm("	.section \"___ksymtab" sec "+" #sym "\", \"a\"	\n"	\
 	    "	.balign	4					\n"	\
-	    "__ksymtab_" #ns NS_SEPARATOR #sym ":		\n"	\
+	    "__ksymtab_" ns NS_SEPARATOR #sym ":		\n"	\
 	    "	.long	" #sym "- .				\n"	\
 	    "	.long	__kstrtab_" #sym "- .			\n"	\
 	    "	.long	__kstrtabns_" #sym "- .			\n"	\
 	    "	.previous					\n")
 
-#define __KSYMTAB_ENTRY(sym, sec)					\
-	__ADDRESSABLE(sym)						\
-	asm("	.section \"___ksymtab" sec "+" #sym "\", \"a\"	\n"	\
-	    "	.balign 4					\n"	\
-	    "__ksymtab_" #sym ":				\n"	\
-	    "	.long	" #sym "- .				\n"	\
-	    "	.long	__kstrtab_" #sym "- .			\n"	\
-	    "	.long	0					\n"	\
-	    "	.previous					\n")
-
 struct kernel_symbol {
 	int value_offset;
 	int name_offset;
 	int namespace_offset;
 };
 #else
-#define __KSYMTAB_ENTRY_NS(sym, sec, ns)				\
-	static const struct kernel_symbol __ksymtab_##sym##__##ns	\
-	asm("__ksymtab_" #ns NS_SEPARATOR #sym)				\
-	__attribute__((section("___ksymtab" sec "+" #sym), used))	\
-	__aligned(sizeof(void *))					\
-	= { (unsigned long)&sym, __kstrtab_##sym, __kstrtabns_##sym }
-
-#define __KSYMTAB_ENTRY(sym, sec)					\
+#define __KSYMTAB_ENTRY(sym, sec, ns)					\
 	static const struct kernel_symbol __ksymtab_##sym		\
-	asm("__ksymtab_" #sym)						\
+	asm("__ksymtab_" ns NS_SEPARATOR #sym)				\
 	__attribute__((section("___ksymtab" sec "+" #sym), used))	\
 	__aligned(sizeof(void *))					\
-	= { (unsigned long)&sym, __kstrtab_##sym, NULL }
+	= { (unsigned long)&sym, __kstrtab_##sym, __kstrtabns_##sym }
 
 struct kernel_symbol {
 	unsigned long value;
@@ -97,29 +80,21 @@  struct kernel_symbol {
 
 #ifdef __GENKSYMS__
 
-#define ___EXPORT_SYMBOL(sym,sec)	__GENKSYMS_EXPORT_SYMBOL(sym)
-#define ___EXPORT_SYMBOL_NS(sym,sec,ns)	__GENKSYMS_EXPORT_SYMBOL(sym)
+#define ___EXPORT_SYMBOL(sym, sec, ns)	__GENKSYMS_EXPORT_SYMBOL(sym)
 
 #else
 
-#define ___export_symbol_common(sym, sec)				\
+/* For every exported symbol, place a struct in the __ksymtab section */
+#define ___EXPORT_SYMBOL(sym, sec, ns)				\
 	extern typeof(sym) sym;						\
 	__CRC_SYMBOL(sym, sec);						\
 	static const char __kstrtab_##sym[]				\
 	__attribute__((section("__ksymtab_strings"), used, aligned(1)))	\
-	= #sym								\
-
-/* For every exported symbol, place a struct in the __ksymtab section */
-#define ___EXPORT_SYMBOL_NS(sym, sec, ns)				\
-	___export_symbol_common(sym, sec);				\
+	= #sym;								\
 	static const char __kstrtabns_##sym[]				\
 	__attribute__((section("__ksymtab_strings"), used, aligned(1)))	\
-	= #ns;								\
-	__KSYMTAB_ENTRY_NS(sym, sec, ns)
-
-#define ___EXPORT_SYMBOL(sym, sec)					\
-	___export_symbol_common(sym, sec);				\
-	__KSYMTAB_ENTRY(sym, sec)
+	= ns;								\
+	__KSYMTAB_ENTRY(sym, sec, ns)
 
 #endif
 
@@ -130,8 +105,7 @@  struct kernel_symbol {
  * be reused in other execution contexts such as the UEFI stub or the
  * decompressor.
  */
-#define __EXPORT_SYMBOL_NS(sym, sec, ns)
-#define __EXPORT_SYMBOL(sym, sec)
+#define __EXPORT_SYMBOL(sym, sec, ns)
 
 #elif defined(CONFIG_TRIM_UNUSED_KSYMS)
 
@@ -147,48 +121,38 @@  struct kernel_symbol {
 #define __ksym_marker(sym)	\
 	static int __ksym_marker_##sym[0] __section(".discard.ksym") __used
 
-#define __EXPORT_SYMBOL(sym, sec)				\
+#define __EXPORT_SYMBOL(sym, sec, ns)				\
 	__ksym_marker(sym);					\
-	__cond_export_sym(sym, sec, __is_defined(__KSYM_##sym))
-#define __cond_export_sym(sym, sec, conf)			\
-	___cond_export_sym(sym, sec, conf)
-#define ___cond_export_sym(sym, sec, enabled)			\
-	__cond_export_sym_##enabled(sym, sec)
-#define __cond_export_sym_1(sym, sec) ___EXPORT_SYMBOL(sym, sec)
-#define __cond_export_sym_0(sym, sec) /* nothing */
-
-#define __EXPORT_SYMBOL_NS(sym, sec, ns)				\
-	__ksym_marker(sym);						\
-	__cond_export_ns_sym(sym, sec, ns, __is_defined(__KSYM_##sym))
-#define __cond_export_ns_sym(sym, sec, ns, conf)			\
-	___cond_export_ns_sym(sym, sec, ns, conf)
-#define ___cond_export_ns_sym(sym, sec, ns, enabled)			\
-	__cond_export_ns_sym_##enabled(sym, sec, ns)
-#define __cond_export_ns_sym_1(sym, sec, ns) ___EXPORT_SYMBOL_NS(sym, sec, ns)
-#define __cond_export_ns_sym_0(sym, sec, ns) /* nothing */
+	__cond_export_sym(sym, sec, ns, __is_defined(__KSYM_##sym))
+#define __cond_export_sym(sym, sec, ns, conf)			\
+	___cond_export_sym(sym, sec, ns, conf)
+#define ___cond_export_sym(sym, sec, ns, enabled)		\
+	__cond_export_sym_##enabled(sym, sec, ns)
+#define __cond_export_sym_1(sym, sec, ns) ___EXPORT_SYMBOL(sym, sec, ns)
+#define __cond_export_sym_0(sym, sec, ns) /* nothing */
 
 #else
 
-#define __EXPORT_SYMBOL_NS(sym,sec,ns)	___EXPORT_SYMBOL_NS(sym,sec,ns)
-#define __EXPORT_SYMBOL(sym,sec)	___EXPORT_SYMBOL(sym,sec)
+#define __EXPORT_SYMBOL(sym, sec, ns)	___EXPORT_SYMBOL(sym, sec, ns)
 
 #endif /* CONFIG_MODULES */
 
 #ifdef DEFAULT_SYMBOL_NAMESPACE
-#undef __EXPORT_SYMBOL
-#define __EXPORT_SYMBOL(sym, sec)				\
-	__EXPORT_SYMBOL_NS(sym, sec, DEFAULT_SYMBOL_NAMESPACE)
+#include <linux/stringify.h>
+#define _EXPORT_SYMBOL(sym, sec)	__EXPORT_SYMBOL(sym, sec, __stringify(DEFAULT_SYMBOL_NAMESPACE))
+#else
+#define _EXPORT_SYMBOL(sym, sec)	__EXPORT_SYMBOL(sym, sec, "")
 #endif
 
-#define EXPORT_SYMBOL(sym)		__EXPORT_SYMBOL(sym, "")
-#define EXPORT_SYMBOL_GPL(sym)		__EXPORT_SYMBOL(sym, "_gpl")
-#define EXPORT_SYMBOL_GPL_FUTURE(sym)	__EXPORT_SYMBOL(sym, "_gpl_future")
-#define EXPORT_SYMBOL_NS(sym, ns)	__EXPORT_SYMBOL_NS(sym, "", ns)
-#define EXPORT_SYMBOL_NS_GPL(sym, ns)	__EXPORT_SYMBOL_NS(sym, "_gpl", ns)
+#define EXPORT_SYMBOL(sym)		_EXPORT_SYMBOL(sym, "")
+#define EXPORT_SYMBOL_GPL(sym)		_EXPORT_SYMBOL(sym, "_gpl")
+#define EXPORT_SYMBOL_GPL_FUTURE(sym)	_EXPORT_SYMBOL(sym, "_gpl_future")
+#define EXPORT_SYMBOL_NS(sym, ns)	__EXPORT_SYMBOL(sym, "", #ns)
+#define EXPORT_SYMBOL_NS_GPL(sym, ns)	__EXPORT_SYMBOL(sym, "_gpl", #ns)
 
 #ifdef CONFIG_UNUSED_SYMBOLS
-#define EXPORT_UNUSED_SYMBOL(sym)	__EXPORT_SYMBOL(sym, "_unused")
-#define EXPORT_UNUSED_SYMBOL_GPL(sym)	__EXPORT_SYMBOL(sym, "_unused_gpl")
+#define EXPORT_UNUSED_SYMBOL(sym)	_EXPORT_SYMBOL(sym, "_unused")
+#define EXPORT_UNUSED_SYMBOL_GPL(sym)	_EXPORT_SYMBOL(sym, "_unused_gpl")
 #else
 #define EXPORT_UNUSED_SYMBOL(sym)
 #define EXPORT_UNUSED_SYMBOL_GPL(sym)
diff --git a/kernel/module.c b/kernel/module.c
index 32873bcce738..73f69ff86db5 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1399,7 +1399,7 @@  static int verify_namespace_is_imported(const struct load_info *info,
 	char *imported_namespace;
 
 	namespace = kernel_symbol_namespace(sym);
-	if (namespace) {
+	if (namespace && namespace[0]) {
 		imported_namespace = get_modinfo(info, "import_ns");
 		while (imported_namespace) {
 			if (strcmp(namespace, imported_namespace) == 0)