mirror of
https://github.com/apache/nuttx.git
synced 2026-10-11 00:00:24 +00:00
tools/nxflat: Split the ELF reader out of mknxflat.
The converter that follows reads the same objects as mknxflat, so the reader goes into a file of its own before it gains a second user. nxflat_elf.c normalises the tables that describe the object -- the headers, the symbols, the relocation entries -- into the host's order, and leaves the section contents alone, because those are the target's bytes and the tools write them out again. A tool reads a field without knowing whose order it arrived in. The -d option goes with it. It chose a dynamic symbol table, which the ld -r object these tools convert does not have, and which the NXFLAT loader cannot use anyway: imports reach a module through the array mknxflat generates. The output is unchanged. The thunk mknxflat generates for each of the eleven modules of apps/examples/nxflat/tests is byte identical to the one the previous version generated. Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
This commit is contained in:
parent
60d01d779f
commit
31acf10057
4 changed files with 483 additions and 285 deletions
|
|
@ -137,7 +137,8 @@ endif
|
|||
|
||||
# mknxflat - Generate the thunk file for an NXFLAT module
|
||||
|
||||
MKNXFLAT_SRCS = nxflat/mknxflat.c nxflat/thunk_arm.c nxflat/thunk_thumb2.c
|
||||
MKNXFLAT_SRCS = nxflat/mknxflat.c nxflat/thunk_arm.c nxflat/thunk_thumb2.c \
|
||||
nxflat/nxflat_elf.c
|
||||
|
||||
mknxflat$(HOSTEXEEXT): $(MKNXFLAT_SRCS)
|
||||
$(Q) $(HOSTCC) $(HOSTCFLAGS) -Inxflat -o mknxflat$(HOSTEXEEXT) \
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@
|
|||
* dependency was never deep: the upstream tool used it only to open the
|
||||
* file and enumerate symbols, never to relocate or rewrite anything.
|
||||
*
|
||||
* The reading itself is in nxflat_elf.c, which ldnxflat uses as well.
|
||||
*
|
||||
* The emitted text is unchanged. The format strings live in the .def
|
||||
* files, which are carried here byte-for-byte from upstream.
|
||||
****************************************************************************/
|
||||
|
|
@ -50,8 +52,29 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "nxflat_elf.h"
|
||||
#include "nxflat_thunk.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define STB_WEAK 2
|
||||
#define MAX_EXPORT_NAMES 1024
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* One imported symbol, in symbol table order */
|
||||
|
||||
struct import_s
|
||||
{
|
||||
const char *name;
|
||||
int is_object;
|
||||
int is_weak;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
|
@ -71,78 +94,6 @@
|
|||
*/
|
||||
|
||||
#define EI_NIDENT 16
|
||||
#define ELFCLASS32 1
|
||||
#define ELFDATA2LSB 1
|
||||
#define ELFDATA2MSB 2
|
||||
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_DYNSYM 11
|
||||
|
||||
#define SHN_UNDEF 0
|
||||
|
||||
#define STB_WEAK 2
|
||||
#define STT_OBJECT 1
|
||||
|
||||
#define ELF_ST_BIND(i) ((i) >> 4)
|
||||
#define ELF_ST_TYPE(i) ((i) & 0x0f)
|
||||
|
||||
#define MAX_EXPORT_NAMES 1024
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct elf32_ehdr_s
|
||||
{
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
uint32_t e_entry;
|
||||
uint32_t e_phoff;
|
||||
uint32_t e_shoff;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_ehsize;
|
||||
uint16_t e_phentsize;
|
||||
uint16_t e_phnum;
|
||||
uint16_t e_shentsize;
|
||||
uint16_t e_shnum;
|
||||
uint16_t e_shstrndx;
|
||||
};
|
||||
|
||||
struct elf32_shdr_s
|
||||
{
|
||||
uint32_t sh_name;
|
||||
uint32_t sh_type;
|
||||
uint32_t sh_flags;
|
||||
uint32_t sh_addr;
|
||||
uint32_t sh_offset;
|
||||
uint32_t sh_size;
|
||||
uint32_t sh_link;
|
||||
uint32_t sh_info;
|
||||
uint32_t sh_addralign;
|
||||
uint32_t sh_entsize;
|
||||
};
|
||||
|
||||
struct elf32_sym_s
|
||||
{
|
||||
uint32_t st_name;
|
||||
uint32_t st_value;
|
||||
uint32_t st_size;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
uint16_t st_shndx;
|
||||
};
|
||||
|
||||
/* One imported symbol, in symbol table order */
|
||||
|
||||
struct import_s
|
||||
{
|
||||
const char *name;
|
||||
int is_object;
|
||||
int is_weak;
|
||||
};
|
||||
|
||||
typedef int (*namefunc_type)(const char *name, void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -153,7 +104,6 @@ typedef int (*namefunc_type)(const char *name, void *arg);
|
|||
|
||||
static int verbose = 0;
|
||||
static int weak_imports = 0;
|
||||
static int dsyms = 0;
|
||||
|
||||
/* Characteristics of things */
|
||||
|
||||
|
|
@ -176,12 +126,6 @@ static long number_undefined = 0;
|
|||
|
||||
static int counter;
|
||||
|
||||
/* Big-endian input? ARM is normally little-endian but big-endian ARM
|
||||
* exists, so honour EI_DATA rather than assuming.
|
||||
*/
|
||||
|
||||
static int need_swap = 0;
|
||||
|
||||
/****************************************************************************
|
||||
* Private constant data
|
||||
****************************************************************************/
|
||||
|
|
@ -208,70 +152,6 @@ static const char *const nonreturners[] =
|
|||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: swap16 / swap32
|
||||
****************************************************************************/
|
||||
|
||||
static uint16_t swap16(uint16_t v)
|
||||
{
|
||||
return need_swap ? (uint16_t)((v >> 8) | (v << 8)) : v;
|
||||
}
|
||||
|
||||
static uint32_t swap32(uint32_t v)
|
||||
{
|
||||
if (!need_swap)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
return ((v & 0x000000fful) << 24) | ((v & 0x0000ff00ul) << 8) |
|
||||
((v & 0x00ff0000ul) >> 8) | ((v & 0xff000000ul) >> 24);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: xread
|
||||
*
|
||||
* Description:
|
||||
* Read exactly nbytes at an absolute offset, or die.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void xread(int fd, void *buffer, size_t nbytes, off_t offset)
|
||||
{
|
||||
ssize_t nread;
|
||||
|
||||
if (lseek(fd, offset, SEEK_SET) == (off_t)-1)
|
||||
{
|
||||
fprintf(stderr, "%s: seek to %ld failed: %s\n",
|
||||
elf_filename, (long)offset, strerror(errno));
|
||||
exit(2);
|
||||
}
|
||||
|
||||
while (nbytes > 0)
|
||||
{
|
||||
nread = read(fd, buffer, nbytes);
|
||||
if (nread < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s: read failed: %s\n",
|
||||
elf_filename, strerror(errno));
|
||||
exit(2);
|
||||
}
|
||||
else if (nread == 0)
|
||||
{
|
||||
fprintf(stderr, "%s: unexpected end of file\n", elf_filename);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
buffer = (char *)buffer + nread;
|
||||
nbytes -= nread;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: load_imports
|
||||
*
|
||||
|
|
@ -290,136 +170,29 @@ static void xread(int fd, void *buffer, size_t nbytes, off_t offset)
|
|||
|
||||
static void load_imports(void)
|
||||
{
|
||||
struct elf32_ehdr_s ehdr;
|
||||
struct elf32_shdr_s *shdrs;
|
||||
struct elf32_sym_s *syms;
|
||||
char *strtab;
|
||||
int wanted = dsyms ? SHT_DYNSYM : SHT_SYMTAB;
|
||||
int symidx = -1;
|
||||
size_t nsyms;
|
||||
size_t strsize;
|
||||
struct nxflat_elf_s elf;
|
||||
size_t strsize = 0;
|
||||
size_t i;
|
||||
uint16_t probe;
|
||||
int host_le;
|
||||
int obj_le;
|
||||
int fd;
|
||||
|
||||
fd = open(elf_filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
nxflat_elf_read(&elf, elf_filename, program_name);
|
||||
|
||||
/* The size of the string table the symbols point into, which bounds
|
||||
* st_name. nxflat_elf_read() has located the table itself.
|
||||
*/
|
||||
|
||||
for (i = 0; i < elf.ehdr->e_shnum; i++)
|
||||
{
|
||||
fprintf(stderr, "%s: cannot open: %s\n",
|
||||
elf_filename, strerror(errno));
|
||||
exit(2);
|
||||
}
|
||||
|
||||
xread(fd, &ehdr, sizeof(ehdr), 0);
|
||||
|
||||
if (memcmp(ehdr.e_ident, "\177ELF", 4) != 0)
|
||||
{
|
||||
fprintf(stderr, "%s: not an ELF file\n", elf_filename);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if (ehdr.e_ident[4] != ELFCLASS32)
|
||||
{
|
||||
fprintf(stderr, "%s: not a 32-bit ELF file\n", elf_filename);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
/* Decide whether the host and the object disagree about byte order */
|
||||
|
||||
probe = 1;
|
||||
host_le = *(const unsigned char *)&probe;
|
||||
obj_le = (ehdr.e_ident[5] == ELFDATA2LSB);
|
||||
|
||||
need_swap = (host_le != obj_le);
|
||||
|
||||
/* Re-read the fields that mattered now that byte order is known */
|
||||
|
||||
ehdr.e_shoff = swap32(ehdr.e_shoff);
|
||||
ehdr.e_shnum = swap16(ehdr.e_shnum);
|
||||
ehdr.e_shentsize = swap16(ehdr.e_shentsize);
|
||||
|
||||
if (ehdr.e_shnum == 0 || ehdr.e_shentsize != sizeof(struct elf32_shdr_s))
|
||||
{
|
||||
fprintf(stderr, "%s: no usable section header table\n", elf_filename);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
shdrs = malloc((size_t)ehdr.e_shnum * sizeof(struct elf32_shdr_s));
|
||||
if (shdrs == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to allocate section headers\n");
|
||||
exit(3);
|
||||
}
|
||||
|
||||
xread(fd, shdrs, (size_t)ehdr.e_shnum * sizeof(struct elf32_shdr_s),
|
||||
ehdr.e_shoff);
|
||||
|
||||
for (i = 0; i < ehdr.e_shnum; i++)
|
||||
{
|
||||
shdrs[i].sh_type = swap32(shdrs[i].sh_type);
|
||||
shdrs[i].sh_offset = swap32(shdrs[i].sh_offset);
|
||||
shdrs[i].sh_size = swap32(shdrs[i].sh_size);
|
||||
shdrs[i].sh_link = swap32(shdrs[i].sh_link);
|
||||
shdrs[i].sh_entsize = swap32(shdrs[i].sh_entsize);
|
||||
|
||||
if ((int)shdrs[i].sh_type == wanted && symidx < 0)
|
||||
if (elf.shdr[i].sh_type == SHT_SYMTAB)
|
||||
{
|
||||
symidx = (int)i;
|
||||
strsize = elf.shdr[elf.shdr[i].sh_link].sh_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (symidx < 0)
|
||||
{
|
||||
fprintf(stderr, "%s: no %s section\n", elf_filename,
|
||||
dsyms ? "dynamic symbol table" : "symbol table");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if (shdrs[symidx].sh_entsize != sizeof(struct elf32_sym_s))
|
||||
{
|
||||
fprintf(stderr, "%s: unexpected symbol entry size\n", elf_filename);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
nsyms = shdrs[symidx].sh_size / sizeof(struct elf32_sym_s);
|
||||
|
||||
syms = malloc(shdrs[symidx].sh_size);
|
||||
if (syms == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to allocate symbol table\n");
|
||||
exit(3);
|
||||
}
|
||||
|
||||
xread(fd, syms, shdrs[symidx].sh_size, shdrs[symidx].sh_offset);
|
||||
|
||||
/* The linked string table holds the names */
|
||||
|
||||
if (shdrs[symidx].sh_link >= ehdr.e_shnum)
|
||||
{
|
||||
fprintf(stderr, "%s: symbol table has no string table\n",
|
||||
elf_filename);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
strsize = shdrs[shdrs[symidx].sh_link].sh_size;
|
||||
strtab = malloc(strsize + 1);
|
||||
if (strtab == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to allocate string table\n");
|
||||
exit(3);
|
||||
}
|
||||
|
||||
xread(fd, strtab, strsize, shdrs[shdrs[symidx].sh_link].sh_offset);
|
||||
strtab[strsize] = '\0';
|
||||
|
||||
close(fd);
|
||||
|
||||
imports = calloc(nsyms + 1, sizeof(struct import_s));
|
||||
imports = malloc((elf.nsyms + 1) * sizeof(struct import_s));
|
||||
if (imports == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to allocate import table\n");
|
||||
fprintf(stderr, "Failed to allocate imports\n");
|
||||
exit(3);
|
||||
}
|
||||
|
||||
|
|
@ -434,20 +207,18 @@ static void load_imports(void)
|
|||
imports[0].is_weak = 0;
|
||||
number_undefined = 1;
|
||||
|
||||
for (i = 0; i < nsyms; i++)
|
||||
for (i = 0; i < elf.nsyms; i++)
|
||||
{
|
||||
uint32_t st_name = swap32(syms[i].st_name);
|
||||
uint32_t st_value = swap32(syms[i].st_value);
|
||||
uint16_t st_shndx = swap16(syms[i].st_shndx);
|
||||
unsigned char info = syms[i].st_info;
|
||||
const struct elf32_sym_s *sym = &elf.syms[i];
|
||||
unsigned char info = sym->st_info;
|
||||
|
||||
if (st_shndx != SHN_UNDEF || st_value != 0 || st_name == 0 ||
|
||||
st_name >= strsize)
|
||||
if (sym->st_shndx != SHN_UNDEF || sym->st_value != 0 ||
|
||||
sym->st_name == 0 || sym->st_name >= strsize)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ELF_ST_TYPE(info) == STT_OBJECT)
|
||||
if (ELF32_ST_TYPE(info) == STT_OBJECT)
|
||||
{
|
||||
/* An undefined object is not something a thunk can stand in
|
||||
* for; leave it to the link to complain.
|
||||
|
|
@ -456,16 +227,13 @@ static void load_imports(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
imports[number_undefined].name = &strtab[st_name];
|
||||
imports[number_undefined].name = elf.strtab + sym->st_name;
|
||||
imports[number_undefined].is_object = 0;
|
||||
imports[number_undefined].is_weak =
|
||||
(ELF_ST_BIND(info) == STB_WEAK);
|
||||
imports[number_undefined].is_weak =
|
||||
(ELF32_ST_BIND(info) == STB_WEAK);
|
||||
number_undefined++;
|
||||
}
|
||||
|
||||
free(shdrs);
|
||||
free(syms);
|
||||
|
||||
dbg("Found %ld undefined symbols\n", number_undefined);
|
||||
}
|
||||
|
||||
|
|
@ -631,7 +399,6 @@ static void show_usage(void)
|
|||
fprintf(stderr, " -a <arch>\n");
|
||||
fprintf(stderr, " Instruction set of the module: arm or thumb2\n");
|
||||
fprintf(stderr, " [thumb2]\n");
|
||||
fprintf(stderr, " -d Use dynamic symbol table. [symtab]\n");
|
||||
fprintf(stderr, " -o <out-filename>\n");
|
||||
fprintf(stderr, " Output to <out-filename> [stdout]\n");
|
||||
fprintf(stderr, " -v Verbose output [no output]\n");
|
||||
|
|
@ -653,7 +420,7 @@ static void parse_args(int argc, char **argv)
|
|||
|
||||
program_name = argv[0];
|
||||
|
||||
while ((opt = getopt(argc, argv, "a:do:vw")) != -1)
|
||||
while ((opt = getopt(argc, argv, "a:o:vw")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
|
|
@ -661,10 +428,6 @@ static void parse_args(int argc, char **argv)
|
|||
arch = optarg;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
dsyms++;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
out_filename = optarg;
|
||||
break;
|
||||
|
|
|
|||
263
tools/nxflat/nxflat_elf.c
Normal file
263
tools/nxflat/nxflat_elf.c
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
/****************************************************************************
|
||||
* tools/nxflat/nxflat_elf.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Reading the object is the one thing mknxflat and ldnxflat both do, so they
|
||||
* do it here. The two also used to disagree about byte order: one swapped
|
||||
* the fields it read, the other refused anything but little endian.
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "nxflat_elf.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static bool g_swap; /* The object disagrees with this host */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static uint16_t swap16(uint16_t v)
|
||||
{
|
||||
return g_swap ? (uint16_t)((v >> 8) | (v << 8)) : v;
|
||||
}
|
||||
|
||||
static uint32_t swap32(uint32_t v)
|
||||
{
|
||||
if (!g_swap)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
return ((v >> 24) & 0x000000ff) | ((v >> 8) & 0x0000ff00) |
|
||||
((v << 8) & 0x00ff0000) | ((v << 24) & 0xff000000);
|
||||
}
|
||||
|
||||
static void elf_fail(const char *program, const char *path, const char *why)
|
||||
{
|
||||
fprintf(stderr, "%s: %s: %s\n", program, path, why);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: normalise
|
||||
*
|
||||
* Description:
|
||||
* Put every table that describes the object into the host's byte order.
|
||||
* The section contents are not touched: they belong to the target.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void normalise(struct nxflat_elf_s *elf)
|
||||
{
|
||||
size_t i;
|
||||
size_t j;
|
||||
|
||||
elf->ehdr->e_type = swap16(elf->ehdr->e_type);
|
||||
elf->ehdr->e_machine = swap16(elf->ehdr->e_machine);
|
||||
elf->ehdr->e_entry = swap32(elf->ehdr->e_entry);
|
||||
elf->ehdr->e_shoff = swap32(elf->ehdr->e_shoff);
|
||||
elf->ehdr->e_shentsize = swap16(elf->ehdr->e_shentsize);
|
||||
elf->ehdr->e_shnum = swap16(elf->ehdr->e_shnum);
|
||||
elf->ehdr->e_shstrndx = swap16(elf->ehdr->e_shstrndx);
|
||||
|
||||
elf->shdr = (struct elf32_shdr_s *)(elf->img + elf->ehdr->e_shoff);
|
||||
|
||||
for (i = 0; i < elf->ehdr->e_shnum; i++)
|
||||
{
|
||||
struct elf32_shdr_s *s = &elf->shdr[i];
|
||||
|
||||
s->sh_name = swap32(s->sh_name);
|
||||
s->sh_type = swap32(s->sh_type);
|
||||
s->sh_flags = swap32(s->sh_flags);
|
||||
s->sh_addr = swap32(s->sh_addr);
|
||||
s->sh_offset = swap32(s->sh_offset);
|
||||
s->sh_size = swap32(s->sh_size);
|
||||
s->sh_link = swap32(s->sh_link);
|
||||
s->sh_info = swap32(s->sh_info);
|
||||
s->sh_addralign = swap32(s->sh_addralign);
|
||||
s->sh_entsize = swap32(s->sh_entsize);
|
||||
}
|
||||
|
||||
/* The symbol and relocation tables describe the object too. Everything
|
||||
* else is left alone.
|
||||
*/
|
||||
|
||||
for (i = 0; i < elf->ehdr->e_shnum; i++)
|
||||
{
|
||||
struct elf32_shdr_s *s = &elf->shdr[i];
|
||||
|
||||
if (s->sh_type == SHT_SYMTAB && s->sh_entsize == sizeof(*elf->syms))
|
||||
{
|
||||
struct elf32_sym_s *syms =
|
||||
(struct elf32_sym_s *)(elf->img + s->sh_offset);
|
||||
|
||||
for (j = 0; j < s->sh_size / sizeof(*syms); j++)
|
||||
{
|
||||
syms[j].st_name = swap32(syms[j].st_name);
|
||||
syms[j].st_value = swap32(syms[j].st_value);
|
||||
syms[j].st_size = swap32(syms[j].st_size);
|
||||
syms[j].st_shndx = swap16(syms[j].st_shndx);
|
||||
}
|
||||
}
|
||||
else if (s->sh_type == SHT_REL &&
|
||||
s->sh_entsize == sizeof(struct elf32_rel_s))
|
||||
{
|
||||
struct elf32_rel_s *rel =
|
||||
(struct elf32_rel_s *)(elf->img + s->sh_offset);
|
||||
|
||||
for (j = 0; j < s->sh_size / sizeof(*rel); j++)
|
||||
{
|
||||
rel[j].r_offset = swap32(rel[j].r_offset);
|
||||
rel[j].r_info = swap32(rel[j].r_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
void nxflat_elf_read(struct nxflat_elf_s *elf, const char *path,
|
||||
const char *program)
|
||||
{
|
||||
struct stat st;
|
||||
uint16_t probe = 1;
|
||||
bool host_le;
|
||||
int symidx = -1;
|
||||
size_t i;
|
||||
int fd;
|
||||
|
||||
memset(elf, 0, sizeof(*elf));
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0 || fstat(fd, &st) < 0)
|
||||
{
|
||||
elf_fail(program, path, strerror(errno));
|
||||
}
|
||||
|
||||
elf->size = (size_t)st.st_size;
|
||||
elf->img = malloc(elf->size);
|
||||
if (elf->img == NULL)
|
||||
{
|
||||
elf_fail(program, path, "out of memory");
|
||||
}
|
||||
|
||||
if (read(fd, elf->img, elf->size) != (ssize_t)elf->size)
|
||||
{
|
||||
elf_fail(program, path, strerror(errno));
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
if (elf->size < sizeof(struct elf32_ehdr_s) ||
|
||||
memcmp(elf->img, "\177ELF", 4) != 0)
|
||||
{
|
||||
elf_fail(program, path, "not an ELF file");
|
||||
}
|
||||
|
||||
elf->ehdr = (struct elf32_ehdr_s *)elf->img;
|
||||
|
||||
if (elf->ehdr->e_ident[4] != ELFCLASS32)
|
||||
{
|
||||
elf_fail(program, path, "not a 32-bit ELF file");
|
||||
}
|
||||
|
||||
if (elf->ehdr->e_ident[5] != ELFDATA2LSB &&
|
||||
elf->ehdr->e_ident[5] != ELFDATA2MSB)
|
||||
{
|
||||
elf_fail(program, path, "has no byte order");
|
||||
}
|
||||
|
||||
elf->littleendian = elf->ehdr->e_ident[5] == ELFDATA2LSB;
|
||||
|
||||
host_le = *(const unsigned char *)&probe != 0;
|
||||
g_swap = host_le != elf->littleendian;
|
||||
|
||||
normalise(elf);
|
||||
|
||||
if (elf->ehdr->e_shnum == 0 ||
|
||||
elf->ehdr->e_shentsize != sizeof(struct elf32_shdr_s))
|
||||
{
|
||||
elf_fail(program, path, "has no usable section header table");
|
||||
}
|
||||
|
||||
elf->shstrtab = (const char *)
|
||||
(elf->img + elf->shdr[elf->ehdr->e_shstrndx].sh_offset);
|
||||
|
||||
/* The static symbol table. There is no dynamic one: ld -r does not make
|
||||
* .dynsym, and NXFLAT has no use for it -- imports reach a module through
|
||||
* the array mknxflat generates.
|
||||
*/
|
||||
|
||||
for (i = 0; i < elf->ehdr->e_shnum; i++)
|
||||
{
|
||||
if (elf->shdr[i].sh_type == SHT_SYMTAB)
|
||||
{
|
||||
symidx = (int)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (symidx < 0)
|
||||
{
|
||||
elf_fail(program, path, "has no symbol table");
|
||||
}
|
||||
|
||||
if (elf->shdr[symidx].sh_entsize != sizeof(struct elf32_sym_s))
|
||||
{
|
||||
elf_fail(program, path, "has symbols of an unexpected size");
|
||||
}
|
||||
|
||||
if (elf->shdr[symidx].sh_link >= elf->ehdr->e_shnum)
|
||||
{
|
||||
elf_fail(program, path, "has a symbol table with no names");
|
||||
}
|
||||
|
||||
elf->syms = (struct elf32_sym_s *)
|
||||
(elf->img + elf->shdr[symidx].sh_offset);
|
||||
elf->nsyms = elf->shdr[symidx].sh_size / sizeof(struct elf32_sym_s);
|
||||
elf->strtab = (const char *)
|
||||
(elf->img + elf->shdr[elf->shdr[symidx].sh_link].sh_offset);
|
||||
}
|
||||
|
||||
const char *nxflat_elf_symname(const struct nxflat_elf_s *elf,
|
||||
const struct elf32_sym_s *sym)
|
||||
{
|
||||
return sym->st_name != 0 ? elf->strtab + sym->st_name : "";
|
||||
}
|
||||
171
tools/nxflat/nxflat_elf.h
Normal file
171
tools/nxflat/nxflat_elf.h
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/****************************************************************************
|
||||
* tools/nxflat/nxflat_elf.h
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __TOOLS_NXFLAT_NXFLAT_ELF_H
|
||||
#define __TOOLS_NXFLAT_NXFLAT_ELF_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* ELF32, declared here and not taken from a host elf.h: macOS has none, and
|
||||
* a tool that writes a target's binary should not use the host's idea of the
|
||||
* format.
|
||||
*/
|
||||
|
||||
#define ELFCLASS32 1
|
||||
#define ELFDATA2LSB 1
|
||||
#define ELFDATA2MSB 2
|
||||
|
||||
#define ET_REL 1
|
||||
#define EM_ARM 40
|
||||
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_NOBITS 8
|
||||
#define SHT_REL 9
|
||||
|
||||
#define SHF_WRITE 0x1
|
||||
#define SHF_ALLOC 0x2
|
||||
#define SHF_EXECINSTR 0x4
|
||||
|
||||
#define SHN_UNDEF 0
|
||||
#define SHN_COMMON 0xfff2
|
||||
|
||||
#define STT_NOTYPE 0
|
||||
#define STT_OBJECT 1
|
||||
#define STT_FUNC 2
|
||||
|
||||
#define ELF32_R_SYM(i) ((i) >> 8)
|
||||
#define ELF32_R_TYPE(i) ((i) & 0xff)
|
||||
#define ELF32_ST_TYPE(i) ((i) & 0x0f)
|
||||
#define ELF32_ST_BIND(i) ((i) >> 4)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
struct elf32_ehdr_s
|
||||
{
|
||||
unsigned char e_ident[16];
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
uint32_t e_entry;
|
||||
uint32_t e_phoff;
|
||||
uint32_t e_shoff;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_ehsize;
|
||||
uint16_t e_phentsize;
|
||||
uint16_t e_phnum;
|
||||
uint16_t e_shentsize;
|
||||
uint16_t e_shnum;
|
||||
uint16_t e_shstrndx;
|
||||
};
|
||||
|
||||
struct elf32_shdr_s
|
||||
{
|
||||
uint32_t sh_name;
|
||||
uint32_t sh_type;
|
||||
uint32_t sh_flags;
|
||||
uint32_t sh_addr;
|
||||
uint32_t sh_offset;
|
||||
uint32_t sh_size;
|
||||
uint32_t sh_link;
|
||||
uint32_t sh_info;
|
||||
uint32_t sh_addralign;
|
||||
uint32_t sh_entsize;
|
||||
};
|
||||
|
||||
struct elf32_sym_s
|
||||
{
|
||||
uint32_t st_name;
|
||||
uint32_t st_value;
|
||||
uint32_t st_size;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
uint16_t st_shndx;
|
||||
};
|
||||
|
||||
struct elf32_rel_s
|
||||
{
|
||||
uint32_t r_offset;
|
||||
uint32_t r_info;
|
||||
};
|
||||
|
||||
/* One object, read and put into the host's byte order.
|
||||
*
|
||||
* The tables that describe it -- headers, symbols, relocation entries --
|
||||
* are normalised, so a tool reads a field without asking whose byte order
|
||||
* it is in. Section contents are not: they are the target's bytes, and are
|
||||
* written out again as they were read.
|
||||
*/
|
||||
|
||||
struct nxflat_elf_s
|
||||
{
|
||||
uint8_t *img; /* The file */
|
||||
size_t size;
|
||||
bool littleendian; /* The byte order the object's contents are in */
|
||||
struct elf32_ehdr_s *ehdr;
|
||||
struct elf32_shdr_s *shdr; /* e_shnum of them */
|
||||
const char *shstrtab;
|
||||
struct elf32_sym_s *syms; /* The static symbol table */
|
||||
size_t nsyms;
|
||||
const char *strtab; /* The names those symbols point into */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxflat_elf_read
|
||||
*
|
||||
* Description:
|
||||
* Read one ELF32 object and locate its section headers, symbol table and
|
||||
* string tables. A bad file is reported against program and the tool
|
||||
* exits; neither tool has anything else to try.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void nxflat_elf_read(struct nxflat_elf_s *elf, const char *path,
|
||||
const char *program);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxflat_elf_symname
|
||||
*
|
||||
* Description:
|
||||
* The name of a symbol, or "" for one that has none.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
const char *nxflat_elf_symname(const struct nxflat_elf_s *elf,
|
||||
const struct elf32_sym_s *sym);
|
||||
|
||||
#endif /* __TOOLS_NXFLAT_NXFLAT_ELF_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue