From 2f2d432f7c45fe69e7778dbbcccfd35e20581118 Mon Sep 17 00:00:00 2001 From: anchao Date: Tue, 19 Mar 2019 08:57:13 -0600 Subject: [PATCH] binfmt/libelf and libs/libc/modlib: Add relocation buffer table to reduce access fs. --- binfmt/Kconfig | 1 - binfmt/libelf/Kconfig | 7 ++++ binfmt/libelf/libelf_bind.c | 72 ++++++++++++++++++++++----------- libs/libc/modlib/Kconfig | 7 ++++ libs/libc/modlib/modlib_bind.c | 74 +++++++++++++++++++++++----------- 5 files changed, 113 insertions(+), 48 deletions(-) diff --git a/binfmt/Kconfig b/binfmt/Kconfig index 7606376c7f..f6478209c1 100644 --- a/binfmt/Kconfig +++ b/binfmt/Kconfig @@ -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. - diff --git a/binfmt/libelf/Kconfig b/binfmt/libelf/Kconfig index 4e61ebe068..719234984c 100644 --- a/binfmt/libelf/Kconfig +++ b/binfmt/libelf/Kconfig @@ -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 diff --git a/binfmt/libelf/libelf_bind.c b/binfmt/libelf/libelf_bind.c index 3678a009b8..8f86c595af 100644 --- a/binfmt/libelf/libelf_bind.c +++ b/binfmt/libelf/libelf_bind.c @@ -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 * * Redistribution and use in source and binary forms, with or without @@ -46,6 +46,7 @@ #include #include +#include #include #include @@ -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, diff --git a/libs/libc/modlib/Kconfig b/libs/libc/modlib/Kconfig index a79b02fb3b..ea9905627e 100644 --- a/libs/libc/modlib/Kconfig +++ b/libs/libc/modlib/Kconfig @@ -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 diff --git a/libs/libc/modlib/modlib_bind.c b/libs/libc/modlib/modlib_bind.c index 606cf6b283..7dd57fcaab 100644 --- a/libs/libc/modlib/modlib_bind.c +++ b/libs/libc/modlib/modlib_bind.c @@ -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 * * Redistribution and use in source and binary forms, with or without @@ -48,6 +48,7 @@ #include #include +#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,