binfmt/libelf/ and libs/libc/modlib: Add symbol buffer table to reduce filesystem access.

This commit is contained in:
anchao 2019-03-19 09:13:50 -06:00 committed by Gregory Nutt
parent 2f2d432f7c
commit 6e69dba341
4 changed files with 238 additions and 80 deletions

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}