diff --git a/arch/arm/src/arm/up_elf.c b/arch/arm/src/arm/up_elf.c index 433024b849..e46703563d 100644 --- a/arch/arm/src/arm/up_elf.c +++ b/arch/arm/src/arm/up_elf.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/arm/up_elf.c * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2012, 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -132,6 +132,10 @@ bool up_checkarch(FAR const Elf32_Ehdr *ehdr) * Input Parameters: * rel - The relocation type * sym - The ELF symbol structure containing the fully resolved value. + * There are a few relocation types for a few architectures that do + * not require symbol information. For those, this value will be + * NULL. Implementations of these functions must be able to handle + * that case. * addr - The address that requires the relocation. * * Returned Value: @@ -144,8 +148,19 @@ int up_relocate(FAR const Elf32_Rel *rel, FAR const Elf32_Sym *sym, uintptr_t addr) { int32_t offset; + unsigned int relotype; - switch (ELF32_R_TYPE(rel->r_info)) + /* All relocations depend upon having valid symbol information */ + + relotype = ELF32_R_TYPE(rel->r_info); + if (sym == NULL && relotype != R_ARM_NONE) + { + return -EINVAL; + } + + /* Handle the relocation by relocation type */ + + switch (relotype) { case R_ARM_NONE: { @@ -254,4 +269,3 @@ int up_relocateadd(FAR const Elf32_Rela *rel, FAR const Elf32_Sym *sym, bdbg("RELA relocation not supported\n"); return -ENOSYS; } - diff --git a/arch/arm/src/armv6-m/up_elf.c b/arch/arm/src/armv6-m/up_elf.c index 7c5b76c21b..d4529540ad 100644 --- a/arch/arm/src/armv6-m/up_elf.c +++ b/arch/arm/src/armv6-m/up_elf.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/armv6-m/up_elf.c * - * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2013-2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -124,6 +124,10 @@ bool up_checkarch(FAR const Elf32_Ehdr *ehdr) * Input Parameters: * rel - The relocation type * sym - The ELF symbol structure containing the fully resolved value. + * There are a few relocation types for a few architectures that do + * not require symbol information. For those, this value will be + * NULL. Implementations of these functions must be able to handle + * that case. * addr - The address that requires the relocation. * * Returned Value: @@ -138,8 +142,21 @@ int up_relocate(FAR const Elf32_Rel *rel, FAR const Elf32_Sym *sym, int32_t offset; uint32_t upper_insn; uint32_t lower_insn; + unsigned int relotype; - switch (ELF32_R_TYPE(rel->r_info)) + /* All relocations except R_ARM_V4BX depend upon having valid symbol + * information. + */ + + relotype = ELF32_R_TYPE(rel->r_info); + if (sym == NULL && relotype != R_ARM_NONE && relotype != R_ARM_V4BX) + { + return -EINVAL; + } + + /* Handle the relocation by relocation type */ + + switch (relotype) { case R_ARM_NONE: { @@ -447,4 +464,3 @@ int up_relocateadd(FAR const Elf32_Rela *rel, FAR const Elf32_Sym *sym, bdbg("RELA relocation not supported\n"); return -ENOSYS; } - diff --git a/arch/arm/src/armv7-a/arm_elf.c b/arch/arm/src/armv7-a/arm_elf.c index 0075f2e2a0..97b85620f2 100644 --- a/arch/arm/src/armv7-a/arm_elf.c +++ b/arch/arm/src/armv7-a/arm_elf.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/armv-7a/arm_elf.c * - * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2013-2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -132,6 +132,10 @@ bool up_checkarch(FAR const Elf32_Ehdr *ehdr) * Input Parameters: * rel - The relocation type * sym - The ELF symbol structure containing the fully resolved value. + * There are a few relocation types for a few architectures that do + * not require symbol information. For those, this value will be + * NULL. Implementations of these functions must be able to handle + * that case. * addr - The address that requires the relocation. * * Returned Value: @@ -144,8 +148,21 @@ int up_relocate(FAR const Elf32_Rel *rel, FAR const Elf32_Sym *sym, uintptr_t addr) { int32_t offset; + unsigned int relotype; - switch (ELF32_R_TYPE(rel->r_info)) + /* All relocations except R_ARM_V4BX depend upon having valid symbol + * information. + */ + + relotype = ELF32_R_TYPE(rel->r_info); + if (sym == NULL && relotype != R_ARM_NONE && relotype != R_ARM_V4BX) + { + return -EINVAL; + } + + /* Handle the relocation by relocation type */ + + switch (relotype) { case R_ARM_NONE: { @@ -254,4 +271,3 @@ int up_relocateadd(FAR const Elf32_Rela *rel, FAR const Elf32_Sym *sym, bdbg("RELA relocation not supported\n"); return -ENOSYS; } - diff --git a/arch/arm/src/armv7-m/up_elf.c b/arch/arm/src/armv7-m/up_elf.c index c4d30d936b..c1ea4e4941 100644 --- a/arch/arm/src/armv7-m/up_elf.c +++ b/arch/arm/src/armv7-m/up_elf.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/armv7-m/up_elf.c * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2012, 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -124,6 +124,10 @@ bool up_checkarch(FAR const Elf32_Ehdr *ehdr) * Input Parameters: * rel - The relocation type * sym - The ELF symbol structure containing the fully resolved value. + * There are a few relocation types for a few architectures that do + * not require symbol information. For those, this value will be + * NULL. Implementations of these functions must be able to handle + * that case. * addr - The address that requires the relocation. * * Returned Value: @@ -138,8 +142,21 @@ int up_relocate(FAR const Elf32_Rel *rel, FAR const Elf32_Sym *sym, int32_t offset; uint32_t upper_insn; uint32_t lower_insn; + unsigned int relotype; - switch (ELF32_R_TYPE(rel->r_info)) + /* All relocations except R_ARM_V4BX depend upon having valid symbol + * information. + */ + + relotype = ELF32_R_TYPE(rel->r_info); + if (sym == NULL && relotype != R_ARM_NONE && relotype != R_ARM_V4BX) + { + return -EINVAL; + } + + /* Handle the relocation by relocation type */ + + switch (relotype) { case R_ARM_NONE: { @@ -447,4 +464,3 @@ int up_relocateadd(FAR const Elf32_Rela *rel, FAR const Elf32_Sym *sym, bdbg("RELA relocation not supported\n"); return -ENOSYS; } - diff --git a/arch/sim/src/up_elf.c b/arch/sim/src/up_elf.c index 02b4ce7105..888b09077e 100644 --- a/arch/sim/src/up_elf.c +++ b/arch/sim/src/up_elf.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/sim/src/up_elf.c * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2012, 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -100,6 +100,10 @@ bool up_checkarch(FAR const Elf32_Ehdr *hdr) * Input Parameters: * rel - The relocation type * sym - The ELF symbol structure containing the fully resolved value. + * There are a few relocation types for a few architectures that do + * not require symbol information. For those, this value will be + * NULL. Implementations of these functions must be able to handle + * that case. * addr - The address that requires the relocation. * * Returned Value: @@ -113,6 +117,15 @@ int up_relocate(FAR const Elf32_Rel *rel, FAR const Elf32_Sym *sym, { FAR uint32_t *ptr = (FAR uint32_t *)addr; + /* All relocations depend upon having valid symbol information. */ + + if (sym == NULL) + { + return -EINVAL; + } + + /* Handle the relocation by relocation type */ + switch (ELF32_R_TYPE(rel->r_info)) { case R_386_32: @@ -124,7 +137,7 @@ int up_relocate(FAR const Elf32_Rel *rel, FAR const Elf32_Sym *sym, break; default: - return -EINVAL; + return -EINVAL; } return OK; diff --git a/arch/x86/src/common/up_elf.c b/arch/x86/src/common/up_elf.c index 7c5772a9bb..894f865786 100644 --- a/arch/x86/src/common/up_elf.c +++ b/arch/x86/src/common/up_elf.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/x86/src/up_elf.c * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2012, 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -100,6 +100,10 @@ bool up_checkarch(FAR const Elf32_Ehdr *hdr) * Input Parameters: * rel - The relocation type * sym - The ELF symbol structure containing the fully resolved value. + * There are a few relocation types for a few architectures that do + * not require symbol information. For those, this value will be + * NULL. Implementations of these functions must be able to handle + * that case. * addr - The address that requires the relocation. * * Returned Value: @@ -113,6 +117,15 @@ int up_relocate(FAR const Elf32_Rel *rel, FAR const Elf32_Sym *sym, { FAR uint32_t *ptr = (FAR uint32_t *)addr; + /* All relocations depend upon having valid symbol information. */ + + if (sym == NULL) + { + return -EINVAL; + } + + /* Handle the relocation by relocation type */ + switch (ELF32_R_TYPE(rel->r_info)) { case R_386_32: @@ -124,7 +137,7 @@ int up_relocate(FAR const Elf32_Rel *rel, FAR const Elf32_Sym *sym, break; default: - return -EINVAL; + return -EINVAL; } return OK; diff --git a/binfmt/libelf/libelf.h b/binfmt/libelf/libelf.h index e1382ee2da..4304e64f29 100644 --- a/binfmt/libelf/libelf.h +++ b/binfmt/libelf/libelf.h @@ -174,6 +174,12 @@ int elf_readsym(FAR struct elf_loadinfo_s *loadinfo, int index, * 0 (OK) is returned on success and a negated errno is returned on * failure. * + * EINVAL - There is something inconsistent in the symbol table (should only + * happen if the file is corrupted) + * ENOSYS - Symbol lies in common + * ESRCH - Symbol has no name + * ENOENT - Symbol undefined and not provided via a symbol table + * ****************************************************************************/ int elf_symvalue(FAR struct elf_loadinfo_s *loadinfo, FAR Elf32_Sym *sym, diff --git a/binfmt/libelf/libelf_bind.c b/binfmt/libelf/libelf_bind.c index 608f65ef7a..58ceb148f8 100644 --- a/binfmt/libelf/libelf_bind.c +++ b/binfmt/libelf/libelf_bind.c @@ -136,6 +136,7 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx, FAR Elf32_Shdr *dstsec = &loadinfo->shdr[relsec->sh_info]; Elf32_Rel rel; Elf32_Sym sym; + FAR Elf32_Sym *psym; uintptr_t addr; int symidx; int ret; @@ -148,6 +149,8 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx, 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); @@ -179,9 +182,28 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx, ret = elf_symvalue(loadinfo, &sym, exports, nexports); if (ret < 0) { - bdbg("Section %d reloc %d: Failed to get value of symbol[%d]: %d\n", - relidx, i, symidx, ret); - return ret; + /* 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) + { + bdbg("Section %d reloc %d: Undefined symbol[%d] has no name: %d\n", + relidx, i, symidx, ret); + psym = NULL; + } + else + { + bdbg("Section %d reloc %d: Failed to get value of symbol[%d]: %d\n", + relidx, i, symidx, ret); + return ret; + } } /* Calculate the relocation address. */ @@ -197,7 +219,7 @@ static int elf_relocate(FAR struct elf_loadinfo_s *loadinfo, int relidx, /* Now perform the architecture-specific relocation */ - ret = up_relocate(&rel, &sym, addr); + ret = up_relocate(&rel, psym, addr); if (ret < 0) { bdbg("ERROR: Section %d reloc %d: Relocation failed: %d\n", ret); diff --git a/binfmt/libelf/libelf_symbols.c b/binfmt/libelf/libelf_symbols.c index bd7942a670..40831d2ec3 100644 --- a/binfmt/libelf/libelf_symbols.c +++ b/binfmt/libelf/libelf_symbols.c @@ -1,7 +1,7 @@ /**************************************************************************** * binfmt/libelf/libelf_symbols.c * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2012, 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -76,6 +76,10 @@ * 0 (OK) is returned on success and a negated errno is returned on * failure. * + * EINVAL - There is something inconsistent in the symbol table (should only + * happen if the file is corrupted). + * ESRCH - Symbol has no name + * ****************************************************************************/ static int elf_symname(FAR struct elf_loadinfo_s *loadinfo, @@ -94,7 +98,7 @@ static int elf_symname(FAR struct elf_loadinfo_s *loadinfo, if (sym->st_name == 0) { bdbg("Symbol has no name\n"); - return -ENOENT; + return -ESRCH; } offset = loadinfo->shdr[loadinfo->strtabidx].sh_offset + sym->st_name; @@ -253,6 +257,12 @@ int elf_readsym(FAR struct elf_loadinfo_s *loadinfo, int index, * 0 (OK) is returned on success and a negated errno is returned on * failure. * + * EINVAL - There is something inconsistent in the symbol table (should only + * happen if the file is corrupted). + * ENOSYS - Symbol lies in common + * ESRCH - Symbol has no name + * ENOENT - Symbol undefined and not provided via a symbol table + * ****************************************************************************/ int elf_symvalue(FAR struct elf_loadinfo_s *loadinfo, FAR Elf32_Sym *sym, @@ -269,7 +279,7 @@ int elf_symvalue(FAR struct elf_loadinfo_s *loadinfo, FAR Elf32_Sym *sym, /* NuttX ELF modules should be compiled with -fno-common. */ bdbg("SHN_COMMON: Re-compile with -fno-common\n"); - return -EINVAL; + return -ENOSYS; } case SHN_ABS: @@ -287,6 +297,12 @@ int elf_symvalue(FAR struct elf_loadinfo_s *loadinfo, FAR Elf32_Sym *sym, ret = elf_symname(loadinfo, sym); if (ret < 0) { + /* 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 return and special error to the caller to + * indicate the nameless symbol. + */ + bdbg("SHN_UNDEF: Failed to get symbol name: %d\n", ret); return ret; } diff --git a/include/nuttx/binfmt/elf.h b/include/nuttx/binfmt/elf.h index 9f74d5bd4a..3d5e9e2ad3 100644 --- a/include/nuttx/binfmt/elf.h +++ b/include/nuttx/binfmt/elf.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/nuttx/binfmt/elf.h * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2012, 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -303,6 +303,10 @@ bool up_checkarch(FAR const Elf32_Ehdr *hdr); * Input Parameters: * rel - The relocation type * sym - The ELF symbol structure containing the fully resolved value. + * There are a few relocation types for a few architectures that do + * not require symbol information. For those, this value will be + * NULL. Implementations of these functions must be able to handle + * that case. * addr - The address that requires the relocation. * * Returned Value: