binfmt/libelf and libs/libc/modlib: Add relocation buffer table to reduce access fs.
This commit is contained in:
parent
579b38b760
commit
2f2d432f7c
5 changed files with 113 additions and 48 deletions
|
@ -119,4 +119,3 @@ config SYMTAB_ORDEREDBYNAME
|
|||
the logic can perform faster lookups using a binary search.
|
||||
Otherwise, the symbol table is assumed to be un-ordered an only
|
||||
slow, linear searches are supported.
|
||||
|
||||
|
|
|
@ -48,3 +48,10 @@ config ELF_EXIDX_SECTNAME
|
|||
be loaded by the ELF binary loader.
|
||||
|
||||
This is needed to support exception handling on loadable ELF modules.
|
||||
|
||||
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
|
||||
reduce access fs. Default: 256
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/****************************************************************************
|
||||
* binfmt/libelf/libelf_bind.c
|
||||
*
|
||||
* Copyright (C) 2012, 2014 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2012, 2014, 2019 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -46,6 +46,7 @@
|
|||
#include <debug.h>
|
||||
|
||||
#include <nuttx/elf.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/binfmt/elf.h>
|
||||
#include <nuttx/binfmt/symtab.h>
|
||||
|
||||
|
@ -82,18 +83,19 @@
|
|||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: elf_readrel
|
||||
* Name: elf_readrels
|
||||
*
|
||||
* Description:
|
||||
* Read the ELF32_Rel structure into memory.
|
||||
* Read the (ELF32_Rel structure * buffer count) into memory.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline int elf_readrel(FAR struct elf_loadinfo_s *loadinfo,
|
||||
static inline int elf_readrels(FAR struct elf_loadinfo_s *loadinfo,
|
||||
FAR const Elf32_Shdr *relsec,
|
||||
int index, FAR Elf32_Rel *rel)
|
||||
int index, FAR Elf32_Rel *rels)
|
||||
{
|
||||
off_t offset;
|
||||
int size;
|
||||
|
||||
/* Verify that the symbol table index lies within symbol table */
|
||||
|
||||
|
@ -105,11 +107,17 @@ static inline int elf_readrel(FAR struct elf_loadinfo_s *loadinfo,
|
|||
|
||||
/* Get the file offset to the symbol table entry */
|
||||
|
||||
offset = relsec->sh_offset + sizeof(Elf32_Rel) * index;
|
||||
offset = sizeof(Elf32_Rel) * index;
|
||||
size = sizeof(Elf32_Rel) * CONFIG_ELF_RELOCATION_BUFFERCOUNT;
|
||||
if (offset + size > relsec->sh_size)
|
||||
{
|
||||
size = relsec->sh_size - offset;
|
||||
}
|
||||
|
||||
/* And, finally, read the symbol table entry into memory */
|
||||
|
||||
return elf_read(loadinfo, (FAR uint8_t *)rel, sizeof(Elf32_Rel), offset);
|
||||
return elf_read(loadinfo, (FAR uint8_t *)rels, size,
|
||||
relsec->sh_offset + offset);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -130,7 +138,8 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx,
|
|||
{
|
||||
FAR Elf32_Shdr *relsec = &loadinfo->shdr[relidx];
|
||||
FAR Elf32_Shdr *dstsec = &loadinfo->shdr[relsec->sh_info];
|
||||
Elf32_Rel rel;
|
||||
FAR Elf32_Rel *rels;
|
||||
FAR Elf32_Rel *rel;
|
||||
Elf32_Sym sym;
|
||||
FAR Elf32_Sym *psym;
|
||||
uintptr_t addr;
|
||||
|
@ -138,30 +147,44 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx,
|
|||
int ret;
|
||||
int i;
|
||||
|
||||
rels = kmm_malloc(CONFIG_ELF_RELOCATION_BUFFERCOUNT * sizeof(Elf32_Rel));
|
||||
if (rels == NULL)
|
||||
{
|
||||
berr("Failed to allocate memory for elf relocation rels\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Examine each relocation in the section. 'relsec' is the section
|
||||
* containing the relations. 'dstsec' is the section containing the data
|
||||
* to be relocated.
|
||||
*/
|
||||
|
||||
ret = OK;
|
||||
|
||||
for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++)
|
||||
{
|
||||
psym = &sym;
|
||||
|
||||
/* Read the relocation entry into memory */
|
||||
|
||||
ret = elf_readrel(loadinfo, relsec, i, &rel);
|
||||
if (ret < 0)
|
||||
rel = &rels[i % CONFIG_ELF_RELOCATION_BUFFERCOUNT];
|
||||
|
||||
if (!(i % CONFIG_ELF_RELOCATION_BUFFERCOUNT))
|
||||
{
|
||||
berr("Section %d reloc %d: Failed to read relocation entry: %d\n",
|
||||
relidx, i, ret);
|
||||
return ret;
|
||||
ret = elf_readrels(loadinfo, relsec, i, rels);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("Section %d reloc %d: Failed to read relocation entry: %d\n",
|
||||
relidx, i, ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the symbol table index for the relocation. This is contained
|
||||
* in a bit-field within the r_info element.
|
||||
*/
|
||||
|
||||
symidx = ELF32_R_SYM(rel.r_info);
|
||||
symidx = ELF32_R_SYM(rel->r_info);
|
||||
|
||||
/* Read the symbol table entry into memory */
|
||||
|
||||
|
@ -170,7 +193,7 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx,
|
|||
{
|
||||
berr("Section %d reloc %d: Failed to read symbol[%d]: %d\n",
|
||||
relidx, i, symidx, ret);
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get the value of the symbol (in sym.st_value) */
|
||||
|
@ -198,32 +221,35 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx,
|
|||
{
|
||||
berr("Section %d reloc %d: Failed to get value of symbol[%d]: %d\n",
|
||||
relidx, i, symidx, ret);
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate the relocation address. */
|
||||
|
||||
if (rel.r_offset < 0 || rel.r_offset > dstsec->sh_size - sizeof(uint32_t))
|
||||
if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(uint32_t))
|
||||
{
|
||||
berr("Section %d reloc %d: Relocation address out of range, offset %d size %d\n",
|
||||
relidx, i, rel.r_offset, dstsec->sh_size);
|
||||
return -EINVAL;
|
||||
relidx, i, rel->r_offset, dstsec->sh_size);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
addr = dstsec->sh_addr + rel.r_offset;
|
||||
addr = dstsec->sh_addr + rel->r_offset;
|
||||
|
||||
/* Now perform the architecture-specific relocation */
|
||||
|
||||
ret = up_relocate(&rel, psym, addr);
|
||||
ret = up_relocate(rel, psym, addr);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: Section %d reloc %d: Relocation failed: %d\n", relidx, i, ret);
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
kmm_free(rels);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int elf_relocateadd(FAR struct elf_loadinfo_s *loadinfo, int relidx,
|
||||
|
|
|
@ -65,6 +65,13 @@ config MODLIB_HAVE_SYMTAB
|
|||
option in order to use it. Symbol tables are required in most
|
||||
cases in order to link executable programs to the base code.
|
||||
|
||||
config MODLIB_RELOCATION_BUFFERCOUNT
|
||||
int "MODLIB Relocation Table Buffer Count"
|
||||
default 256
|
||||
---help---
|
||||
This is an cache buffer that is used to store elf relocation table to
|
||||
reduce access fs. Default: 256
|
||||
|
||||
if MODLIB_HAVE_SYMTAB
|
||||
|
||||
config MODLIB_SYMTAB_ARRAY
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/****************************************************************************
|
||||
* libs/libc/modlib/modlib_bind.c
|
||||
*
|
||||
* Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2015, 2017, 2019 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -48,6 +48,7 @@
|
|||
#include <nuttx/elf.h>
|
||||
#include <nuttx/lib/modlib.h>
|
||||
|
||||
#include "libc.h"
|
||||
#include "modlib/modlib.h"
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -55,18 +56,19 @@
|
|||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: modlib_readrel
|
||||
* Name: modlib_readrels
|
||||
*
|
||||
* Description:
|
||||
* Read the ELF32_Rel structure into memory.
|
||||
* Read the (ELF32_Rel structure * buffer count) into memory.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline int modlib_readrel(FAR struct mod_loadinfo_s *loadinfo,
|
||||
FAR const Elf32_Shdr *relsec,
|
||||
int index, FAR Elf32_Rel *rel)
|
||||
static inline int modlib_readrels(FAR struct mod_loadinfo_s *loadinfo,
|
||||
FAR const Elf32_Shdr *relsec,
|
||||
int index, FAR Elf32_Rel *rels)
|
||||
{
|
||||
off_t offset;
|
||||
int size;
|
||||
|
||||
/* Verify that the symbol table index lies within symbol table */
|
||||
|
||||
|
@ -78,11 +80,17 @@ static inline int modlib_readrel(FAR struct mod_loadinfo_s *loadinfo,
|
|||
|
||||
/* Get the file offset to the symbol table entry */
|
||||
|
||||
offset = relsec->sh_offset + sizeof(Elf32_Rel) * index;
|
||||
offset = sizeof(Elf32_Rel) * index;
|
||||
size = sizeof(Elf32_Rel) * CONFIG_MODLIB_RELOCATION_BUFFERCOUNT;
|
||||
if (offset + size > relsec->sh_size)
|
||||
{
|
||||
size = relsec->sh_size - offset;
|
||||
}
|
||||
|
||||
/* And, finally, read the symbol table entry into memory */
|
||||
|
||||
return modlib_read(loadinfo, (FAR uint8_t *)rel, sizeof(Elf32_Rel), offset);
|
||||
return modlib_read(loadinfo, (FAR uint8_t *)rels, size,
|
||||
relsec->sh_offset + offset);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -103,7 +111,8 @@ static int modlib_relocate(FAR struct module_s *modp,
|
|||
{
|
||||
FAR Elf32_Shdr *relsec = &loadinfo->shdr[relidx];
|
||||
FAR Elf32_Shdr *dstsec = &loadinfo->shdr[relsec->sh_info];
|
||||
Elf32_Rel rel;
|
||||
FAR Elf32_Rel *rels;
|
||||
FAR Elf32_Rel *rel;
|
||||
Elf32_Sym sym;
|
||||
FAR Elf32_Sym *psym;
|
||||
uintptr_t addr;
|
||||
|
@ -111,30 +120,44 @@ static int modlib_relocate(FAR struct module_s *modp,
|
|||
int ret;
|
||||
int i;
|
||||
|
||||
rels = lib_malloc(CONFIG_MODLIB_RELOCATION_BUFFERCOUNT * sizeof(Elf32_Rel));
|
||||
if (!rels)
|
||||
{
|
||||
berr("Failed to allocate memory for elf relocation rels\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Examine each relocation in the section. 'relsec' is the section
|
||||
* containing the relations. 'dstsec' is the section containing the data
|
||||
* to be relocated.
|
||||
*/
|
||||
|
||||
ret = OK;
|
||||
|
||||
for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++)
|
||||
{
|
||||
psym = &sym;
|
||||
|
||||
/* Read the relocation entry into memory */
|
||||
|
||||
ret = modlib_readrel(loadinfo, relsec, i, &rel);
|
||||
if (ret < 0)
|
||||
rel = &rels[i % CONFIG_MODLIB_RELOCATION_BUFFERCOUNT];
|
||||
|
||||
if (!(i % CONFIG_MODLIB_RELOCATION_BUFFERCOUNT))
|
||||
{
|
||||
berr("ERROR: Section %d reloc %d: Failed to read relocation entry: %d\n",
|
||||
relidx, i, ret);
|
||||
return ret;
|
||||
ret = modlib_readrels(loadinfo, relsec, i, rels);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: Section %d reloc %d: Failed to read relocation entry: %d\n",
|
||||
relidx, i, ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the symbol table index for the relocation. This is contained
|
||||
* in a bit-field within the r_info element.
|
||||
*/
|
||||
|
||||
symidx = ELF32_R_SYM(rel.r_info);
|
||||
symidx = ELF32_R_SYM(rel->r_info);
|
||||
|
||||
/* Read the symbol table entry into memory */
|
||||
|
||||
|
@ -143,7 +166,7 @@ static int modlib_relocate(FAR struct module_s *modp,
|
|||
{
|
||||
berr("ERROR: Section %d reloc %d: Failed to read symbol[%d]: %d\n",
|
||||
relidx, i, symidx, ret);
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get the value of the symbol (in sym.st_value) */
|
||||
|
@ -171,32 +194,35 @@ static int modlib_relocate(FAR struct module_s *modp,
|
|||
{
|
||||
berr("ERROR: Section %d reloc %d: Failed to get value of symbol[%d]: %d\n",
|
||||
relidx, i, symidx, ret);
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate the relocation address. */
|
||||
|
||||
if (rel.r_offset < 0 || rel.r_offset > dstsec->sh_size - sizeof(uint32_t))
|
||||
if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(uint32_t))
|
||||
{
|
||||
berr("ERROR: Section %d reloc %d: Relocation address out of range, offset %d size %d\n",
|
||||
relidx, i, rel.r_offset, dstsec->sh_size);
|
||||
return -EINVAL;
|
||||
relidx, i, rel->r_offset, dstsec->sh_size);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
addr = dstsec->sh_addr + rel.r_offset;
|
||||
addr = dstsec->sh_addr + rel->r_offset;
|
||||
|
||||
/* Now perform the architecture-specific relocation */
|
||||
|
||||
ret = up_relocate(&rel, psym, addr);
|
||||
ret = up_relocate(rel, psym, addr);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: Section %d reloc %d: Relocation failed: %d\n", relidx, i, ret);
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
lib_free(rels);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int modlib_relocateadd(FAR struct module_s *modp,
|
||||
|
|
Loading…
Reference in a new issue