From: John Marino Date: Fri, 16 Mar 2012 19:46:52 +0000 (+0100) Subject: rtld: Shrink by eliminating stdio X-Git-Tag: v3.2.0~1237 X-Git-Url: https://gitweb.dragonflybsd.org/~tuxillo/dragonfly.git/commitdiff_plain/b2cf26499615896e389f50012c0bf803e99bc7f3 rtld: Shrink by eliminating stdio Eliminate stdio for parsing libmap.conf, and instead parse it from direct mapping. Also stop using strerror(3) in rtld which sucks in msgcat and stdio. Instead directly access sys_errlist array of error messages with private rtld_strerror() function. Results on x86_64 (includes debug symbols): > size /usr/libexec/ld-elf.so.2* text data bss dec hex filename 95294 1560 7680 104534 19856 /usr/libexec/ld-elf.so.2 108830 3128 18216 130174 1fc7e /usr/libexec/ld-elf.so.2.old > ls -al /usr/libexec/ld-elf.so.2* -r-xr-xr-x 1 root wheel 305763 Mar 16 20:33 /usr/libexec/ld-elf.so.2 -r-xr-xr-x 1 root wheel 370392 Mar 14 00:02 /usr/libexec/ld-elf.so.2.old Taken from: FreeBSD SVN 232862 (2012-03-12) FreeBSD SVN 232974 (2012-03-14) --- diff --git a/libexec/rtld-elf/libmap.c b/libexec/rtld-elf/libmap.c index c8b60f67ce..2851a11674 100644 --- a/libexec/rtld-elf/libmap.c +++ b/libexec/rtld-elf/libmap.c @@ -2,12 +2,14 @@ * $FreeBSD$ */ -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include #include "debug.h" #include "rtld.h" @@ -21,7 +23,6 @@ TAILQ_HEAD(lm_list, lm); struct lm { char *f; char *t; - TAILQ_ENTRY(lm) lm_link; }; @@ -33,76 +34,112 @@ struct lmp { TAILQ_ENTRY(lmp) lmp_link; }; -static int lm_count; +static int lm_count; -static void lmc_parse (FILE *); -static void lm_add (const char *, const char *, const char *); -static void lm_free (struct lm_list *); -static char * lml_find (struct lm_list *, const char *); -static struct lm_list * lmp_find (const char *); -static struct lm_list * lmp_init (char *); -static const char * quickbasename (const char *); -static int readstrfn (void * cookie, char *buf, int len); -static int closestrfn (void * cookie); +static void lmc_parse(char *, size_t); +static void lm_add(const char *, const char *, const char *); +static void lm_free(struct lm_list *); +static char *lml_find(struct lm_list *, const char *); +static struct lm_list *lmp_find(const char *); +static struct lm_list *lmp_init(char *); +static const char *quickbasename(const char *); #define iseol(c) (((c) == '#') || ((c) == '\0') || \ ((c) == '\n') || ((c) == '\r')) +/* + * Do not use ctype.h macros, which rely on working TLS. It is + * too early to have thread-local variables functional. + */ +#define rtld_isspace(c) ((c) == ' ' || (c) == '\t') + int -lm_init (char *libmap_override) +lm_init(char *libmap_override) { - FILE *fp; - - dbg("%s(\"%s\")", __func__, libmap_override); + struct stat st; + char *lm_map, *p; + int fd; + dbg("lm_init(\"%s\")", libmap_override); TAILQ_INIT(&lmp_head); - fp = fopen(_PATH_LIBMAP_CONF, "r"); - if (fp) { - lmc_parse(fp); - fclose(fp); + fd = open(_PATH_LIBMAP_CONF, O_RDONLY); + if (fd == -1) { + dbg("lm_init: open(\"%s\") failed, %s", _PATH_LIBMAP_CONF, + rtld_strerror(errno)); + goto override; + } + if (fstat(fd, &st) == -1) { + close(fd); + dbg("lm_init: fstat(\"%s\") failed, %s", _PATH_LIBMAP_CONF, + rtld_strerror(errno)); + goto override; + } + lm_map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (lm_map == (const char *)MAP_FAILED) { + close(fd); + dbg("lm_init: mmap(\"%s\") failed, %s", _PATH_LIBMAP_CONF, + rtld_strerror(errno)); + goto override; } + close(fd); + lmc_parse(lm_map, st.st_size); + munmap(lm_map, st.st_size); +override: if (libmap_override) { - char *p; - /* do some character replacement to make $LIBMAP look like a - text file, then "open" it with funopen */ + /* + * Do some character replacement to make $LIBMAP look + * like a text file, then parse it. + */ libmap_override = xstrdup(libmap_override); - for (p = libmap_override; *p; p++) { switch (*p) { - case '=': - *p = ' '; break; - case ',': - *p = '\n'; break; + case '=': + *p = ' '; + break; + case ',': + *p = '\n'; + break; } } - fp = funopen(libmap_override, readstrfn, NULL, NULL, closestrfn); - if (fp) { - lmc_parse(fp); - fclose(fp); - } + lmc_parse(p, strlen(p)); + free(p); } return (lm_count == 0); } static void -lmc_parse (FILE *fp) +lmc_parse(char *lm_p, size_t lm_len) { - char *cp; - char *f, *t, *c, *p; - char prog[MAXPATHLEN]; - char line[MAXPATHLEN + 2]; - - dbg("%s(%p)", __func__, fp); + char *cp, *f, *t, *c, *p; + char prog[MAXPATHLEN]; + char line[MAXPATHLEN + 2]; + size_t cnt; + int i; + cnt = 0; p = NULL; - while ((cp = fgets(line, MAXPATHLEN + 1, fp)) != NULL) { + while (cnt < lm_len) { + i = 0; + while (lm_p[cnt] != '\n' && cnt < lm_len && + i < sizeof(line) - 1) { + line[i] = lm_p[cnt]; + cnt++; + i++; + } + line[i] = '\0'; + while (lm_p[cnt] != '\n' && cnt < lm_len) + cnt++; + /* skip over nl */ + cnt++; + + cp = &line[0]; t = f = c = NULL; /* Skip over leading space */ - while (isspace(*cp)) cp++; + while (rtld_isspace(*cp)) cp++; /* Found a comment or EOL */ if (iseol(*cp)) continue; @@ -112,7 +149,7 @@ lmc_parse (FILE *fp) cp++; /* Skip leading space */ - while (isspace(*cp)) cp++; + while (rtld_isspace(*cp)) cp++; /* Found comment, EOL or end of selector */ if (iseol(*cp) || *cp == ']') @@ -120,11 +157,11 @@ lmc_parse (FILE *fp) c = cp++; /* Skip to end of word */ - while (!isspace(*cp) && !iseol(*cp) && *cp != ']') + while (!rtld_isspace(*cp) && !iseol(*cp) && *cp != ']') cp++; /* Skip and zero out trailing space */ - while (isspace(*cp)) *cp++ = '\0'; + while (rtld_isspace(*cp)) *cp++ = '\0'; /* Check if there is a closing brace */ if (*cp != ']') continue; @@ -136,7 +173,7 @@ lmc_parse (FILE *fp) * There should be nothing except whitespace or comment from this point to the end of the line. */ - while(isspace(*cp)) cp++; + while(rtld_isspace(*cp)) cp++; if (!iseol(*cp)) continue; strcpy(prog, c); @@ -146,20 +183,20 @@ lmc_parse (FILE *fp) /* Parse the 'from' candidate. */ f = cp++; - while (!isspace(*cp) && !iseol(*cp)) cp++; + while (!rtld_isspace(*cp) && !iseol(*cp)) cp++; /* Skip and zero out the trailing whitespace */ - while (isspace(*cp)) *cp++ = '\0'; + while (rtld_isspace(*cp)) *cp++ = '\0'; /* Found a comment or EOL */ if (iseol(*cp)) continue; /* Parse 'to' mapping */ t = cp++; - while (!isspace(*cp) && !iseol(*cp)) cp++; + while (!rtld_isspace(*cp) && !iseol(*cp)) cp++; /* Skip and zero out the trailing whitespace */ - while (isspace(*cp)) *cp++ = '\0'; + while (rtld_isspace(*cp)) *cp++ = '\0'; /* Should be no extra tokens at this point */ if (!iseol(*cp)) continue; @@ -313,31 +350,3 @@ quickbasename (const char *path) } return (p); } - -static int -readstrfn(void * cookie, char *buf, int len) -{ - static char *current; - static int left; - int copied; - - copied = 0; - if (!current) { - current = cookie; - left = strlen(cookie); - } - while (*current && left && len) { - *buf++ = *current++; - left--; - len--; - copied++; - } - return copied; -} - -static int -closestrfn(void * cookie) -{ - free(cookie); - return 0; -} diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c index f33c839c62..a90a29e91e 100644 --- a/libexec/rtld-elf/map_object.c +++ b/libexec/rtld-elf/map_object.c @@ -171,7 +171,7 @@ map_object(int fd, const char *path, const struct stat *sb) MAP_NOCORE, -1, 0); if (mapbase == (caddr_t) -1) { _rtld_error("%s: mmap of entire address space failed: %s", - path, strerror(errno)); + path, rtld_strerror(errno)); return NULL; } if (base_addr != NULL && mapbase != base_addr) { @@ -191,7 +191,8 @@ map_object(int fd, const char *path, const struct stat *sb) data_flags = convert_flags(segs[i]->p_flags) | MAP_FIXED; if (mmap(data_addr, data_vlimit - data_vaddr, data_prot, data_flags, fd, data_offset) == (caddr_t) -1) { - _rtld_error("%s: mmap of data failed: %s", path, strerror(errno)); + _rtld_error("%s: mmap of data failed: %s", path, + rtld_strerror(errno)); return NULL; } @@ -208,7 +209,7 @@ map_object(int fd, const char *path, const struct stat *sb) if ((data_prot & PROT_WRITE) == 0 && -1 == mprotect(clear_page, PAGE_SIZE, data_prot|PROT_WRITE)) { _rtld_error("%s: mprotect failed: %s", path, - strerror(errno)); + rtld_strerror(errno)); return NULL; } @@ -232,7 +233,7 @@ map_object(int fd, const char *path, const struct stat *sb) if (mmap(bss_addr, bss_vlimit - bss_vaddr, data_prot, data_flags | MAP_ANON, -1, 0) == (caddr_t)-1) { _rtld_error("%s: mmap of bss failed: %s", path, - strerror(errno)); + rtld_strerror(errno)); return NULL; } } @@ -300,7 +301,7 @@ get_elf_header (int fd, const char *path) ssize_t nbytes; if ((nbytes = pread(fd, u.buf, PAGE_SIZE, 0)) == -1) { - _rtld_error("%s: read error: %s", path, strerror(errno)); + _rtld_error("%s: read error: %s", path, rtld_strerror(errno)); return NULL; } diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 17f6b06f14..9a7723cb32 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -2265,7 +2265,7 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj, if (mprotect(obj->mapbase, obj->textsize, PROT_READ|PROT_WRITE|PROT_EXEC) == -1) { _rtld_error("%s: Cannot write-enable text segment: %s", - obj->path, strerror(errno)); + obj->path, rtld_strerror(errno)); return -1; } } @@ -2292,7 +2292,7 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj, if (mprotect(obj->mapbase, obj->textsize, PROT_READ|PROT_EXEC) == -1) { _rtld_error("%s: Cannot write-protect text segment: %s", - obj->path, strerror(errno)); + obj->path, rtld_strerror(errno)); return -1; } } @@ -2324,7 +2324,7 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj, if (obj->relro_size) { if (mprotect(obj->relro_page, obj->relro_size, PROT_READ) == -1) { _rtld_error("%s: Cannot enforce relro relocation: %s", - obj->path, strerror(errno)); + obj->path, rtld_strerror(errno)); return -1; } } @@ -4405,3 +4405,12 @@ void __pthread_cxa_finalize(struct dl_phdr_info *a) { } + +const char * +rtld_strerror(int errnum) +{ + + if (errnum < 0 || errnum >= sys_nerr) + return ("Unknown error"); + return (sys_errlist[errnum]); +} diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index d70d788df5..b58cea72e2 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -306,6 +306,7 @@ typedef struct Struct_SymLook { } SymLook; void _rtld_error(const char *, ...) __printflike(1, 2); +const char *rtld_strerror(int); Obj_Entry *map_object(int, const char *, const struct stat *); void *xcalloc(size_t); void *xmalloc(size_t);