summaryrefslogtreecommitdiff
path: root/scripts/mod
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/mod')
-rw-r--r--scripts/mod/devicetable-offsets.c1
-rw-r--r--scripts/mod/file2alias.c45
-rw-r--r--scripts/mod/modpost.c134
-rw-r--r--scripts/mod/modpost.h20
4 files changed, 153 insertions, 47 deletions
diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c
index 9c7b404defbd..d3d00e85edf7 100644
--- a/scripts/mod/devicetable-offsets.c
+++ b/scripts/mod/devicetable-offsets.c
@@ -237,7 +237,6 @@ int main(void)
DEVID(typec_device_id);
DEVID_FIELD(typec_device_id, svid);
- DEVID_FIELD(typec_device_id, mode);
DEVID(tee_client_device_id);
DEVID_FIELD(tee_client_device_id, uuid);
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 5b5745f00eb3..00586119a25b 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -132,7 +132,8 @@ struct devtable {
* based at address m.
*/
#define DEF_FIELD(m, devid, f) \
- typeof(((struct devid *)0)->f) f = TO_NATIVE(*(typeof(f) *)((m) + OFF_##devid##_##f))
+ typeof(((struct devid *)0)->f) f = \
+ get_unaligned_native((typeof(f) *)((m) + OFF_##devid##_##f))
/* Define a variable f that holds the address of field f of struct devid
* based at address m. Due to the way typeof works, for a field of type
@@ -600,7 +601,7 @@ static void do_pnp_card_entry(struct module *mod, void *symval)
static void do_pcmcia_entry(struct module *mod, void *symval)
{
char alias[256] = {};
- unsigned int i;
+
DEF_FIELD(symval, pcmcia_device_id, match_flags);
DEF_FIELD(symval, pcmcia_device_id, manf_id);
DEF_FIELD(symval, pcmcia_device_id, card_id);
@@ -609,10 +610,6 @@ static void do_pcmcia_entry(struct module *mod, void *symval)
DEF_FIELD(symval, pcmcia_device_id, device_no);
DEF_FIELD_ADDR(symval, pcmcia_device_id, prod_id_hash);
- for (i=0; i<4; i++) {
- (*prod_id_hash)[i] = TO_NATIVE((*prod_id_hash)[i]);
- }
-
ADD(alias, "m", match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID,
manf_id);
ADD(alias, "c", match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID,
@@ -623,10 +620,14 @@ static void do_pcmcia_entry(struct module *mod, void *symval)
function);
ADD(alias, "pfn", match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO,
device_no);
- ADD(alias, "pa", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1, (*prod_id_hash)[0]);
- ADD(alias, "pb", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2, (*prod_id_hash)[1]);
- ADD(alias, "pc", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, (*prod_id_hash)[2]);
- ADD(alias, "pd", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, (*prod_id_hash)[3]);
+ ADD(alias, "pa", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1,
+ get_unaligned_native(*prod_id_hash + 0));
+ ADD(alias, "pb", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2,
+ get_unaligned_native(*prod_id_hash + 1));
+ ADD(alias, "pc", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3,
+ get_unaligned_native(*prod_id_hash + 2));
+ ADD(alias, "pd", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4,
+ get_unaligned_native(*prod_id_hash + 3));
module_alias_printf(mod, true, "pcmcia:%s", alias);
}
@@ -654,10 +655,9 @@ static void do_input(char *alias,
{
unsigned int i;
- for (i = min / BITS_PER_LONG; i < max / BITS_PER_LONG + 1; i++)
- arr[i] = TO_NATIVE(arr[i]);
- for (i = min; i < max; i++)
- if (arr[i / BITS_PER_LONG] & (1ULL << (i%BITS_PER_LONG)))
+ for (i = min; i <= max; i++)
+ if (get_unaligned_native(arr + i / BITS_PER_LONG) &
+ (1ULL << (i % BITS_PER_LONG)))
sprintf(alias + strlen(alias), "%X,*", i);
}
@@ -812,15 +812,13 @@ static void do_virtio_entry(struct module *mod, void *symval)
* Each byte of the guid will be represented by two hex characters
* in the name.
*/
-
static void do_vmbus_entry(struct module *mod, void *symval)
{
- int i;
DEF_FIELD_ADDR(symval, hv_vmbus_device_id, guid);
- char guid_name[(sizeof(*guid) + 1) * 2];
+ char guid_name[sizeof(*guid) * 2 + 1];
- for (i = 0; i < (sizeof(*guid) * 2); i += 2)
- sprintf(&guid_name[i], "%02x", TO_NATIVE((guid->b)[i/2]));
+ for (int i = 0; i < sizeof(*guid); i++)
+ sprintf(&guid_name[i * 2], "%02x", guid->b[i]);
module_alias_printf(mod, false, "vmbus:%s", guid_name);
}
@@ -1221,17 +1219,12 @@ static void do_tbsvc_entry(struct module *mod, void *symval)
module_alias_printf(mod, true, "tbsvc:%s", alias);
}
-/* Looks like: typec:idNmN */
+/* Looks like: typec:idN */
static void do_typec_entry(struct module *mod, void *symval)
{
- char alias[256] = {};
-
DEF_FIELD(symval, typec_device_id, svid);
- DEF_FIELD(symval, typec_device_id, mode);
-
- ADD(alias, "m", mode != TYPEC_ANY_MODE, mode);
- module_alias_printf(mod, false, "typec:id%04X%s", svid, alias);
+ module_alias_printf(mod, false, "typec:id%04X", svid);
}
/* Looks like: tee:uuid */
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 94ee49207a45..c35d22607978 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -33,6 +33,10 @@ static bool module_enabled;
static bool modversions;
/* Is CONFIG_MODULE_SRCVERSION_ALL set? */
static bool all_versions;
+/* Is CONFIG_BASIC_MODVERSIONS set? */
+static bool basic_modversions;
+/* Is CONFIG_EXTENDED_MODVERSIONS set? */
+static bool extended_modversions;
/* If we are modposting external module set to 1 */
static bool external_module;
/* Only warn about unresolved symbols */
@@ -186,8 +190,8 @@ static struct module *new_module(const char *name, size_t namelen)
/*
* Set mod->is_gpl_compatible to true by default. If MODULE_LICENSE()
- * is missing, do not check the use for EXPORT_SYMBOL_GPL() becasue
- * modpost will exit wiht error anyway.
+ * is missing, do not check the use for EXPORT_SYMBOL_GPL() because
+ * modpost will exit with an error anyway.
*/
mod->is_gpl_compatible = true;
@@ -503,6 +507,9 @@ static int parse_elf(struct elf_info *info, const char *filename)
info->modinfo_len = sechdrs[i].sh_size;
} else if (!strcmp(secname, ".export_symbol")) {
info->export_symbol_secndx = i;
+ } else if (!strcmp(secname, ".no_trim_symbol")) {
+ info->no_trim_symbol = (void *)hdr + sechdrs[i].sh_offset;
+ info->no_trim_symbol_len = sechdrs[i].sh_size;
}
if (sechdrs[i].sh_type == SHT_SYMTAB) {
@@ -1138,9 +1145,9 @@ static Elf_Addr addend_386_rel(uint32_t *location, unsigned int r_type)
{
switch (r_type) {
case R_386_32:
- return TO_NATIVE(*location);
+ return get_unaligned_native(location);
case R_386_PC32:
- return TO_NATIVE(*location) + 4;
+ return get_unaligned_native(location) + 4;
}
return (Elf_Addr)(-1);
@@ -1161,24 +1168,24 @@ static Elf_Addr addend_arm_rel(void *loc, Elf_Sym *sym, unsigned int r_type)
switch (r_type) {
case R_ARM_ABS32:
case R_ARM_REL32:
- inst = TO_NATIVE(*(uint32_t *)loc);
+ inst = get_unaligned_native((uint32_t *)loc);
return inst + sym->st_value;
case R_ARM_MOVW_ABS_NC:
case R_ARM_MOVT_ABS:
- inst = TO_NATIVE(*(uint32_t *)loc);
+ inst = get_unaligned_native((uint32_t *)loc);
offset = sign_extend32(((inst & 0xf0000) >> 4) | (inst & 0xfff),
15);
return offset + sym->st_value;
case R_ARM_PC24:
case R_ARM_CALL:
case R_ARM_JUMP24:
- inst = TO_NATIVE(*(uint32_t *)loc);
+ inst = get_unaligned_native((uint32_t *)loc);
offset = sign_extend32((inst & 0x00ffffff) << 2, 25);
return offset + sym->st_value + 8;
case R_ARM_THM_MOVW_ABS_NC:
case R_ARM_THM_MOVT_ABS:
- upper = TO_NATIVE(*(uint16_t *)loc);
- lower = TO_NATIVE(*((uint16_t *)loc + 1));
+ upper = get_unaligned_native((uint16_t *)loc);
+ lower = get_unaligned_native((uint16_t *)loc + 1);
offset = sign_extend32(((upper & 0x000f) << 12) |
((upper & 0x0400) << 1) |
((lower & 0x7000) >> 4) |
@@ -1195,8 +1202,8 @@ static Elf_Addr addend_arm_rel(void *loc, Elf_Sym *sym, unsigned int r_type)
* imm11 = lower[10:0]
* imm32 = SignExtend(S:J2:J1:imm6:imm11:'0')
*/
- upper = TO_NATIVE(*(uint16_t *)loc);
- lower = TO_NATIVE(*((uint16_t *)loc + 1));
+ upper = get_unaligned_native((uint16_t *)loc);
+ lower = get_unaligned_native((uint16_t *)loc + 1);
sign = (upper >> 10) & 1;
j1 = (lower >> 13) & 1;
@@ -1219,8 +1226,8 @@ static Elf_Addr addend_arm_rel(void *loc, Elf_Sym *sym, unsigned int r_type)
* I2 = NOT(J2 XOR S)
* imm32 = SignExtend(S:I1:I2:imm10:imm11:'0')
*/
- upper = TO_NATIVE(*(uint16_t *)loc);
- lower = TO_NATIVE(*((uint16_t *)loc + 1));
+ upper = get_unaligned_native((uint16_t *)loc);
+ lower = get_unaligned_native((uint16_t *)loc + 1);
sign = (upper >> 10) & 1;
j1 = (lower >> 13) & 1;
@@ -1241,7 +1248,7 @@ static Elf_Addr addend_mips_rel(uint32_t *location, unsigned int r_type)
{
uint32_t inst;
- inst = TO_NATIVE(*location);
+ inst = get_unaligned_native(location);
switch (r_type) {
case R_MIPS_LO16:
return inst & 0xffff;
@@ -1562,6 +1569,14 @@ static void read_symbols(const char *modname)
/* strip trailing .o */
mod = new_module(modname, strlen(modname) - strlen(".o"));
+ /* save .no_trim_symbol section for later use */
+ if (info.no_trim_symbol_len) {
+ mod->no_trim_symbol = xmalloc(info.no_trim_symbol_len);
+ memcpy(mod->no_trim_symbol, info.no_trim_symbol,
+ info.no_trim_symbol_len);
+ mod->no_trim_symbol_len = info.no_trim_symbol_len;
+ }
+
if (!mod->is_vmlinux) {
license = get_modinfo(&info, "license");
if (!license)
@@ -1724,6 +1739,28 @@ static void handle_white_list_exports(const char *white_list)
free(buf);
}
+/*
+ * Keep symbols recorded in the .no_trim_symbol section. This is necessary to
+ * prevent CONFIG_TRIM_UNUSED_KSYMS from dropping EXPORT_SYMBOL because
+ * symbol_get() relies on the symbol being present in the ksymtab for lookups.
+ */
+static void keep_no_trim_symbols(struct module *mod)
+{
+ unsigned long size = mod->no_trim_symbol_len;
+
+ for (char *s = mod->no_trim_symbol; s; s = next_string(s , &size)) {
+ struct symbol *sym;
+
+ /*
+ * If find_symbol() returns NULL, this symbol is not provided
+ * by any module, and symbol_get() will fail.
+ */
+ sym = find_symbol(s);
+ if (sym)
+ sym->used = true;
+ }
+}
+
static void check_modname_len(struct module *mod)
{
const char *mod_name;
@@ -1806,13 +1843,56 @@ static void add_exported_symbols(struct buffer *buf, struct module *mod)
}
/**
+ * Record CRCs for unresolved symbols, supporting long names
+ */
+static void add_extended_versions(struct buffer *b, struct module *mod)
+{
+ struct symbol *s;
+
+ if (!extended_modversions)
+ return;
+
+ buf_printf(b, "\n");
+ buf_printf(b, "static const u32 ____version_ext_crcs[]\n");
+ buf_printf(b, "__used __section(\"__version_ext_crcs\") = {\n");
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
+ if (!s->module)
+ continue;
+ if (!s->crc_valid) {
+ warn("\"%s\" [%s.ko] has no CRC!\n",
+ s->name, mod->name);
+ continue;
+ }
+ buf_printf(b, "\t0x%08x,\n", s->crc);
+ }
+ buf_printf(b, "};\n");
+
+ buf_printf(b, "static const char ____version_ext_names[]\n");
+ buf_printf(b, "__used __section(\"__version_ext_names\") =\n");
+ list_for_each_entry(s, &mod->unresolved_symbols, list) {
+ if (!s->module)
+ continue;
+ if (!s->crc_valid)
+ /*
+ * We already warned on this when producing the crc
+ * table.
+ * We need to skip its name too, as the indexes in
+ * both tables need to align.
+ */
+ continue;
+ buf_printf(b, "\t\"%s\\0\"\n", s->name);
+ }
+ buf_printf(b, ";\n");
+}
+
+/**
* Record CRCs for unresolved symbols
**/
static void add_versions(struct buffer *b, struct module *mod)
{
struct symbol *s;
- if (!modversions)
+ if (!basic_modversions)
return;
buf_printf(b, "\n");
@@ -1828,11 +1908,16 @@ static void add_versions(struct buffer *b, struct module *mod)
continue;
}
if (strlen(s->name) >= MODULE_NAME_LEN) {
- error("too long symbol \"%s\" [%s.ko]\n",
- s->name, mod->name);
- break;
+ if (extended_modversions) {
+ /* this symbol will only be in the extended info */
+ continue;
+ } else {
+ error("too long symbol \"%s\" [%s.ko]\n",
+ s->name, mod->name);
+ break;
+ }
}
- buf_printf(b, "\t{ %#8x, \"%s\" },\n",
+ buf_printf(b, "\t{ 0x%08x, \"%s\" },\n",
s->crc, s->name);
}
@@ -1961,6 +2046,7 @@ static void write_mod_c_file(struct module *mod)
add_header(&buf, mod);
add_exported_symbols(&buf, mod);
add_versions(&buf, mod);
+ add_extended_versions(&buf, mod);
add_depends(&buf, mod);
buf_printf(&buf, "\n");
@@ -2126,7 +2212,7 @@ int main(int argc, char **argv)
LIST_HEAD(dump_lists);
struct dump_list *dl, *dl2;
- while ((opt = getopt(argc, argv, "ei:MmnT:to:au:WwENd:")) != -1) {
+ while ((opt = getopt(argc, argv, "ei:MmnT:to:au:WwENd:xb")) != -1) {
switch (opt) {
case 'e':
external_module = true;
@@ -2175,6 +2261,12 @@ int main(int argc, char **argv)
case 'd':
missing_namespace_deps = optarg;
break;
+ case 'b':
+ basic_modversions = true;
+ break;
+ case 'x':
+ extended_modversions = true;
+ break;
default:
exit(1);
}
@@ -2195,6 +2287,8 @@ int main(int argc, char **argv)
read_symbols_from_files(files_source);
list_for_each_entry(mod, &modules, list) {
+ keep_no_trim_symbols(mod);
+
if (mod->dump_file || mod->is_vmlinux)
continue;
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index 8b72c227ebf4..59366f456b76 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -65,6 +65,20 @@
#define TO_NATIVE(x) \
(target_is_big_endian == host_is_big_endian ? x : bswap(x))
+#define __get_unaligned_t(type, ptr) ({ \
+ const struct { type x; } __attribute__((__packed__)) *__pptr = \
+ (typeof(__pptr))(ptr); \
+ __pptr->x; \
+})
+
+#define get_unaligned(ptr) __get_unaligned_t(typeof(*(ptr)), (ptr))
+
+#define get_unaligned_native(ptr) \
+({ \
+ typeof(*(ptr)) _val = get_unaligned(ptr); \
+ TO_NATIVE(_val); \
+})
+
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
@@ -97,6 +111,8 @@ struct module_alias {
*
* @dump_file: path to the .symvers file if loaded from a file
* @aliases: list head for module_aliases
+ * @no_trim_symbol: .no_trim_symbol section data
+ * @no_trim_symbol_len: length of the .no_trim_symbol section
*/
struct module {
struct list_head list;
@@ -114,6 +130,8 @@ struct module {
// Actual imported namespaces
struct list_head imported_namespaces;
struct list_head aliases;
+ char *no_trim_symbol;
+ unsigned int no_trim_symbol_len;
char name[];
};
@@ -127,6 +145,8 @@ struct elf_info {
char *strtab;
char *modinfo;
unsigned int modinfo_len;
+ char *no_trim_symbol;
+ unsigned int no_trim_symbol_len;
/* support for 32bit section numbers */