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:
Marco Casaroli 2026-09-27 11:56:10 +02:00 • committed by Alan C. Assis
parent 60d01d779f
commit 31acf10057
4 changed files with 483 additions and 285 deletions

View file

@ -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) \

View file

@ -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
View 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
View 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 */