aboutsummaryrefslogtreecommitdiff
path: root/libbb/appletlib.c
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2016-03-30 00:42:05 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2016-03-30 00:44:11 +0200
commit610c4c385b38280c7bde7a48d95ec019cbfe1ab4 (patch)
tree82ad4366ce9e927f64efa89d178c4dd2bfea1435 /libbb/appletlib.c
parent9844d7e830a2c55421e27e8828d2067c50f57c23 (diff)
downloadbusybox-w32-610c4c385b38280c7bde7a48d95ec019cbfe1ab4.tar.gz
busybox-w32-610c4c385b38280c7bde7a48d95ec019cbfe1ab4.tar.bz2
busybox-w32-610c4c385b38280c7bde7a48d95ec019cbfe1ab4.zip
applet_tables: save space by removing applet name offsets
The array applet_nameofs consumes two bytes per applet. It encodes nofork/noexec flags suid flags the offset of the applet name in the applet_name string Change the applet_table build tool to store the flags in two separate arrays (applet_flags and applet_suid). Replace applet_nameofs[] with a smaller version that only stores a limited number of offsets. This requires changes to the macros APPLET_IS_NOFORK, APPLET_IS_NOEXEC and APPLET_SUID. According to Valgrind the original find_applet_by_name required 353 cycles per call, averaged over all names. Adjusting the number of known offsets allows space to be traded off against execution time: KNOWN_OFFSETS cycles bytes (wrt KNOWN_OFFSETS = 0) 0 9057 - 2 4604 32 4 2407 75 8 1342 98 16 908 130 32 884 194 This patch uses KNOWN_OFFSETS = 8. v2: Remove some dead code from the applet_table tool; Treat the applet in the middle of the table as a special case. v3: Use the middle applet to adjust the start of the linear search as well as the last applet found. v4: Use an augmented linear search in find_applet_by_name. Drop the special treatment of the middle name from get_applet_name: most of the advantage now derives from the last stored value. v5: Don't store index in applet_nameofs, it can be calculated. v6: Tweaks by Denys function old new delta find_applet_by_name 25 125 +100 applet_suid - 92 +92 run_applet_no_and_exit 452 460 +8 run_applet_and_exit 695 697 +2 applet_name_compare 31 - -31 applet_nameofs 734 14 -720 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 3/1 up/down: 202/-751) Total: -549 bytes text data bss dec hex filename 925464 906 17160 943530 e65aa busybox_old 924915 906 17160 942981 e6385 busybox_unstripped Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'libbb/appletlib.c')
-rw-r--r--libbb/appletlib.c82
1 files changed, 54 insertions, 28 deletions
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 95e589e74..aeaf238f1 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -139,36 +139,56 @@ void FAST_FUNC bb_show_usage(void)
139 xfunc_die(); 139 xfunc_die();
140} 140}
141 141
142#if NUM_APPLETS > 8
143static int applet_name_compare(const void *name, const void *idx)
144{
145 int i = (int)(ptrdiff_t)idx - 1;
146 return strcmp(name, APPLET_NAME(i));
147}
148#endif
149int FAST_FUNC find_applet_by_name(const char *name) 142int FAST_FUNC find_applet_by_name(const char *name)
150{ 143{
151#if NUM_APPLETS > 8 144 unsigned i, max;
152 /* Do a binary search to find the applet entry given the name. */ 145 int j;
153 const char *p; 146 const char *p;
154 p = bsearch(name, (void*)(ptrdiff_t)1, ARRAY_SIZE(applet_main), 1, applet_name_compare); 147
155 /* 148 p = applet_names;
156 * if (!p) return -1; 149 i = 0;
157 * ^^^^^^^^^^^^^^^^^^ the code below will do this if p == NULL :) 150#if KNOWN_APPNAME_OFFSETS <= 0
158 */ 151 max = NUM_APPLETS;
159 return (int)(ptrdiff_t)p - 1;
160#else 152#else
161 /* A version which does not pull in bsearch */ 153 max = NUM_APPLETS * KNOWN_APPNAME_OFFSETS;
162 int i = 0; 154 for (j = ARRAY_SIZE(applet_nameofs)-1; j >= 0; j--) {
163 const char *p = applet_names; 155 const char *pp = applet_names + applet_nameofs[j];
164 while (i < NUM_APPLETS) { 156 if (strcmp(name, pp) >= 0) {
165 if (strcmp(name, p) == 0) 157 //bb_error_msg("name:'%s' >= pp:'%s'", name, pp);
166 return i; 158 p = pp;
167 p += strlen(p) + 1; 159 i = max - NUM_APPLETS;
160 break;
161 }
162 max -= NUM_APPLETS;
163 }
164 max /= (unsigned)KNOWN_APPNAME_OFFSETS;
165 i /= (unsigned)KNOWN_APPNAME_OFFSETS;
166 //bb_error_msg("name:'%s' starting from:'%s' i:%u max:%u", name, p, i, max);
167#endif
168
169 /* Open-coding without strcmp/strlen calls for speed */
170 while (i < max) {
171 char ch;
172 j = 0;
173 /* Do we see "name\0" in applet_names[p] position? */
174 while ((ch = *p) == name[j]) {
175 if (ch == '\0') {
176 //bb_error_msg("found:'%s' i:%u", name, i);
177 return i; /* yes */
178 }
179 p++;
180 j++;
181 }
182 /* No.
183 * p => 1st non-matching char in applet_names[],
184 * skip to and including NUL.
185 */
186 while (ch != '\0')
187 ch = *++p;
188 p++;
168 i++; 189 i++;
169 } 190 }
170 return -1; 191 return -1;
171#endif
172} 192}
173 193
174 194
@@ -583,6 +603,7 @@ static void install_links(const char *busybox, int use_symbolic_links,
583 * busybox.h::bb_install_loc_t, or else... */ 603 * busybox.h::bb_install_loc_t, or else... */
584 int (*lf)(const char *, const char *); 604 int (*lf)(const char *, const char *);
585 char *fpc; 605 char *fpc;
606 const char *appname = applet_names;
586 unsigned i; 607 unsigned i;
587 int rc; 608 int rc;
588 609
@@ -593,7 +614,7 @@ static void install_links(const char *busybox, int use_symbolic_links,
593 for (i = 0; i < ARRAY_SIZE(applet_main); i++) { 614 for (i = 0; i < ARRAY_SIZE(applet_main); i++) {
594 fpc = concat_path_file( 615 fpc = concat_path_file(
595 custom_install_dir ? custom_install_dir : install_dir[APPLET_INSTALL_LOC(i)], 616 custom_install_dir ? custom_install_dir : install_dir[APPLET_INSTALL_LOC(i)],
596 APPLET_NAME(i)); 617 appname);
597 // debug: bb_error_msg("%slinking %s to busybox", 618 // debug: bb_error_msg("%slinking %s to busybox",
598 // use_symbolic_links ? "sym" : "", fpc); 619 // use_symbolic_links ? "sym" : "", fpc);
599 rc = lf(busybox, fpc); 620 rc = lf(busybox, fpc);
@@ -601,6 +622,8 @@ static void install_links(const char *busybox, int use_symbolic_links,
601 bb_simple_perror_msg(fpc); 622 bb_simple_perror_msg(fpc);
602 } 623 }
603 free(fpc); 624 free(fpc);
625 while (*appname++ != '\0')
626 continue;
604 } 627 }
605} 628}
606# else 629# else
@@ -754,7 +777,7 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv)
754 777
755 /* Reinit some shared global data */ 778 /* Reinit some shared global data */
756 xfunc_error_retval = EXIT_FAILURE; 779 xfunc_error_retval = EXIT_FAILURE;
757 applet_name = APPLET_NAME(applet_no); 780 applet_name = bb_get_last_path_component_nostrip(argv[0]);
758 781
759 /* Special case. POSIX says "test --help" 782 /* Special case. POSIX says "test --help"
760 * should be no different from e.g. "test --foo". 783 * should be no different from e.g. "test --foo".
@@ -785,11 +808,14 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv)
785 808
786void FAST_FUNC run_applet_and_exit(const char *name, char **argv) 809void FAST_FUNC run_applet_and_exit(const char *name, char **argv)
787{ 810{
788 int applet = find_applet_by_name(name); 811 int applet;
789 if (applet >= 0) 812
790 run_applet_no_and_exit(applet, argv);
791 if (is_prefixed_with(name, "busybox")) 813 if (is_prefixed_with(name, "busybox"))
792 exit(busybox_main(argv)); 814 exit(busybox_main(argv));
815 /* find_applet_by_name() search is more expensive, so goes second */
816 applet = find_applet_by_name(name);
817 if (applet >= 0)
818 run_applet_no_and_exit(applet, argv);
793} 819}
794 820
795#endif /* !defined(SINGLE_APPLET_MAIN) */ 821#endif /* !defined(SINGLE_APPLET_MAIN) */