Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

modpost: detect endianness on run-time

Endianness is currently detected on compile-time, but we can defer this
until run-time. This change avoids re-executing scripts/mod/mk_elfconfig
even if modpost in the linux-headers package needs to be rebuilt for a
foreign architecture.

Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
Reviewed-by: Nicolas Schier <nicolas@fjasle.eu>

+40 -28
-19
scripts/mod/mk_elfconfig.c
··· 8 8 main(int argc, char **argv) 9 9 { 10 10 unsigned char ei[EI_NIDENT]; 11 - union { short s; char c[2]; } endian_test; 12 11 13 12 if (fread(ei, 1, EI_NIDENT, stdin) != EI_NIDENT) { 14 13 fprintf(stderr, "Error: input truncated\n"); ··· 27 28 default: 28 29 exit(1); 29 30 } 30 - switch (ei[EI_DATA]) { 31 - case ELFDATA2LSB: 32 - printf("#define KERNEL_ELFDATA ELFDATA2LSB\n"); 33 - break; 34 - case ELFDATA2MSB: 35 - printf("#define KERNEL_ELFDATA ELFDATA2MSB\n"); 36 - break; 37 - default: 38 - exit(1); 39 - } 40 - 41 - endian_test.s = 0x0102; 42 - if (memcmp(endian_test.c, "\x01\x02", 2) == 0) 43 - printf("#define HOST_ELFDATA ELFDATA2MSB\n"); 44 - else if (memcmp(endian_test.c, "\x02\x01", 2) == 0) 45 - printf("#define HOST_ELFDATA ELFDATA2LSB\n"); 46 - else 47 - exit(1); 48 31 49 32 return 0; 50 33 }
+36
scripts/mod/modpost.c
··· 50 50 51 51 static bool extra_warn; 52 52 53 + bool target_is_big_endian; 54 + bool host_is_big_endian; 55 + 53 56 /* 54 57 * Cut off the warnings when there are too many. This typically occurs when 55 58 * vmlinux is missing. ('make modules' without building vmlinux.) ··· 441 438 /* Not an ELF file - silently ignore it */ 442 439 return 0; 443 440 } 441 + 442 + switch (hdr->e_ident[EI_DATA]) { 443 + case ELFDATA2LSB: 444 + target_is_big_endian = false; 445 + break; 446 + case ELFDATA2MSB: 447 + target_is_big_endian = true; 448 + break; 449 + default: 450 + fatal("target endian is unknown\n"); 451 + } 452 + 444 453 /* Fix endianness in ELF header */ 445 454 hdr->e_type = TO_NATIVE(hdr->e_type); 446 455 hdr->e_machine = TO_NATIVE(hdr->e_machine); ··· 2132 2117 const char *file; 2133 2118 }; 2134 2119 2120 + static void check_host_endian(void) 2121 + { 2122 + static const union { 2123 + short s; 2124 + char c[2]; 2125 + } endian_test = { .c = {0x01, 0x02} }; 2126 + 2127 + switch (endian_test.s) { 2128 + case 0x0102: 2129 + host_is_big_endian = true; 2130 + break; 2131 + case 0x0201: 2132 + host_is_big_endian = false; 2133 + break; 2134 + default: 2135 + fatal("Unknown host endian\n"); 2136 + } 2137 + } 2138 + 2135 2139 int main(int argc, char **argv) 2136 2140 { 2137 2141 struct module *mod; ··· 2214 2180 exit(1); 2215 2181 } 2216 2182 } 2183 + 2184 + check_host_endian(); 2217 2185 2218 2186 list_for_each_entry_safe(dl, dl2, &dump_lists, list) { 2219 2187 read_dump(dl->file);
+4 -9
scripts/mod/modpost.h
··· 62 62 x); \ 63 63 }) 64 64 65 - #if KERNEL_ELFDATA != HOST_ELFDATA 66 - 67 - #define TO_NATIVE(x) (bswap(x)) 68 - 69 - #else /* endianness matches */ 70 - 71 - #define TO_NATIVE(x) (x) 72 - 73 - #endif 65 + #define TO_NATIVE(x) \ 66 + (target_is_big_endian == host_is_big_endian ? x : bswap(x)) 74 67 75 68 #define NOFAIL(ptr) do_nofail((ptr), #ptr) 76 69 ··· 180 187 void get_src_version(const char *modname, char sum[], unsigned sumlen); 181 188 182 189 /* from modpost.c */ 190 + extern bool target_is_big_endian; 191 + extern bool host_is_big_endian; 183 192 char *read_text_file(const char *filename); 184 193 char *get_line(char **stringp); 185 194 void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym);