2019-11-14 17:45:06

by Masahiro Yamada

[permalink] [raw]
Subject: [PATCH 1/6] modpost: add a helper to get data pointed by a symbol

When CONFIG_MODULE_REL_CRCS is enabled, the value of __crc_* is not
an absolute value, but the address to the CRC data embedded in the
.rodata section.

Getting the data pointed by the symbol value is somewhat complex.
Split it out into a new helper, sym_get_data().

I will reuse it to refactor namespace_from_kstrtabns() in the next
commit.

Signed-off-by: Masahiro Yamada <[email protected]>
---

scripts/mod/modpost.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 46d7f695fe7f..cd885573daaf 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -308,6 +308,18 @@ static const char *sec_name(struct elf_info *elf, int secindex)
return sech_name(elf, &elf->sechdrs[secindex]);
}

+static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
+{
+ Elf_Shdr *sechdr = &info->sechdrs[sym->st_shndx];
+ unsigned long offset;
+
+ offset = sym->st_value;
+ if (info->hdr->e_type != ET_REL)
+ offset -= sechdr->sh_addr;
+
+ return (void *)info->hdr + sechdr->sh_offset + offset;
+}
+
#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)

static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
@@ -697,10 +709,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
unsigned int *crcp;

/* symbol points to the CRC in the ELF object */
- crcp = (void *)info->hdr + sym->st_value +
- info->sechdrs[sym->st_shndx].sh_offset -
- (info->hdr->e_type != ET_REL ?
- info->sechdrs[sym->st_shndx].sh_addr : 0);
+ crcp = sym_get_data(info, sym);
crc = TO_NATIVE(*crcp);
}
sym_update_crc(symname + strlen("__crc_"), mod, crc,
--
2.17.1


2019-11-14 17:45:37

by Masahiro Yamada

[permalink] [raw]
Subject: [PATCH 2/6] modpost: refactor namespace_from_kstrtabns() to not hard-code section name

Currently, namespace_from_kstrtabns() relies on the fact that
namespace strings are recorded in the __ksymtab_strings section.
Actually, it is coded in include/linux/export.h, but modpost does
not need to hard-code the section name.

Elf_Sym::st_shndx holds the section number of the relevant section.
Using it is a more portable way to find the namespace string.

sym_get_value() takes care of it, so namespace_from_kstrtabns() can
simply wrap it. Delete the unneeded info->ksymtab_strings .

While I was here, I added more 'const' qualifiers to pointers.

Signed-off-by: Masahiro Yamada <[email protected]>
---

scripts/mod/modpost.c | 10 +++-------
scripts/mod/modpost.h | 1 -
2 files changed, 3 insertions(+), 8 deletions(-)

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index cd885573daaf..d9418c58a8c0 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -356,10 +356,10 @@ static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
return export_unknown;
}

-static const char *namespace_from_kstrtabns(struct elf_info *info,
- Elf_Sym *kstrtabns)
+static const char *namespace_from_kstrtabns(const struct elf_info *info,
+ const Elf_Sym *sym)
{
- char *value = info->ksymtab_strings + kstrtabns->st_value;
+ const char *value = sym_get_data(info, sym);
return value[0] ? value : NULL;
}

@@ -601,10 +601,6 @@ static int parse_elf(struct elf_info *info, const char *filename)
info->export_unused_gpl_sec = i;
else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
info->export_gpl_future_sec = i;
- else if (strcmp(secname, "__ksymtab_strings") == 0)
- info->ksymtab_strings = (void *)hdr +
- sechdrs[i].sh_offset -
- sechdrs[i].sh_addr;

