From 6e69dba341f4731ad1eb437add0a4503ae16297c Mon Sep 17 00:00:00 2001 From: anchao Date: Tue, 19 Mar 2019 09:13:50 -0600 Subject: [PATCH] binfmt/libelf/ and libs/libc/modlib: Add symbol buffer table to reduce filesystem access. --- binfmt/libelf/Kconfig | 9 +- binfmt/libelf/libelf_bind.c | 161 ++++++++++++++++++++++++--------- libs/libc/modlib/Kconfig | 7 ++ libs/libc/modlib/modlib_bind.c | 141 ++++++++++++++++++++++------- 4 files changed, 238 insertions(+), 80 deletions(-) diff --git a/binfmt/libelf/Kconfig b/binfmt/libelf/Kconfig index 719234984c..5f2f292a22 100644 --- a/binfmt/libelf/Kconfig +++ b/binfmt/libelf/Kconfig @@ -53,5 +53,12 @@ config ELF_RELOCATION_BUFFERCOUNT int "ELF Relocation Table Buffer Count" default 256 ---help--- - This is an cache buffer that is used to store elf relocation table to + This is an relocation buffer that is used to store elf relocation table to + reduce access fs. Default: 256 + +config ELF_SYMBOL_CACHECOUNT + int "ELF SYMBOL Table Cache Count" + default 256 + ---help--- + This is an cache that is used to store elf symbol table to reduce access fs. Default: 256 diff --git a/binfmt/libelf/libelf_bind.c b/binfmt/libelf/libelf_bind.c index 8f86c595af..6bacf4eaa7 100644 --- a/binfmt/libelf/libelf_bind.c +++ b/binfmt/libelf/libelf_bind.c @@ -74,6 +74,17 @@ * Private Types ****************************************************************************/ +/* REVISIT: This naming breaks the NuttX coding standard, but is consistent + * with legacy naming of other ELF32 types. + */ + +typedef struct +{ + dq_entry_t entry; + Elf32_Sym sym; + int idx; +} Elf32_SymCache; + /**************************************************************************** * Private Data ****************************************************************************/ @@ -91,8 +102,9 @@ ****************************************************************************/ static inline int elf_readrels(FAR struct elf_loadinfo_s *loadinfo, - FAR const Elf32_Shdr *relsec, - int index, FAR Elf32_Rel *rels) + FAR const Elf32_Shdr *relsec, + int index, FAR Elf32_Rel *rels, + int count) { off_t offset; int size; @@ -108,7 +120,7 @@ static inline int elf_readrels(FAR struct elf_loadinfo_s *loadinfo, /* Get the file offset to the symbol table entry */ offset = sizeof(Elf32_Rel) * index; - size = sizeof(Elf32_Rel) * CONFIG_ELF_RELOCATION_BUFFERCOUNT; + size = sizeof(Elf32_Rel) * count; if (offset + size > relsec->sh_size) { size = relsec->sh_size - offset; @@ -136,24 +148,29 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx, FAR const struct symtab_s *exports, int nexports) { - FAR Elf32_Shdr *relsec = &loadinfo->shdr[relidx]; - FAR Elf32_Shdr *dstsec = &loadinfo->shdr[relsec->sh_info]; - FAR Elf32_Rel *rels; - FAR Elf32_Rel *rel; - Elf32_Sym sym; - FAR Elf32_Sym *psym; - uintptr_t addr; - int symidx; - int ret; - int i; + FAR Elf32_Shdr *relsec = &loadinfo->shdr[relidx]; + FAR Elf32_Shdr *dstsec = &loadinfo->shdr[relsec->sh_info]; + FAR Elf32_Rel *rels; + FAR Elf32_Rel *rel; + FAR Elf32_SymCache *cache; + FAR Elf32_Sym *sym; + FAR dq_entry_t *e; + dq_queue_t q; + uintptr_t addr; + int symidx; + int ret; + int i; + int j; rels = kmm_malloc(CONFIG_ELF_RELOCATION_BUFFERCOUNT * sizeof(Elf32_Rel)); if (rels == NULL) { - berr("Failed to allocate memory for elf relocation rels\n"); + berr("Failed to allocate memory for elf relocation\n"); return -ENOMEM; } + dq_init(&q); + /* Examine each relocation in the section. 'relsec' is the section * containing the relations. 'dstsec' is the section containing the data * to be relocated. @@ -161,21 +178,20 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx, ret = OK; - for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++) + for (i = j = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++) { - psym = &sym; - /* Read the relocation entry into memory */ rel = &rels[i % CONFIG_ELF_RELOCATION_BUFFERCOUNT]; if (!(i % CONFIG_ELF_RELOCATION_BUFFERCOUNT)) { - ret = elf_readrels(loadinfo, relsec, i, rels); + ret = elf_readrels(loadinfo, relsec, i, rels, + CONFIG_ELF_RELOCATION_BUFFERCOUNT); if (ret < 0) { berr("Section %d reloc %d: Failed to read relocation entry: %d\n", - relidx, i, ret); + relidx, i, ret); break; } } @@ -186,43 +202,93 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx, symidx = ELF32_R_SYM(rel->r_info); - /* Read the symbol table entry into memory */ + /* First try the cache */ - ret = elf_readsym(loadinfo, symidx, &sym); - if (ret < 0) + sym = NULL; + for (e = dq_peek(&q); e; e = dq_next(e)) { - berr("Section %d reloc %d: Failed to read symbol[%d]: %d\n", - relidx, i, symidx, ret); - break; + cache = (FAR Elf32_SymCache *)e; + if (cache->idx == symidx) + { + dq_rem(&cache->entry, &q); + dq_addfirst(&cache->entry, &q); + sym = &cache->sym; + break; + } } - /* Get the value of the symbol (in sym.st_value) */ + /* If the symbol was not found in the cache, we will need to read the + * symbol from the file. + */ - ret = elf_symvalue(loadinfo, &sym, exports, nexports); - if (ret < 0) + if (sym == NULL) { - /* The special error -ESRCH is returned only in one condition: The - * symbol has no name. - * - * There are a few relocations for a few architectures that do - * no depend upon a named symbol. We don't know if that is the - * case here, but we will use a NULL symbol pointer to indicate - * that case to up_relocate(). That function can then do what - * is best. - */ - - if (ret == -ESRCH) + if (j < CONFIG_ELF_SYMBOL_CACHECOUNT) { - berr("Section %d reloc %d: Undefined symbol[%d] has no name: %d\n", - relidx, i, symidx, ret); - psym = NULL; + cache = kmm_malloc(sizeof(Elf32_SymCache)); + if (!cache) + { + berr("Failed to allocate memory for elf symbols\n"); + ret = -ENOMEM; + break; + } + + j++; } else { - berr("Section %d reloc %d: Failed to get value of symbol[%d]: %d\n", - relidx, i, symidx, ret); + cache = (FAR Elf32_SymCache *)dq_remlast(&q); + } + + sym = &cache->sym; + + /* Read the symbol table entry into memory */ + + ret = elf_readsym(loadinfo, symidx, sym); + if (ret < 0) + { + berr("Section %d reloc %d: Failed to read symbol[%d]: %d\n", + relidx, i, symidx, ret); + kmm_free(cache); break; } + + /* Get the value of the symbol (in sym.st_value) */ + + ret = elf_symvalue(loadinfo, sym, exports, nexports); + if (ret < 0) + { + /* The special error -ESRCH is returned only in one condition: The + * symbol has no name. + * + * There are a few relocations for a few architectures that do + * no depend upon a named symbol. We don't know if that is the + * case here, but we will use a NULL symbol pointer to indicate + * that case to up_relocate(). That function can then do what + * is best. + */ + + if (ret == -ESRCH) + { + berr("Section %d reloc %d: Undefined symbol[%d] has no name: %d\n", + relidx, i, symidx, ret); + } + else + { + berr("Section %d reloc %d: Failed to get value of symbol[%d]: %d\n", + relidx, i, symidx, ret); + kmm_free(cache); + break; + } + } + + cache->idx = symidx; + dq_addfirst(&cache->entry, &q); + } + + if (sym->st_shndx == SHN_UNDEF && sym->st_name == 0) + { + sym = NULL; } /* Calculate the relocation address. */ @@ -239,7 +305,7 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx, /* Now perform the architecture-specific relocation */ - ret = up_relocate(rel, psym, addr); + ret = up_relocate(rel, sym, addr); if (ret < 0) { berr("ERROR: Section %d reloc %d: Relocation failed: %d\n", relidx, i, ret); @@ -248,6 +314,11 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx, } kmm_free(rels); + while ((e = dq_peek(&q))) + { + dq_rem(e, &q); + kmm_free(e); + } return ret; } diff --git a/libs/libc/modlib/Kconfig b/libs/libc/modlib/Kconfig index ea9905627e..a650ad019b 100644 --- a/libs/libc/modlib/Kconfig +++ b/libs/libc/modlib/Kconfig @@ -72,6 +72,13 @@ config MODLIB_RELOCATION_BUFFERCOUNT This is an cache buffer that is used to store elf relocation table to reduce access fs. Default: 256 +config MODLIB_SYMBOL_CACHECOUNT + int "MODLIB SYMBOL Table Cache Count" + default 256 + ---help--- + This is an cache that is used to store elf symbol table to + reduce access fs. Default: 256 + if MODLIB_HAVE_SYMTAB config MODLIB_SYMTAB_ARRAY diff --git a/libs/libc/modlib/modlib_bind.c b/libs/libc/modlib/modlib_bind.c index 7dd57fcaab..872bca29c4 100644 --- a/libs/libc/modlib/modlib_bind.c +++ b/libs/libc/modlib/modlib_bind.c @@ -51,6 +51,21 @@ #include "libc.h" #include "modlib/modlib.h" +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* REVISIT: This naming breaks the NuttX coding standard, but is consistent + * with legacy naming of other ELF32 types. + */ + +typedef struct +{ + dq_entry_t entry; + Elf32_Sym sym; + int idx; +} Elf32_SymCache; + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -65,7 +80,8 @@ static inline int modlib_readrels(FAR struct mod_loadinfo_s *loadinfo, FAR const Elf32_Shdr *relsec, - int index, FAR Elf32_Rel *rels) + int index, FAR Elf32_Rel *rels, + int count) { off_t offset; int size; @@ -81,7 +97,7 @@ static inline int modlib_readrels(FAR struct mod_loadinfo_s *loadinfo, /* Get the file offset to the symbol table entry */ offset = sizeof(Elf32_Rel) * index; - size = sizeof(Elf32_Rel) * CONFIG_MODLIB_RELOCATION_BUFFERCOUNT; + size = sizeof(Elf32_Rel) * count; if (offset + size > relsec->sh_size) { size = relsec->sh_size - offset; @@ -113,12 +129,15 @@ static int modlib_relocate(FAR struct module_s *modp, FAR Elf32_Shdr *dstsec = &loadinfo->shdr[relsec->sh_info]; FAR Elf32_Rel *rels; FAR Elf32_Rel *rel; - Elf32_Sym sym; - FAR Elf32_Sym *psym; + FAR Elf32_SymCache *cache; + FAR Elf32_Sym *sym; + FAR dq_entry_t *e; + dq_queue_t q; uintptr_t addr; int symidx; int ret; int i; + int j; rels = lib_malloc(CONFIG_MODLIB_RELOCATION_BUFFERCOUNT * sizeof(Elf32_Rel)); if (!rels) @@ -127,6 +146,8 @@ static int modlib_relocate(FAR struct module_s *modp, return -ENOMEM; } + dq_init(&q); + /* Examine each relocation in the section. 'relsec' is the section * containing the relations. 'dstsec' is the section containing the data * to be relocated. @@ -134,17 +155,15 @@ static int modlib_relocate(FAR struct module_s *modp, ret = OK; - for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++) + for (i = j = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++) { - psym = &sym; - /* Read the relocation entry into memory */ rel = &rels[i % CONFIG_MODLIB_RELOCATION_BUFFERCOUNT]; if (!(i % CONFIG_MODLIB_RELOCATION_BUFFERCOUNT)) { - ret = modlib_readrels(loadinfo, relsec, i, rels); + ret = modlib_readrels(loadinfo, relsec, i, rels, CONFIG_MODLIB_RELOCATION_BUFFERCOUNT); if (ret < 0) { berr("ERROR: Section %d reloc %d: Failed to read relocation entry: %d\n", @@ -159,43 +178,92 @@ static int modlib_relocate(FAR struct module_s *modp, symidx = ELF32_R_SYM(rel->r_info); - /* Read the symbol table entry into memory */ + /* First try the cache */ - ret = modlib_readsym(loadinfo, symidx, &sym); - if (ret < 0) + sym = NULL; + for (e = dq_peek(&q); e; e = dq_next(e)) { - berr("ERROR: Section %d reloc %d: Failed to read symbol[%d]: %d\n", - relidx, i, symidx, ret); - break; + cache = (FAR Elf32_SymCache *)e; + if (cache->idx == symidx) + { + dq_rem(&cache->entry, &q); + dq_addfirst(&cache->entry, &q); + sym = &cache->sym; + break; + } } - /* Get the value of the symbol (in sym.st_value) */ + /* If the symbol was not found in the cache, we will need to read the + * symbol from the file. + */ - ret = modlib_symvalue(modp, loadinfo, &sym); - if (ret < 0) + if (sym == NULL) { - /* The special error -ESRCH is returned only in one condition: The - * symbol has no name. - * - * There are a few relocations for a few architectures that do - * no depend upon a named symbol. We don't know if that is the - * case here, but we will use a NULL symbol pointer to indicate - * that case to up_relocate(). That function can then do what - * is best. - */ - - if (ret == -ESRCH) + if (j < CONFIG_MODLIB_SYMBOL_CACHECOUNT) { - berr("ERROR: Section %d reloc %d: Undefined symbol[%d] has no name: %d\n", - relidx, i, symidx, ret); - psym = NULL; + cache = lib_malloc(sizeof(Elf32_SymCache)); + if (!cache) + { + berr("Failed to allocate memory for elf symbols\n"); + ret = -ENOMEM; + break; + } + j++; } else { - berr("ERROR: Section %d reloc %d: Failed to get value of symbol[%d]: %d\n", - relidx, i, symidx, ret); + cache = (FAR Elf32_SymCache *)dq_remlast(&q); + } + + sym = &cache->sym; + + /* Read the symbol table entry into memory */ + + ret = modlib_readsym(loadinfo, symidx, sym); + if (ret < 0) + { + berr("ERROR: Section %d reloc %d: Failed to read symbol[%d]: %d\n", + relidx, i, symidx, ret); + lib_free(cache); break; } + + /* Get the value of the symbol (in sym.st_value) */ + + ret = modlib_symvalue(modp, loadinfo, sym); + if (ret < 0) + { + /* The special error -ESRCH is returned only in one condition: The + * symbol has no name. + * + * There are a few relocations for a few architectures that do + * no depend upon a named symbol. We don't know if that is the + * case here, but we will use a NULL symbol pointer to indicate + * that case to up_relocate(). That function can then do what + * is best. + */ + + if (ret == -ESRCH) + { + berr("ERROR: Section %d reloc %d: Undefined symbol[%d] has no name: %d\n", + relidx, i, symidx, ret); + } + else + { + berr("ERROR: Section %d reloc %d: Failed to get value of symbol[%d]: %d\n", + relidx, i, symidx, ret); + lib_free(cache); + break; + } + } + + cache->idx = symidx; + dq_addfirst(&cache->entry, &q); + } + + if (sym->st_shndx == SHN_UNDEF && sym->st_name == 0) + { + sym = NULL; } /* Calculate the relocation address. */ @@ -212,7 +280,7 @@ static int modlib_relocate(FAR struct module_s *modp, /* Now perform the architecture-specific relocation */ - ret = up_relocate(rel, psym, addr); + ret = up_relocate(rel, sym, addr); if (ret < 0) { berr("ERROR: Section %d reloc %d: Relocation failed: %d\n", relidx, i, ret); @@ -221,6 +289,11 @@ static int modlib_relocate(FAR struct module_s *modp, } lib_free(rels); + while ((e = dq_peek(&q))) + { + dq_rem(e, &q); + lib_free(e); + } return ret; }