summaryrefslogtreecommitdiffstats
path: root/lib/libelf/elf_scn.c
diff options
context:
space:
mode:
authorjkoshy <jkoshy@FreeBSD.org>2006-12-25 02:22:22 +0000
committerjkoshy <jkoshy@FreeBSD.org>2006-12-25 02:22:22 +0000
commit26d8253ac6532abcb8d1c8d57743998f5368173b (patch)
tree1f1c4db9c6b866adf56e5cc3eccd23baaa57af28 /lib/libelf/elf_scn.c
parent44313eba34c379a180dc73dcd02ab9c415941db3 (diff)
downloadFreeBSD-src-26d8253ac6532abcb8d1c8d57743998f5368173b.zip
FreeBSD-src-26d8253ac6532abcb8d1c8d57743998f5368173b.tar.gz
Keep shadow copies of the `e_shnum', `e_phnum' and `e_shstrndx'
members of the ELF Executable Header inside the library-private `struct _Elf' descriptor and only update the underlying Elf{32,64}_Ehdr structure on an elf_update(3) call. These fields of the Ehdr structure are technically `out of bounds' for an application program per the ELF(3) API, but we've seen applications that initialize a new Ehdr structure using memcpy(), messing up the library's invariants. [1] Implement elf_getphnum() and handle ELF objects with more than 64K program header table entries. Reported by: jb [1]
Diffstat (limited to 'lib/libelf/elf_scn.c')
-rw-r--r--lib/libelf/elf_scn.c68
1 files changed, 26 insertions, 42 deletions
diff --git a/lib/libelf/elf_scn.c b/lib/libelf/elf_scn.c
index fa1527f..139f6d9 100644
--- a/lib/libelf/elf_scn.c
+++ b/lib/libelf/elf_scn.c
@@ -44,7 +44,6 @@ _libelf_load_scn(Elf *e, void *ehdr)
int ec, swapbytes;
size_t fsz, i, shnum;
uint64_t shoff;
- uint32_t shtype;
char *src;
Elf32_Ehdr *eh32;
Elf64_Ehdr *eh64;
@@ -53,6 +52,7 @@ _libelf_load_scn(Elf *e, void *ehdr)
assert(e != NULL);
assert(ehdr != NULL);
+ assert((e->e_flags & LIBELF_F_SHDRS_LOADED) == 0);
#define CHECK_EHDR(E,EH) do { \
if (fsz != (EH)->e_shentsize || \
@@ -62,18 +62,18 @@ _libelf_load_scn(Elf *e, void *ehdr)
} \
} while (0)
- fsz = gelf_fsize(e, ELF_T_SHDR, (size_t) 1, e->e_version);
+ ec = e->e_class;
+ fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1);
assert(fsz > 0);
- ec = e->e_class;
+ shnum = e->e_u.e_elf.e_nscn;
+
if (ec == ELFCLASS32) {
eh32 = (Elf32_Ehdr *) ehdr;
- shnum = eh32->e_shnum;
shoff = (uint64_t) eh32->e_shoff;
CHECK_EHDR(e, eh32);
} else {
eh64 = (Elf64_Ehdr *) ehdr;
- shnum = eh64->e_shnum;
shoff = eh64->e_shoff;
CHECK_EHDR(e, eh64);
}
@@ -82,32 +82,18 @@ _libelf_load_scn(Elf *e, void *ehdr)
swapbytes = e->e_byteorder != LIBELF_PRIVATE(byteorder);
src = e->e_rawfile + shoff;
- i = 0;
-
- if (shnum == (size_t) 0 && shoff != 0LL) {
- /* Extended section numbering */
- if ((scn = _libelf_allocate_scn(e, (size_t) 0)) == NULL)
- return (0);
-
- (*xlator)((char *) &scn->s_shdr, src, (size_t) 1, swapbytes);
-
- if (ec == ELFCLASS32) {
- shtype = scn->s_shdr.s_shdr32.sh_type;
- shnum = scn->s_shdr.s_shdr32.sh_size;
- } else {
- shtype = scn->s_shdr.s_shdr64.sh_type;
- shnum = scn->s_shdr.s_shdr64.sh_size;
- }
- if (shtype != SHT_NULL) {
- LIBELF_SET_ERROR(SECTION, 0);
- return (0);
- }
+ /*
+ * If the file is using extended numbering then section #0
+ * would have already been read in.
+ */
- scn->s_size = 0LL;
- scn->s_offset = scn->s_rawoff = 0LL;
+ i = 0;
+ if (!STAILQ_EMPTY(&e->e_u.e_elf.e_scn)) {
+ assert(STAILQ_FIRST(&e->e_u.e_elf.e_scn) ==
+ STAILQ_LAST(&e->e_u.e_elf.e_scn, _Elf_Scn, s_next));
- i++;
+ i = 1;
src += fsz;
}
@@ -127,6 +113,9 @@ _libelf_load_scn(Elf *e, void *ehdr)
scn->s_size = scn->s_shdr.s_shdr64.sh_size;
}
}
+
+ e->e_flags |= LIBELF_F_SHDRS_LOADED;
+
return (1);
}
@@ -147,7 +136,8 @@ elf_getscn(Elf *e, size_t index)
if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
return (NULL);
- if (e->e_cmd != ELF_C_WRITE && STAILQ_EMPTY(&e->e_u.e_elf.e_scn) &&
+ if (e->e_cmd != ELF_C_WRITE &&
+ (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 &&
_libelf_load_scn(e, ehdr) == 0)
return (NULL);
@@ -174,7 +164,6 @@ elf_newscn(Elf *e)
{
int ec;
void *ehdr;
- size_t shnum;
Elf_Scn *scn;
if (e == NULL || e->e_kind != ELF_K_ELF) {
@@ -200,30 +189,25 @@ elf_newscn(Elf *e)
* file using ELF_C_READ, mess with its internal structure and
* use elf_update(...,ELF_C_NULL) to compute its new layout.
*/
- if (e->e_cmd != ELF_C_WRITE && STAILQ_EMPTY(&e->e_u.e_elf.e_scn) &&
+ if (e->e_cmd != ELF_C_WRITE &&
+ (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 &&
_libelf_load_scn(e, ehdr) == 0)
return (NULL);
- if (_libelf_getshnum(e, ehdr, ec, &shnum) == 0)
- return (NULL);
-
if (STAILQ_EMPTY(&e->e_u.e_elf.e_scn)) {
- assert(shnum == 0);
+ assert(e->e_u.e_elf.e_nscn == 0);
if ((scn = _libelf_allocate_scn(e, (size_t) SHN_UNDEF)) ==
NULL)
return (NULL);
- shnum++;
+ e->e_u.e_elf.e_nscn++;
}
- assert(shnum > 0);
+ assert(e->e_u.e_elf.e_nscn > 0);
- if ((scn = _libelf_allocate_scn(e, shnum)) == NULL)
+ if ((scn = _libelf_allocate_scn(e, e->e_u.e_elf.e_nscn)) == NULL)
return (NULL);
- shnum++;
-
- if (_libelf_setshnum(e, ehdr, ec, shnum) == 0)
- return (NULL);
+ e->e_u.e_elf.e_nscn++;
(void) elf_flagscn(scn, ELF_C_SET, ELF_F_DIRTY);
OpenPOWER on IntegriCloud