diff options
| author | Miles Bader <miles@lsi.nec.co.jp> | 2002-04-01 09:34:25 +0000 |
|---|---|---|
| committer | Miles Bader <miles@lsi.nec.co.jp> | 2002-04-01 09:34:25 +0000 |
| commit | ae28b04ff232a97f93c45995cc0374462979fc3f (patch) | |
| tree | 7587414c1e0838c734816df0be4d56f611024f7f /modutils | |
| parent | c57e42b8f0aaeb44952284ade29717a36ee43e49 (diff) | |
| download | busybox-w32-ae28b04ff232a97f93c45995cc0374462979fc3f.tar.gz busybox-w32-ae28b04ff232a97f93c45995cc0374462979fc3f.tar.bz2 busybox-w32-ae28b04ff232a97f93c45995cc0374462979fc3f.zip | |
Add support for the NEC v850e processor.
Diffstat (limited to 'modutils')
| -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 | ||