if (sechdrs[i].sh_type == SHT_SYMTAB) {
unsigned int sh_link_idx;
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index fe6652535e4b..64a82d2d85f6 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -143,7 +143,6 @@ struct elf_info {
Elf_Section export_gpl_sec;
Elf_Section export_unused_gpl_sec;
Elf_Section export_gpl_future_sec;
- char *ksymtab_strings;
char *strtab;
char *modinfo;
unsigned int modinfo_len;
--
2.17.1

2019-11-14 17:46:11

by Masahiro Yamada

[permalink] [raw]
Subject: [PATCH 5/6] modpost: do not set ->preloaded for symbols from Module.symvers

Now that there is no overwrap between symbols from ELF files and
ones from Module.symvers.

So, the 'exported twice' warning should be reported irrespective
of where the symbol in question came from.

The exceptional case is external module; in some cases, we build
an external module to provide a different version/variant of the
corresponding in-kernel module, overriding the same set of exported
symbols.

You can see this use-case in upstream; tools/testing/nvdimm/libnvdimm.ko
replaces drivers/nvdimm/libnvdimm.ko in order to link it against mocked
version of core kernel symbols.

So, let's relax the 'exported twice' warning when building external
modules. The multiple export from external modules is warned only
when the previous one is from vmlinux or itself.

With this refactoring, the ugly preloading goes away.

Signed-off-by: Masahiro Yamada <[email protected]>
---

scripts/mod/modpost.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 73bdf27c41fe..06086105011f 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -169,7 +169,6 @@ struct symbol {
unsigned int vmlinux:1; /* 1 if symbol is defined in vmlinux */
unsigned int kernel:1; /* 1 if symbol is from kernel
* (only for external modules) **/
- unsigned int preloaded:1; /* 1 if symbol from Module.symvers */
unsigned int is_static:1; /* 1 if symbol is not global */
enum export export; /* Type of export */
char name[0];
@@ -394,7 +393,8 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod,
if (!s) {
s = new_symbol(name, mod, export);
} else {
- if (!s->preloaded) {
+ if (!external_module || is_vmlinux(s->module->name) ||
+ s->module == mod) {
warn("%s: '%s' exported twice. Previous export was in %s%s\n",
mod->name, name, s->module->name,
is_vmlinux(s->module->name) ? "" : ".ko");
@@ -403,7 +403,6 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod,
s->module = mod;
}
}
- s->preloaded = 0;
s->vmlinux = is_vmlinux(mod->name);
s->kernel = 0;
s->export = export;
@@ -2480,7 +2479,6 @@ static void read_dump(const char *fname, unsigned int kernel)
}
s = sym_add_exported(symname, mod, export_no(export));
s->kernel = kernel;
- s->preloaded = 1;
s->is_static = 0;
sym_set_crc(symname, mod, crc);
sym_update_namespace(symname, namespace);
--
2.17.1

2019-11-14 17:48:54

by Masahiro Yamada

[permalink] [raw]
Subject: Re: [PATCH 2/6] modpost: refactor namespace_from_kstrtabns() to not hard-code section name

(+CC: Matthias, who might be interested)


On Fri, Nov 15, 2019 at 2:42 AM Masahiro Yamada
<[email protected]> wrote:
>
> Currently, namespace_from_kstrtabns() relies on the fact that
> namespace strings are recorded in the __ksymtab_strings section.
> Actually, it is coded in include/linux/export.h, but modpost does
> not need to hard-code the section name.
>
> Elf_Sym::st_shndx holds the section number of the relevant section.
> Using it is a more portable way to find the namespace string.
>
> sym_get_value() takes care of it, so namespace_from_kstrtabns() can
> simply wrap it. Delete the unneeded info->ksymtab_strings .
>
> While I was here, I added more 'const' qualifiers to pointers.
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> scripts/mod/modpost.c | 10 +++-------
> scripts/mod/modpost.h | 1 -
> 2 files changed, 3 insertions(+), 8 deletions(-)
>
> diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
> index cd885573daaf..d9418c58a8c0 100644
> --- a/scripts/mod/modpost.c
> +++ b/scripts/mod/modpost.c
> @@ -356,10 +356,10 @@ static enum export export_from_sec(struct elf_info *elf, unsigned int sec)
> return export_unknown;
> }
>
> -static const char *namespace_from_kstrtabns(struct elf_info *info,
> - Elf_Sym *kstrtabns)
> +static const char *namespace_from_kstrtabns(const struct elf_info *info,
> + const Elf_Sym *sym)
> {
> - char *value = info->ksymtab_strings + kstrtabns->st_value;
> + const char *value = sym_get_data(info, sym);
> return value[0] ? value : NULL;
> }
>
> @@ -601,10 +601,6 @@ static int parse_elf(struct elf_info *info, const char *filename)
> info->export_unused_gpl_sec = i;
> else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
> info->export_gpl_future_sec = i;
> - else if (strcmp(secname, "__ksymtab_strings") == 0)
> - info->ksymtab_strings = (void *)hdr +
> - sechdrs[i].sh_offset -
> - sechdrs[i].sh_addr;
>
> if (sechdrs[i].sh_type == SHT_SYMTAB) {
> unsigned int sh_link_idx;
> diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
> index fe6652535e4b..64a82d2d85f6 100644
> --- a/scripts/mod/modpost.h
> +++ b/scripts/mod/modpost.h
> @@ -143,7 +143,6 @@ struct elf_info {
> Elf_Section export_gpl_sec;
> Elf_Section export_unused_gpl_sec;
> Elf_Section export_gpl_future_sec;
> - char *ksymtab_strings;
> char *strtab;
> char *modinfo;
> unsigned int modinfo_len;
> --
> 2.17.1
>


--
Best Regards
Masahiro Yamada

2019-11-14 17:49:37

by Masahiro Yamada

[permalink] [raw]
Subject: Re: [PATCH 1/6] modpost: add a helper to get data pointed by a symbol

(+CC: Matthias, who might be interested)

On Fri, Nov 15, 2019 at 2:42 AM Masahiro Yamada
<[email protected]> wrote:
>
> When CONFIG_MODULE_REL_CRCS is enabled, the value of __crc_* is not
> an absolute value, but the address to the CRC data embedded in the
> .rodata section.
>
> Getting the data pointed by the symbol value is somewhat complex.
> Split it out into a new helper, sym_get_data().
>
> I will reuse it to refactor namespace_from_kstrtabns() in the next
> commit.
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---
>
> scripts/mod/modpost.c | 17 +++++++++++++----
> 1 file changed, 13 insertions(+), 4 deletions(-)
>
> diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
> index 46d7f695fe7f..cd885573daaf 100644
> --- a/scripts/mod/modpost.c
> +++ b/scripts/mod/modpost.c
> @@ -308,6 +308,18 @@ static const char *sec_name(struct elf_info *elf, int secindex)
> return sech_name(elf, &elf->sechdrs[secindex]);
> }
>
> +static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
> +{
> + Elf_Shdr *sechdr = &info->sechdrs[sym->st_shndx];
> + unsigned long offset;
> +
> + offset = sym->st_value;
> + if (info->hdr->e_type != ET_REL)
> + offset -= sechdr->sh_addr;
> +
> + return (void *)info->hdr + sechdr->sh_offset + offset;
> +}
> +
> #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
>
> static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
> @@ -697,10 +709,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
> unsigned int *crcp;
>
> /* symbol points to the CRC in the ELF object */
> - crcp = (void *)info->hdr + sym->st_value +
> - info->sechdrs[sym->st_shndx].sh_offset -
> - (info->hdr->e_type != ET_REL ?
> - info->sechdrs[sym->st_shndx].sh_addr : 0);
> + crcp = sym_get_data(info, sym);
> crc = TO_NATIVE(*crcp);
> }
> sym_update_crc(symname + strlen("__crc_"), mod, crc,
> --
> 2.17.1
>


--
Best Regards
Masahiro Yamada

2019-11-23 07:26:50

by Masahiro Yamada

[permalink] [raw]
Subject: Re: [PATCH 1/6] modpost: add a helper to get data pointed by a symbol

On Fri, Nov 15, 2019 at 2:42 AM Masahiro Yamada
<[email protected]> wrote:
>
> When CONFIG_MODULE_REL_CRCS is enabled, the value of __crc_* is not
> an absolute value, but the address to the CRC data embedded in the
> .rodata section.
>
> Getting the data pointed by the symbol value is somewhat complex.
> Split it out into a new helper, sym_get_data().
>
> I will reuse it to refactor namespace_from_kstrtabns() in the next
> commit.
>
> Signed-off-by: Masahiro Yamada <[email protected]>
> ---

Series, applied to linux-kbuild.


>
> scripts/mod/modpost.c | 17 +++++++++++++----
> 1 file changed, 13 insertions(+), 4 deletions(-)
>
> diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
> index 46d7f695fe7f..cd885573daaf 100644
> --- a/scripts/mod/modpost.c
> +++ b/scripts/mod/modpost.c
> @@ -308,6 +308,18 @@ static const char *sec_name(struct elf_info *elf, int secindex)
> return sech_name(elf, &elf->sechdrs[secindex]);
> }
>
> +static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
> +{
> + Elf_Shdr *sechdr = &info->sechdrs[sym->st_shndx];
> + unsigned long offset;
> +
> + offset = sym->st_value;
> + if (info->hdr->e_type != ET_REL)
> + offset -= sechdr->sh_addr;
> +
> + return (void *)info->hdr + sechdr->sh_offset + offset;
> +}
> +
> #define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
>
> static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
> @@ -697,10 +709,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
> unsigned int *crcp;
>
> /* symbol points to the CRC in the ELF object */
> - crcp = (void *)info->hdr + sym->st_value +
> - info->sechdrs[sym->st_shndx].sh_offset -
> - (info->hdr->e_type != ET_REL ?
> - info->sechdrs[sym->st_shndx].sh_addr : 0);
> + crcp = sym_get_data(info, sym);
> crc = TO_NATIVE(*crcp);
> }
> sym_update_crc(symname + strlen("__crc_"), mod, crc,
> --
> 2.17.1
>


--
Best Regards
Masahiro Yamada