Skip to content

Commit f292d87

Browse files
committed
modpost: extract symbol versions from *.cmd files
Currently, CONFIG_MODVERSIONS needs extra link to embed the symbol versions into ELF objects. Then, modpost extracts the version CRCs from them. The following figures show how it currently works, and how I am trying to change it. Current implementation ====================== |----------| embed CRC -------------------------->| final | $(CC) $(LD) / |---------| | link for | -----> *.o -------> *.o -->| modpost | | vmlinux | / / | |-- *.mod.c -->| or | / genksyms / |---------| | module | *.c ------> *.symversions |----------| Genksyms outputs the calculated CRCs in the form of linker script (*.symversions), which is used by $(LD) to update the object. If CONFIG_LTO_CLANG=y, the build process is much more complex. Embedding the CRCs is postponed until the LLVM bitcode is converted into ELF, creating another intermediate *.prelink.o. However, this complexity is unneeded. There is no reason why we must embed version CRCs in objects so early. There is final link stage for vmlinux (scripts/link-vmlinux.sh) and modules (scripts/Makefile.modfinal). We can link CRCs at the very last moment. New implementation ================== |----------| --------------------------------------->| final | $(CC) / |---------| | link for | -----> *.o ---->| | | vmlinux | / | modpost |--- .vmlinux.export.c -->| or | / genksyms | |--- *.mod.c ------------>| module | *.c ------> *.cmd -->|---------| |----------| Pass the symbol versions to modpost as separate text data, which are available in *.cmd files. This commit changes modpost to extract CRCs from *.cmd files instead of from ELF objects. Signed-off-by: Masahiro Yamada <[email protected]> Reviewed-by: Nicolas Schier <[email protected]> Tested-by: Nathan Chancellor <[email protected]> Reviewed-by: Sami Tolvanen <[email protected]> Tested-by: Sedat Dilek <[email protected]> # LLVM-14 (x86-64)
1 parent 69c4cc9 commit f292d87

File tree

1 file changed

+131
-48
lines changed

1 file changed

+131
-48
lines changed

scripts/mod/modpost.c

Lines changed: 131 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -383,19 +383,10 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod,
383383
return s;
384384
}
385385

386-
static void sym_set_crc(const char *name, unsigned int crc)
386+
static void sym_set_crc(struct symbol *sym, unsigned int crc)
387387
{
388-
struct symbol *s = find_symbol(name);
389-
390-
/*
391-
* Ignore stand-alone __crc_*, which might be auto-generated symbols
392-
* such as __*_veneer in ARM ELF.
393-
*/
394-
if (!s)
395-
return;
396-
397-
s->crc = crc;
398-
s->crc_valid = true;
388+
sym->crc = crc;
389+
sym->crc_valid = true;
399390
}
400391

401392
static void *grab_file(const char *filename, size_t *size)
@@ -618,33 +609,6 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname)
618609
return 0;
619610
}
620611

621-
static void handle_modversion(const struct module *mod,
622-
const struct elf_info *info,
623-
const Elf_Sym *sym, const char *symname)
624-
{
625-
unsigned int crc;
626-
627-
if (sym->st_shndx == SHN_UNDEF) {
628-
warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n"
629-
"Is \"%s\" prototyped in <asm/asm-prototypes.h>?\n",
630-
symname, mod->name, mod->is_vmlinux ? "" : ".ko",
631-
symname);
632-
633-
return;
634-
}
635-
636-
if (sym->st_shndx == SHN_ABS) {
637-
crc = sym->st_value;
638-
} else {
639-
unsigned int *crcp;
640-
641-
/* symbol points to the CRC in the ELF object */
642-
crcp = sym_get_data(info, sym);
643-
crc = TO_NATIVE(*crcp);
644-
}
645-
sym_set_crc(symname, crc);
646-
}
647-
648612
static void handle_symbol(struct module *mod, struct elf_info *info,
649613
const Elf_Sym *sym, const char *symname)
650614
{
@@ -1952,6 +1916,104 @@ static char *remove_dot(char *s)
19521916
return s;
19531917
}
19541918

