diff options
Diffstat (limited to 'modutils/insmod.c')
-rw-r--r-- | modutils/insmod.c | 175 |
1 files changed, 142 insertions, 33 deletions
diff --git a/modutils/insmod.c b/modutils/insmod.c index 2fa48083b..f53fdadeb 100644 --- a/modutils/insmod.c +++ b/modutils/insmod.c | |||
@@ -3,12 +3,14 @@ | |||
3 | * Mini insmod implementation for busybox | 3 | * Mini insmod implementation for busybox |
4 | * | 4 | * |
5 | * This version of insmod supports x86, ARM, SH3/4, powerpc, m68k, | 5 | * This version of insmod supports x86, ARM, SH3/4, powerpc, m68k, |
6 | * and MIPS. | 6 | * MIPS, and v850e. |
7 | * | 7 | * |
8 | * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen | 8 | * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen |
9 | * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org> | 9 | * Copyright (C) 1999,2000,2001,2002 by Erik Andersen <andersee@debian.org> |
10 | * and Ron Alder <alder@lineo.com> | 10 | * and Ron Alder <alder@lineo.com> |
11 | * | 11 | * |
12 | * Modified by Miles Bader <miles@gnu.org> to support the NEC V850E. | ||
13 | * | ||
12 | * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4 | 14 | * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4 |
13 | * and (theoretically) SH3. I have only tested SH4 in little endian mode. | 15 | * and (theoretically) SH3. I have only tested SH4 in little endian mode. |
14 | * | 16 | * |
@@ -104,6 +106,11 @@ | |||
104 | // neither used | 106 | // neither used |
105 | #endif | 107 | #endif |
106 | 108 | ||
109 | #if defined (__v850e__) | ||
110 | #define CONFIG_USE_PLT_ENTRIES | ||
111 | #define CONFIG_PLT_ENTRY_SIZE 8 | ||
112 | #endif | ||
113 | |||
107 | //---------------------------------------------------------------------------- | 114 | //---------------------------------------------------------------------------- |
108 | //--------modutils module.h, lines 45-242 | 115 | //--------modutils module.h, lines 45-242 |
109 | //---------------------------------------------------------------------------- | 116 | //---------------------------------------------------------------------------- |
@@ -133,7 +140,7 @@ | |||
133 | #ifndef MODUTILS_MODULE_H | 140 | #ifndef MODUTILS_MODULE_H |
134 | static const int MODUTILS_MODULE_H = 1; | 141 | static const int MODUTILS_MODULE_H = 1; |
135 | 142 | ||
136 | #ident "$Id: insmod.c,v 1.78 2001/12/29 04:15:13 andersen Exp $" | 143 | #ident "$Id: insmod.c,v 1.79 2002/04/01 09:34:25 miles Exp $" |
137 | 144 | ||
138 | /* This file contains the structures used by the 2.0 and 2.1 kernels. | 145 | /* This file contains the structures used by the 2.0 and 2.1 kernels. |
139 | We do not use the kernel headers directly because we do not wish | 146 | We do not use the kernel headers directly because we do not wish |
@@ -350,7 +357,7 @@ int delete_module(const char *); | |||
350 | #ifndef MODUTILS_OBJ_H | 357 | #ifndef MODUTILS_OBJ_H |
351 | static const int MODUTILS_OBJ_H = 1; | 358 | static const int MODUTILS_OBJ_H = 1; |
352 | 359 | ||
353 | #ident "$Id: insmod.c,v 1.78 2001/12/29 04:15:13 andersen Exp $" | 360 | #ident "$Id: insmod.c,v 1.79 2002/04/01 09:34:25 miles Exp $" |
354 | 361 | ||
355 | /* The relocatable object is manipulated using elfin types. */ | 362 | /* The relocatable object is manipulated using elfin types. */ |
356 | 363 | ||
@@ -449,6 +456,19 @@ static const int MODUTILS_OBJ_H = 1; | |||
449 | #define SHT_RELM SHT_RELA | 456 | #define SHT_RELM SHT_RELA |
450 | #define Elf32_RelM Elf32_Rela | 457 | #define Elf32_RelM Elf32_Rela |
451 | 458 | ||
459 | #elif defined (__v850e__) | ||
460 | |||
461 | #ifndef EM_CYGNUS_V850 /* grumble */ | ||
462 | #define EM_CYGNUS_V850 0x9080 | ||
463 | #endif | ||
464 | |||
465 | #define MATCH_MACHINE(x) ((x) == EM_V850 || (x) == EM_CYGNUS_V850) | ||
466 | #define SHT_RELM SHT_RELA | ||
467 | #define Elf32_RelM Elf32_Rela | ||
468 | #define ELFDATAM ELFDATA2LSB | ||
469 | |||
470 | #define SYMBOL_PREFIX "_" | ||
471 | |||
452 | #else | 472 | #else |
453 | #error Sorry, but insmod.c does not yet support this architecture... | 473 | #error Sorry, but insmod.c does not yet support this architecture... |
454 | #endif | 474 | #endif |
@@ -626,6 +646,12 @@ static int arch_init_module (struct obj_file *f, struct new_module *); | |||
626 | 646 | ||
627 | 647 | ||
628 | 648 | ||
649 | /* SPFX is always a string, so it can be concatenated to string constants. */ | ||
650 | #ifdef SYMBOL_PREFIX | ||
651 | #define SPFX SYMBOL_PREFIX | ||
652 | #else | ||
653 | #define SPFX "" | ||
654 | #endif | ||
629 | 655 | ||
630 | 656 | ||
631 | #define _PATH_MODULES "/lib/modules" | 657 | #define _PATH_MODULES "/lib/modules" |
@@ -828,9 +854,22 @@ arch_apply_relocation(struct obj_file *f, | |||
828 | case R_PPC_NONE: | 854 | case R_PPC_NONE: |
829 | #elif defined(__mips__) | 855 | #elif defined(__mips__) |
830 | case R_MIPS_NONE: | 856 | case R_MIPS_NONE: |
857 | #elif defined (__v850e__) | ||
858 | case R_V850_NONE: | ||
831 | #endif | 859 | #endif |
832 | break; | 860 | break; |
833 | 861 | ||
862 | #if defined (__v850e__) | ||
863 | case R_V850_32: | ||
864 | /* We write two shorts instead of a long because even | ||
865 | 32-bit insns only need half-word alignment, but | ||
866 | 32-bit data needs to be long-word aligned. */ | ||
867 | v += ((unsigned short *)loc)[0]; | ||
868 | v += ((unsigned short *)loc)[1] << 16; | ||
869 | ((unsigned short *)loc)[0] = v & 0xffff; | ||
870 | ((unsigned short *)loc)[1] = (v >> 16) & 0xffff; | ||
871 | break; | ||
872 | #else /* !__v850e__ */ | ||
834 | #if defined(__sh__) | 873 | #if defined(__sh__) |
835 | case R_SH_DIR32: | 874 | case R_SH_DIR32: |
836 | #elif defined(__arm__) | 875 | #elif defined(__arm__) |
@@ -846,6 +885,8 @@ arch_apply_relocation(struct obj_file *f, | |||
846 | #endif | 885 | #endif |
847 | *loc += v; | 886 | *loc += v; |
848 | break; | 887 | break; |
888 | #endif /* __v850e__ */ | ||
889 | |||
849 | #if defined(__mc68000__) | 890 | #if defined(__mc68000__) |
850 | case R_68K_8: | 891 | case R_68K_8: |
851 | if (v > 0xff) | 892 | if (v > 0xff) |
@@ -1001,6 +1042,9 @@ arch_apply_relocation(struct obj_file *f, | |||
1001 | #if defined(__powerpc__) | 1042 | #if defined(__powerpc__) |
1002 | case R_PPC_REL24: | 1043 | case R_PPC_REL24: |
1003 | #endif | 1044 | #endif |
1045 | #if defined (__v850e__) | ||
1046 | case R_V850_22_PCREL: | ||
1047 | #endif | ||
1004 | /* find the plt entry and initialize it if necessary */ | 1048 | /* find the plt entry and initialize it if necessary */ |
1005 | assert(isym != NULL); | 1049 | assert(isym != NULL); |
1006 | 1050 | ||
@@ -1021,18 +1065,33 @@ arch_apply_relocation(struct obj_file *f, | |||
1021 | ip[2] = 0x7d6903a6; /* mtctr r11 */ | 1065 | ip[2] = 0x7d6903a6; /* mtctr r11 */ |
1022 | ip[3] = 0x4e800420; /* bctr */ | 1066 | ip[3] = 0x4e800420; /* bctr */ |
1023 | #endif | 1067 | #endif |
1068 | #if defined (__v850e__) | ||
1069 | /* We have to trash a register, so we assume that any control | ||
1070 | transfer more than 21-bits away must be a function call | ||
1071 | (so we can use a call-clobbered register). */ | ||
1072 | ip[0] = 0x0621 + ((v & 0xffff) << 16); /* mov sym, r1 ... */ | ||
1073 | ip[1] = ((v >> 16) & 0xffff) + 0x610000; /* ...; jmp r1 */ | ||
1074 | #endif | ||
1024 | pe->inited = 1; | 1075 | pe->inited = 1; |
1025 | } | 1076 | } |
1026 | 1077 | ||
1027 | /* relative distance to target */ | 1078 | /* relative distance to target */ |
1028 | v -= dot; | 1079 | v -= dot; |
1029 | /* if the target is too far away.... */ | 1080 | /* if the target is too far away.... */ |
1030 | if ((int)v < -0x02000000 || (int)v >= 0x02000000) { | 1081 | #if defined (__arm__) || defined (__powerpc__) |
1031 | /* go via the plt */ | 1082 | if ((int)v < -0x02000000 || (int)v >= 0x02000000) |
1032 | v = plt + pe->offset - dot; | 1083 | #elif defined (__v850e__) |
1033 | } | 1084 | if ((Elf32_Sword)v > 0x1fffff || (Elf32_Sword)v < (Elf32_Sword)-0x200000) |
1085 | #endif | ||
1086 | /* go via the plt */ | ||
1087 | v = plt + pe->offset - dot; | ||
1088 | |||
1089 | #if defined (__v850e__) | ||
1090 | if (v & 1) | ||
1091 | #else | ||
1034 | if (v & 3) | 1092 | if (v & 3) |
1035 | ret = obj_reloc_dangerous; | 1093 | #endif |
1094 | ret = obj_reloc_dangerous; | ||
1036 | 1095 | ||
1037 | /* merge the offset into the instruction. */ | 1096 | /* merge the offset into the instruction. */ |
1038 | #if defined(__arm__) | 1097 | #if defined(__arm__) |
@@ -1044,6 +1103,17 @@ arch_apply_relocation(struct obj_file *f, | |||
1044 | #if defined(__powerpc__) | 1103 | #if defined(__powerpc__) |
1045 | *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc); | 1104 | *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc); |
1046 | #endif | 1105 | #endif |
1106 | #if defined (__v850e__) | ||
1107 | /* We write two shorts instead of a long because even 32-bit insns | ||
1108 | only need half-word alignment, but the 32-bit data write needs | ||
1109 | to be long-word aligned. */ | ||
1110 | ((unsigned short *)loc)[0] = | ||
1111 | (*(unsigned short *)loc & 0xffc0) /* opcode + reg */ | ||
1112 | | ((v >> 16) & 0x3f); /* offs high part */ | ||
1113 | ((unsigned short *)loc)[1] = | ||
1114 | (v & 0xffff); /* offs low part */ | ||
1115 | #endif | ||
1116 | |||
1047 | break; | 1117 | break; |
1048 | #endif /* CONFIG_USE_PLT_ENTRIES */ | 1118 | #endif /* CONFIG_USE_PLT_ENTRIES */ |
1049 | 1119 | ||
@@ -1203,6 +1273,12 @@ static int arch_create_got(struct obj_file *f) | |||
1203 | break; | 1273 | break; |
1204 | #endif | 1274 | #endif |
1205 | 1275 | ||
1276 | #if defined (__v850e__) | ||
1277 | case R_V850_22_PCREL: | ||
1278 | pltneeded = 1; | ||
1279 | break; | ||
1280 | #endif | ||
1281 | |||
1206 | #if defined(__arm__) | 1282 | #if defined(__arm__) |
1207 | case R_ARM_PC24: | 1283 | case R_ARM_PC24: |
1208 | case R_ARM_PLT32: | 1284 | case R_ARM_PLT32: |
@@ -1250,8 +1326,8 @@ static int arch_create_got(struct obj_file *f) | |||
1250 | pltneeded = 0; | 1326 | pltneeded = 0; |
1251 | } | 1327 | } |
1252 | #endif | 1328 | #endif |
1253 | } | ||
1254 | } | 1329 | } |
1330 | } | ||
1255 | 1331 | ||
1256 | #if defined(CONFIG_USE_GOT_ENTRIES) | 1332 | #if defined(CONFIG_USE_GOT_ENTRIES) |
1257 | if (got_offset) { | 1333 | if (got_offset) { |
@@ -1610,19 +1686,45 @@ add_symbols_from( | |||
1610 | struct new_module_symbol *s; | 1686 | struct new_module_symbol *s; |
1611 | size_t i; | 1687 | size_t i; |
1612 | int used = 0; | 1688 | int used = 0; |
1689 | #ifdef SYMBOL_PREFIX | ||
1690 | char *name_buf = 0; | ||
1691 | size_t name_alloced_size = 0; | ||
1692 | #endif | ||
1613 | 1693 | ||
1614 | for (i = 0, s = syms; i < nsyms; ++i, ++s) { | 1694 | for (i = 0, s = syms; i < nsyms; ++i, ++s) { |
1615 | 1695 | /* Only add symbols that are already marked external. | |
1616 | /* Only add symbols that are already marked external. If we | 1696 | If we override locals we may cause problems for |
1617 | override locals we may cause problems for argument initialization. | 1697 | argument initialization. We will also create a false |
1618 | We will also create a false dependency on the module. */ | 1698 | dependency on the module. */ |
1619 | struct obj_symbol *sym; | 1699 | struct obj_symbol *sym; |
1620 | 1700 | char *name = (char *)s->name; | |
1621 | sym = obj_find_symbol(f, (char *) s->name); | 1701 | |
1622 | if (sym && !ELFW(ST_BIND) (sym->info) == STB_LOCAL) { | 1702 | #ifdef SYMBOL_PREFIX |
1623 | sym = obj_add_symbol(f, (char *) s->name, -1, | 1703 | /* Prepend SYMBOL_PREFIX to the symbol's name (the |
1624 | ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE), | 1704 | kernel exports `C names', but module object files |
1625 | idx, s->value, 0); | 1705 | reference `linker names'). */ |
1706 | size_t extra = sizeof SYMBOL_PREFIX; | ||
1707 | size_t name_size = strlen (name) + extra; | ||
1708 | if (name_size > name_alloced_size) { | ||
1709 | name_alloced_size = name_size * 2; | ||
1710 | name_buf = alloca (name_alloced_size); | ||
1711 | } | ||
1712 | strcpy (name_buf, SYMBOL_PREFIX); | ||
1713 | strcpy (name_buf + extra - 1, name); | ||
1714 | name = name_buf; | ||
1715 | #endif /* SYMBOL_PREFIX */ | ||
1716 | |||
1717 | sym = obj_find_symbol(f, name); | ||
1718 | if (sym && !(ELFW(ST_BIND) (sym->info) == STB_LOCAL)) { | ||
1719 | #ifdef SYMBOL_PREFIX | ||
1720 | /* Put NAME_BUF into more permanent storage. */ | ||
1721 | name = xmalloc (name_size); | ||
1722 | strcpy (name, name_buf); | ||
1723 | #endif | ||
1724 | sym = obj_add_symbol(f, name, -1, | ||
1725 | ELFW(ST_INFO) (STB_GLOBAL, | ||
1726 | STT_NOTYPE), | ||
1727 | idx, s->value, 0); | ||
1626 | /* Did our symbol just get installed? If so, mark the | 1728 | /* Did our symbol just get installed? If so, mark the |
1627 | module as "used". */ | 1729 | module as "used". */ |
1628 | if (sym->secidx == idx) | 1730 | if (sym->secidx == idx) |
@@ -2012,9 +2114,9 @@ old_init_module(const char *m_name, struct obj_file *f, | |||
2012 | /* Fill in routines. */ | 2114 | /* Fill in routines. */ |
2013 | 2115 | ||
2014 | routines.init = | 2116 | routines.init = |
2015 | obj_symbol_final_value(f, obj_find_symbol(f, "init_module")); | 2117 | obj_symbol_final_value(f, obj_find_symbol(f, SPFX "init_module")); |
2016 | routines.cleanup = | 2118 | routines.cleanup = |
2017 | obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module")); | 2119 | obj_symbol_final_value(f, obj_find_symbol(f, SPFX "cleanup_module")); |
2018 | 2120 | ||
2019 | /* Whew! All of the initialization is complete. Collect the final | 2121 | /* Whew! All of the initialization is complete. Collect the final |
2020 | module image and give it to the kernel. */ | 2122 | module image and give it to the kernel. */ |
@@ -2053,7 +2155,7 @@ static int | |||
2053 | new_process_module_arguments(struct obj_file *f, int argc, char **argv) | 2155 | new_process_module_arguments(struct obj_file *f, int argc, char **argv) |
2054 | { | 2156 | { |
2055 | while (argc > 0) { | 2157 | while (argc > 0) { |
2056 | char *p, *q, *key; | 2158 | char *p, *q, *key, *sym_name; |
2057 | struct obj_symbol *sym; | 2159 | struct obj_symbol *sym; |
2058 | char *contents, *loc; | 2160 | char *contents, *loc; |
2059 | int min, max, n; | 2161 | int min, max, n; |
@@ -2076,7 +2178,14 @@ new_process_module_arguments(struct obj_file *f, int argc, char **argv) | |||
2076 | return 0; | 2178 | return 0; |
2077 | } | 2179 | } |
2078 | 2180 | ||
2079 | sym = obj_find_symbol(f, key); | 2181 | #ifdef SYMBOL_PREFIX |
2182 | sym_name = alloca (strlen (key) + sizeof SYMBOL_PREFIX); | ||
2183 | strcpy (sym_name, SYMBOL_PREFIX); | ||
2184 | strcat (sym_name, key); | ||
2185 | #else | ||
2186 | sym_name = key; | ||
2187 | #endif | ||
2188 | sym = obj_find_symbol(f, sym_name); | ||
2080 | 2189 | ||
2081 | /* Also check that the parameter was not resolved from the kernel. */ | 2190 | /* Also check that the parameter was not resolved from the kernel. */ |
2082 | if (sym == NULL || sym->secidx > SHN_HIRESERVE) { | 2191 | if (sym == NULL || sym->secidx > SHN_HIRESERVE) { |
@@ -2440,9 +2549,9 @@ static int new_create_this_module(struct obj_file *f, const char *m_name) | |||
2440 | sizeof(struct new_module)); | 2549 | sizeof(struct new_module)); |
2441 | memset(sec->contents, 0, sizeof(struct new_module)); | 2550 | memset(sec->contents, 0, sizeof(struct new_module)); |
2442 | 2551 | ||
2443 | obj_add_symbol(f, "__this_module", -1, | 2552 | obj_add_symbol(f, SPFX "__this_module", -1, |
2444 | ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0, | 2553 | ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0, |
2445 | sizeof(struct new_module)); | 2554 | sizeof(struct new_module)); |
2446 | 2555 | ||
2447 | obj_string_patch(f, sec->idx, offsetof(struct new_module, name), | 2556 | obj_string_patch(f, sec->idx, offsetof(struct new_module, name), |
2448 | m_name); | 2557 | m_name); |
@@ -2468,7 +2577,7 @@ static int new_create_module_ksymtab(struct obj_file *f) | |||
2468 | if (!sec) | 2577 | if (!sec) |
2469 | return 0; | 2578 | return 0; |
2470 | 2579 | ||
2471 | tm = obj_find_symbol(f, "__this_module"); | 2580 | tm = obj_find_symbol(f, SPFX "__this_module"); |
2472 | dep = (struct new_module_ref *) sec->contents; | 2581 | dep = (struct new_module_ref *) sec->contents; |
2473 | for (i = 0; i < n_ext_modules; ++i) | 2582 | for (i = 0; i < n_ext_modules; ++i) |
2474 | if (ext_modules[i].used) { | 2583 | if (ext_modules[i].used) { |
@@ -2554,9 +2663,9 @@ new_init_module(const char *m_name, struct obj_file *f, | |||
2554 | } | 2663 | } |
2555 | 2664 | ||
2556 | module->init = | 2665 | module->init = |
2557 | obj_symbol_final_value(f, obj_find_symbol(f, "init_module")); | 2666 | obj_symbol_final_value(f, obj_find_symbol(f, SPFX "init_module")); |
2558 | module->cleanup = | 2667 | module->cleanup = |
2559 | obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module")); | 2668 | obj_symbol_final_value(f, obj_find_symbol(f, SPFX "cleanup_module")); |
2560 | 2669 | ||
2561 | sec = obj_find_section(f, "__ex_table"); | 2670 | sec = obj_find_section(f, "__ex_table"); |
2562 | if (sec) { | 2671 | if (sec) { |
@@ -3201,9 +3310,9 @@ static int obj_load_progbits(FILE * fp, struct obj_file* f, char* imagebase) | |||
3201 | static void hide_special_symbols(struct obj_file *f) | 3310 | static void hide_special_symbols(struct obj_file *f) |
3202 | { | 3311 | { |
3203 | static const char *const specials[] = { | 3312 | static const char *const specials[] = { |
3204 | "cleanup_module", | 3313 | SPFX "cleanup_module", |
3205 | "init_module", | 3314 | SPFX "init_module", |
3206 | "kernel_version", | 3315 | SPFX "kernel_version", |
3207 | NULL | 3316 | NULL |
3208 | }; | 3317 | }; |
3209 | 3318 | ||