1919+
/*
1920+
* The CRCs are recorded in .*.cmd files in the form of:
1921+
* #SYMVER <name> <crc>
1922+
*/
1923+
static void extract_crcs_for_object(const char *object, struct module *mod)
1924+
{
1925+
char cmd_file[PATH_MAX];
1926+
char *buf, *p;
1927+
const char *base;
1928+
int dirlen, ret;
1929+
1930+
base = strrchr(object, '/');
1931+
if (base) {
1932+
base++;
1933+
dirlen = base - object;
1934+
} else {
1935+
dirlen = 0;
1936+
base = object;
1937+
}
1938+
1939+
ret = snprintf(cmd_file, sizeof(cmd_file), "%.*s.%s.cmd",
1940+
dirlen, object, base);
1941+
if (ret >= sizeof(cmd_file)) {
1942+
error("%s: too long path was truncated\n", cmd_file);
1943+
return;
1944+
}
1945+
1946+
buf = read_text_file(cmd_file);
1947+
p = buf;
1948+
1949+
while ((p = strstr(p, "\n#SYMVER "))) {
1950+
char *name;
1951+
size_t namelen;
1952+
unsigned int crc;
1953+
struct symbol *sym;
1954+
1955+
name = p + strlen("\n#SYMVER ");
1956+
1957+
p = strchr(name, ' ');
1958+
if (!p)
1959+
break;
1960+
1961+
namelen = p - name;
1962+
p++;
1963+
1964+
if (!isdigit(*p))
1965+
continue; /* skip this line */
1966+
1967+
crc = strtol(p, &p, 0);
1968+
if (*p != '\n')
1969+
continue; /* skip this line */
1970+
1971+
name[namelen] = '\0';
1972+
1973+
/*
1974+
* sym_find_with_module() may return NULL here.
1975+
* It typically occurs when CONFIG_TRIM_UNUSED_KSYMS=y.
1976+
* Since commit e1327a127703, genksyms calculates CRCs of all
1977+
* symbols, including trimmed ones. Ignore orphan CRCs.
1978+
*/
1979+
sym = sym_find_with_module(name, mod);
1980+
if (sym)
1981+
sym_set_crc(sym, crc);
1982+
}
1983+
1984+
free(buf);
1985+
}
1986+
1987+
/*
1988+
* The symbol versions (CRC) are recorded in the .*.cmd files.
1989+
* Parse them to retrieve CRCs for the current module.
1990+
*/
1991+
static void mod_set_crcs(struct module *mod)
1992+
{
1993+
char objlist[PATH_MAX];
1994+
char *buf, *p, *obj;
1995+
int ret;
1996+
1997+
if (mod->is_vmlinux) {
1998+
strcpy(objlist, ".vmlinux.objs");
1999+
} else {
2000+
/* objects for a module are listed in the *.mod file. */
2001+
ret = snprintf(objlist, sizeof(objlist), "%s.mod", mod->name);
2002+
if (ret >= sizeof(objlist)) {
2003+
error("%s: too long path was truncated\n", objlist);
2004+
return;
2005+
}
2006+
}
2007+
2008+
buf = read_text_file(objlist);
2009+
p = buf;
2010+
2011+
while ((obj = strsep(&p, "\n")) && obj[0])
2012+
extract_crcs_for_object(obj, mod);
2013+
2014+
free(buf);
2015+
}
2016+
19552017
static void read_symbols(const char *modname)
19562018
{
19572019
const char *symname;
@@ -2012,9 +2074,6 @@ static void read_symbols(const char *modname)
20122074
if (strstarts(symname, "__kstrtabns_"))
20132075
sym_update_namespace(symname + strlen("__kstrtabns_"),
20142076
sym_get_data(&info, sym));
2015-
if (strstarts(symname, "__crc_"))
2016-
handle_modversion(mod, &info, sym,
2017-
symname + strlen("__crc_"));
20182077
}
20192078

20202079
// check for static EXPORT_SYMBOL_* functions && global vars
@@ -2042,12 +2101,17 @@ static void read_symbols(const char *modname)
20422101

20432102
parse_elf_finish(&info);
20442103

2045-
/* Our trick to get versioning for module struct etc. - it's
2046-
* never passed as an argument to an exported function, so
2047-
* the automatic versioning doesn't pick it up, but it's really
2048-
* important anyhow */
2049-
if (modversions)
2104+
if (modversions) {
2105+
/*
2106+
* Our trick to get versioning for module struct etc. - it's
2107+
* never passed as an argument to an exported function, so
2108+
* the automatic versioning doesn't pick it up, but it's really
2109+
* important anyhow.
2110+
*/
20502111
sym_add_unresolved("module_layout", mod, false);
2112+
2113+
mod_set_crcs(mod);
2114+
}
20512115
}
20522116

20532117
static void read_symbols_from_files(const char *filename)
@@ -2204,6 +2268,23 @@ static void add_header(struct buffer *b, struct module *mod)
22042268
buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
22052269
}
22062270

2271+
static void check_symversions(struct module *mod)
2272+
{
2273+
struct symbol *sym;
2274+
2275+
if (!modversions)
2276+
return;
2277+
2278+
list_for_each_entry(sym, &mod->exported_symbols, list) {
2279+
if (!sym->crc_valid) {
2280+
warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n"
2281+
"Is \"%s\" prototyped in <asm/asm-prototypes.h>?\n",
2282+
sym->name, mod->name, mod->is_vmlinux ? "" : ".ko",
2283+
sym->name);
2284+
}
2285+
}
2286+
}
2287+
22072288
/**
22082289
* Record CRCs for unresolved symbols
22092290
**/
@@ -2419,7 +2500,7 @@ static void read_dump(const char *fname)
24192500
}
24202501
s = sym_add_exported(symname, mod, gpl_only);
24212502
s->is_static = false;
2422-
sym_set_crc(symname, crc);
2503+
sym_set_crc(s, crc);
24232504
sym_update_namespace(symname, namespace);
24242505
}
24252506
free(buf);
@@ -2545,6 +2626,8 @@ int main(int argc, char **argv)
25452626
if (mod->from_dump)
25462627
continue;
25472628

2629+
check_symversions(mod);
2630+
25482631
if (!mod->is_vmlinux)
25492632
write_mod_c_file(mod);
25502633
}

0 commit comments

Comments
 (0)