Fix loading of ET_DYN type of shared objects

* build-globals.sh
  - Only look in the nuttx for external symbols used when loading
    dynamic shared objects

* include/elf64.h
  - Correct the type of fields in the Elf64_Phdr structure

* libs/libc/dlfcn/lib_dlclose.c
  - Distinguish between ET_DYN and other objects as the former
    has both text and data in a single allocation to reserve
    GOT offsets

* libs/libc/dlfcn/lib_dlopen.c
  - Code formatting

* libs/libc/modlib/modlib_bind.c
  - Distinguish between relocation entry sizes by section type
  - Handle RELA style relocations

* libs/libc/modlib/modlib_globals.S
  - Formatting fixes
  - Symbols should not be weak - they exist or they don't

* include/nuttx/lib/modlib.h
  - Add an inidcator to module_s to distinguish between ET_DYN and other

* libs/libc/modlib/modlib_load.c
  - ET_DYN objects need to keep the relative displacement between the text
    and data sections due to GOT references from the former to the latter.
    This also implies that linking may require modification from the default
    for the shared objects being produced. For example, default alignment may
    mean nearly 64K of wasted space.

* libs/libc/modlib/modlib_unload.c
  sched/module/mod_rmmod.c
  - Distingusih between freeing of ET_DYN storage and other as the former
    is a single allocation.

* libs/libc/modlib/mod_insmod.c
  - Cater for ET_DYN objects having init and preinit sections
This commit is contained in:
Neale Ferguson 2023-09-04 10:37:48 +10:00 committed by Alan Carvalho de Assis
parent f47991e34d
commit 5d7f2fdf16
12 changed files with 248 additions and 176 deletions

View File

@ -230,6 +230,7 @@ CMODULEFLAGS += -fno-stack-protector
LDMODULEFLAGS = -r -e module_initialize --gc-sections
LDMODULEFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/modlib/gnu-elf.ld)
SHMODULEFLAGS = -Bsymbolic -G -Bdynamic
# NuttX modules are ELF binaries.
# Non-ELF platforms like macOS need to use a separate ELF toolchain.
@ -270,5 +271,6 @@ ifeq ($(CONFIG_SIM_M32),y)
LDLINKFLAGS += -melf_i386
LDFLAGS += -m32
LDMODULEFLAGS += -melf_i386
SHMODULEFLAGS += -melf_i386
LDELFFLAGS += -melf_i386
endif

View File

@ -142,9 +142,9 @@ typedef struct
Elf64_Off p_offset; /* Offset in file */
Elf64_Addr p_vaddr; /* Virtual address in memory */
Elf64_Addr p_paddr; /* Reserved */
Elf64_Word p_filesz; /* Size of segment in file */
Elf64_Word p_memsz; /* Size of segment in memory */
Elf64_Word p_align; /* Alignment of segment */
Elf64_Xword p_filesz; /* Size of segment in file */
Elf64_Xword p_memsz; /* Size of segment in memory */
Elf64_Xword p_align; /* Alignment of segment */
} Elf64_Phdr;
/* Figure 7. Format of a Note Section */

View File

@ -159,6 +159,7 @@ struct module_s
struct mod_info_s modinfo; /* Module information */
FAR void *textalloc; /* Allocated kernel text memory */
FAR void *dataalloc; /* Allocated kernel memory */
int dynamic; /* Module is a dynamic shared object */
#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE)
size_t textsize; /* Size of the kernel .text memory allocation */
size_t datasize; /* Size of the kernel .bss/.data memory allocation */

View File

@ -125,38 +125,45 @@ static inline int dlremove(FAR void *handle)
/* Release resources held by the module */
if (modp->textalloc != NULL)
/* Dynamic shared objects have text and data allocated in one
* operation to keep the relative positions between the two
* areas relative otherwise references to the GOT will fail
*/
if (!modp->dynamic)
{
/* Free the module memory */
if (modp->textalloc != NULL)
{
/* Free the module memory */
#if defined(CONFIG_ARCH_USE_TEXT_HEAP)
up_textheap_free(modp->textalloc);
up_textheap_free((FAR void *)modp->textalloc);
#else
lib_free(modp->textalloc);
lib_free((FAR void *)modp->textalloc);
#endif
}
/* Nullify so that the memory cannot be freed again */
if (modp->dataalloc != NULL)
{
/* Free the module memory */
modp->textalloc = NULL;
#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE)
modp->textsize = 0;
#endif
lib_free((FAR void *)modp->dataalloc);
}
}
if (modp->dataalloc != NULL)
else
{
/* Free the module memory */
lib_free(modp->dataalloc);
/* Nullify so that the memory cannot be freed again */
modp->dataalloc = NULL;
#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE)
modp->datasize = 0;
#endif
lib_free((FAR void *)modp->textalloc);
}
/* Nullify so that the memory cannot be freed again */
modp->textalloc = NULL;
modp->dataalloc = NULL;
#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE)
modp->textsize = 0;
modp->datasize = 0;
#endif
/* Free the modules exported symmbols table */
modlib_freesymtab(modp);

View File

@ -232,6 +232,7 @@ static inline FAR void *dlinsert(FAR const char *filename)
modp->textalloc = (FAR void *)loadinfo.textalloc;
modp->dataalloc = (FAR void *)loadinfo.datastart;
modp->dynamic = (loadinfo.ehdr.e_type == ET_DYN);
#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE)
modp->textsize = loadinfo.textsize;
modp->datasize = loadinfo.datasize;

View File

@ -64,9 +64,10 @@ struct
int stroff; /* offset to string table */
int symoff; /* offset to symbol table */
int lsymtab; /* size of symbol table */
int relentsz; /* size of relocation entry */
int relentsz[2]; /* size of relocation entry */
int reloff[2]; /* offset to the relocation section */
int relsz[2]; /* size of relocation table */
int relrela[2]; /* type of relocation type - 0: DT_REL / 1: DT_RELA */
} reldata;
/****************************************************************************
@ -558,6 +559,8 @@ static int modlib_relocatedyn(FAR struct module_s *modp,
FAR Elf_Dyn *dyn = NULL;
FAR Elf_Rel *rels = NULL;
FAR Elf_Rel *rel;
FAR Elf_Rela *relas = NULL;
FAR Elf_Rela *rela;
FAR Elf_Sym *sym = NULL;
uintptr_t addr;
int ret;
@ -574,7 +577,9 @@ static int modlib_relocatedyn(FAR struct module_s *modp,
return ret;
}
rels = lib_malloc(CONFIG_MODLIB_RELOCATION_BUFFERCOUNT * sizeof(Elf_Rel));
/* Assume DT_RELA to get maximum size required */
rels = lib_malloc(CONFIG_MODLIB_RELOCATION_BUFFERCOUNT * sizeof(Elf_Rela));
if (!rels)
{
berr("Failed to allocate memory for elf relocation rels\n");
@ -583,6 +588,7 @@ static int modlib_relocatedyn(FAR struct module_s *modp,
}
memset((void *)&reldata, 0, sizeof(reldata));
relas = (FAR Elf_Rela *)rels;
for (i = 0; dyn[i].d_tag != DT_NULL; i++)
{
@ -595,7 +601,7 @@ static int modlib_relocatedyn(FAR struct module_s *modp,
reldata.relsz[I_REL] = dyn[i].d_un.d_val;
break;
case DT_RELENT:
reldata.relentsz = dyn[i].d_un.d_val;
reldata.relentsz[I_REL] = dyn[i].d_un.d_val;
break;
case DT_SYMTAB:
reldata.symoff = dyn[i].d_un.d_val;
@ -609,6 +615,18 @@ static int modlib_relocatedyn(FAR struct module_s *modp,
case DT_PLTRELSZ:
reldata.relsz[I_PLT] = dyn[i].d_un.d_val;
break;
case DT_PLTREL:
if (dyn[i].d_un.d_val == DT_REL)
{
reldata.relentsz[I_PLT] = sizeof(Elf_Rel);
reldata.relrela[I_PLT] = 0;
}
else
{
reldata.relentsz[I_PLT] = sizeof(Elf_Rela);
reldata.relrela[I_PLT] = 1;
}
break;
}
}
@ -637,7 +655,9 @@ static int modlib_relocatedyn(FAR struct module_s *modp,
for (idx_rel = 0; idx_rel < N_RELS; idx_rel++)
{
if (reldata.reloff[idx_rel] == 0)
int lrelent;
if ((reldata.relsz[idx_rel] == 0) || (reldata.reloff[idx_rel] == 0))
{
continue;
}
@ -645,16 +665,30 @@ static int modlib_relocatedyn(FAR struct module_s *modp,
/* Examine each relocation in the .rel.* section. */
ret = OK;
lrelent = reldata.relsz[idx_rel] / reldata.relentsz[idx_rel];
for (i = 0; i < reldata.relsz[idx_rel] / reldata.relentsz; i++)
for (i = 0; i < lrelent; i++)
{
/* Process each relocation entry */
/* Process each relocation entry
* - we cheat by using the fact the 1st two fields of Elf_Rel
* and Elf_Rela are identical so can do things based on the
* former until it's important
*/
rel = &rels[i % CONFIG_MODLIB_RELOCATION_BUFFERCOUNT];
if (reldata.relrela[idx_rel] == 0)
{
rel = &rels[i % CONFIG_MODLIB_RELOCATION_BUFFERCOUNT];
rela = (Elf_Rela *)rel; /* Just to keep the compiler happy */
}
else
{
rela = &relas[i % CONFIG_MODLIB_RELOCATION_BUFFERCOUNT];
rel = (Elf_Rel *)rela;
}
if (!(i % CONFIG_MODLIB_RELOCATION_BUFFERCOUNT))
{
size_t relsize = (sizeof(Elf_Rel) *
size_t relsize = (sizeof(Elf_Rela) *
CONFIG_MODLIB_RELOCATION_BUFFERCOUNT);
if (reldata.relsz[idx_rel] < relsize)
@ -713,6 +747,12 @@ static int modlib_relocatedyn(FAR struct module_s *modp,
}
addr = rel->r_offset + loadinfo->textalloc;
if (reldata.relrela[idx_rel] == 1)
{
addr += rela->r_addend;
}
*(FAR uintptr_t *)addr = (uintptr_t)ep;
}
}
@ -722,6 +762,11 @@ static int modlib_relocatedyn(FAR struct module_s *modp,
addr = rel->r_offset - loadinfo->datasec + loadinfo->datastart;
if (reldata.relrela[idx_rel] == 1)
{
addr += rela->r_addend;
}
if ((*(FAR uint32_t *)addr) < loadinfo->datasec)
{
dynsym.st_value = *(FAR uint32_t *)addr +
@ -748,8 +793,8 @@ static int modlib_relocatedyn(FAR struct module_s *modp,
}
}
/* Iterate through the dynamic symbol table looking for global symbols to
* put in our own symbol table for use with dlgetsym()
/* Iterate through the dynamic symbol table looking for global symbols
* to put in our own symbol table for use with dlgetsym()
*/
/* Relocate the entries in the table */
@ -831,6 +876,7 @@ int modlib_bind(FAR struct module_s *modp,
if (loadinfo->ehdr.e_type == ET_DYN)
{
modp->dynamic = 1;
switch (loadinfo->shdr[i].sh_type)
{
case SHT_DYNAMIC:
@ -864,8 +910,10 @@ int modlib_bind(FAR struct module_s *modp,
}
else
{
/* Make sure that the section is allocated. We can't relocate
* sections that were not loaded into memory.
modp->dynamic = 0;
/* Make sure that the section is allocated. We can't
* relocate sections that were not loaded into memory.
*/
if ((loadinfo->shdr[infosec].sh_flags & SHF_ALLOC) == 0)

View File

@ -1,28 +1,25 @@
#ifdef __CYGWIN__
# define SYMBOL(s) s
# define WEAK .weak
# define SYMBOL(s) _##s
# define GLOBAL .global
# define SECTION .data
.macro GLOBAL ep
.global SYMBOL(\ep)
.type SYMBOL(\ep), "object"
.global SYMBOL(\ep)
.type SYMBOL(\ep), "object"
.endm
.macro SIZE ep
.endm
#elif defined(__ELF__)
# define SYMBOL(s) s
# define WEAK .weak
# define SECTION .data
.macro GLOBAL ep
.global SYMBOL(\ep)
.type SYMBOL(\ep), "object"
.global SYMBOL(\ep)
.type SYMBOL(\ep), "object"
.endm
.macro SIZE ep
.size SYMBOL(\ep), . - SYMBOL(\ep)
.size SYMBOL(\ep), . - SYMBOL(\ep)
.endm
#else
# define SYMBOL(s) _##s
# define WEAK .weak_definition
# define SECTION .section __DATA,__data
.macro GLOBAL ep
.private_extern SYMBOL(\ep)
@ -34,14 +31,12 @@
#if __SIZEOF_POINTER__ == 8
.macro globalEntry index, ep
WEAK SYMBOL(\ep)
.quad .l\index
.quad \ep
.endm
# define ALIGN 8
#else
.macro globalEntry index, ep
WEAK SYMBOL(\ep)
.long .l\index
.long \ep
.endm
@ -54,20 +49,20 @@
.arch armv8-m.base
#endif
#ifdef __ARM_ASM_SYNTAX_UNIFIED__
.syntax unified
.syntax unified
#endif
.thumb
#endif
.data
.align ALIGN
GLOBAL globalNames
GLOBAL globalNames
SYMBOL(globalNames):
SIZE globalNames
SIZE globalNames
.align ALIGN
GLOBAL nglobals
SYMBOL(nglobals):
SYMBOL(nglobals):
.word 0
SIZE nglobals

View File

@ -309,36 +309,62 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo)
/* Allocate memory to hold the ELF image */
if (loadinfo->textsize > 0)
/* For Dynamic shared objects the relative positions between
* text and data must be maintained due to references to the
* GOT. Therefore we cannot do two different allocations.
*/
if (loadinfo->ehdr.e_type == ET_REL)
{
#if defined(CONFIG_ARCH_USE_TEXT_HEAP)
loadinfo->textalloc = (uintptr_t)
up_textheap_memalign(loadinfo->textalign,
loadinfo->textsize +
loadinfo->segpad);
#else
loadinfo->textalloc = (uintptr_t)lib_memalign(loadinfo->textalign,
loadinfo->textsize +
loadinfo->segpad);
#endif
if (!loadinfo->textalloc)
if (loadinfo->textsize > 0)
{
berr("ERROR: Failed to allocate memory for the module text\n");
ret = -ENOMEM;
goto errout_with_buffers;
#if defined(CONFIG_ARCH_USE_TEXT_HEAP)
loadinfo->textalloc = (uintptr_t)
up_textheap_memalign(loadinfo->textalign,
loadinfo->textsize +
loadinfo->segpad);
#else
loadinfo->textalloc = (uintptr_t)lib_memalign(loadinfo->textalign,
loadinfo->textsize +
loadinfo->segpad);
#endif
if (!loadinfo->textalloc)
{
berr("ERROR: Failed to allocate memory for the module text\n");
ret = -ENOMEM;
goto errout_with_buffers;
}
}
if (loadinfo->datasize > 0)
{
loadinfo->datastart = (uintptr_t)lib_memalign(loadinfo->dataalign,
loadinfo->datasize);
if (!loadinfo->datastart)
{
berr("ERROR: Failed to allocate memory for the module data\n");
ret = -ENOMEM;
goto errout_with_buffers;
}
}
}
if (loadinfo->datasize > 0)
else
{
loadinfo->datastart = (uintptr_t)lib_memalign(loadinfo->dataalign,
loadinfo->datasize);
if (!loadinfo->datastart)
loadinfo->textalloc = (uintptr_t)lib_memalign(loadinfo->textalign,
loadinfo->textsize +
loadinfo->datasize +
loadinfo->segpad);
if (!loadinfo->textalloc)
{
berr("ERROR: Failed to allocate memory for the module data\n");
berr("ERROR: Failed to allocate memory for the module\n");
ret = -ENOMEM;
goto errout_with_buffers;
}
loadinfo->datastart = loadinfo->textalloc +
loadinfo->textsize +
loadinfo->segpad;
}
/* Load ELF section data into memory */

View File

@ -58,18 +58,27 @@ int modlib_unload(FAR struct mod_loadinfo_s *loadinfo)
/* Release memory holding the relocated ELF image */
if (loadinfo->textalloc != 0)
{
#if defined(CONFIG_ARCH_USE_TEXT_HEAP)
up_textheap_free((FAR void *)loadinfo->textalloc);
#else
lib_free((FAR void *)loadinfo->textalloc);
#endif
}
/* ET_DYN has a single allocation so we only free textalloc */
if (loadinfo->datastart != 0)
if (loadinfo->ehdr.e_type != ET_DYN)
{
lib_free((FAR void *)loadinfo->datastart);
if (loadinfo->textalloc != 0)
{
#if defined(CONFIG_ARCH_USE_TEXT_HEAP)
up_textheap_free((FAR void *)loadinfo->textalloc);
#else
lib_free((FAR void *)loadinfo->textalloc);
#endif
}
if (loadinfo->datastart != 0)
{
lib_free((FAR void *)loadinfo->datastart);
}
}
else
{
lib_free((FAR void *)loadinfo->textalloc);
}
/* Clear out all indications of the allocated address environment */

View File

@ -155,7 +155,9 @@ FAR void *insmod(FAR const char *filename, FAR const char *modname)
struct mod_loadinfo_s loadinfo;
FAR struct module_s *modp;
mod_initializer_t initializer;
FAR void (**array)(void);
int ret;
int i;
DEBUGASSERT(filename != NULL && modname != NULL);
binfo("Loading file: %s\n", filename);
@ -237,11 +239,37 @@ FAR void *insmod(FAR const char *filename, FAR const char *modname)
/* Call the module initializer */
ret = initializer(&modp->modinfo);
if (ret < 0)
switch (loadinfo.ehdr.e_type)
{
binfo("Failed to initialize the module: %d\n", ret);
goto errout_with_load;
case ET_REL :
ret = initializer(&modp->modinfo);
if (ret < 0)
{
binfo("Failed to initialize the module: %d\n", ret);
goto errout_with_load;
}
break;
case ET_DYN :
/* Process any preinit_array entries */
array = (FAR void (**)(void))loadinfo.preiarr;
for (i = 0; i < loadinfo.nprei; i++)
{
array[i]();
}
/* Process any init_array entries */
array = (FAR void (**)(void))loadinfo.initarr;
for (i = 0; i < loadinfo.ninit; i++)
{
array[i]();
}
modp->finiarr = loadinfo.finiarr;
modp->nfini = loadinfo.nfini;
break;
}
/* Add the new module entry to the registry */

View File

@ -116,16 +116,27 @@ int rmmod(FAR void *handle)
if (modp->textalloc != NULL || modp->dataalloc != NULL)
{
/* Free the module memory
* and nullify so that the memory cannot be freed again
/* Free the module memory and nullify so that the memory cannot
* be freed again
*
* NOTE: For dynamic shared objects there is only a single
* allocation: the text/data were allocated in one operation
*/
if (!modp->dynamic)
{
#if defined(CONFIG_ARCH_USE_TEXT_HEAP)
up_textheap_free(modp->textalloc);
up_textheap_free((FAR void *)modp->textalloc);
#else
kmm_free(modp->textalloc);
kmm_free((FAR void *)modp->textalloc);
#endif
kmm_free(modp->dataalloc);
kmm_free((FAR void *)modp->dataalloc);
}
else
{
kmm_free((FAR void *)modp->textalloc);
}
modp->textalloc = NULL;
modp->dataalloc = NULL;
#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE)

View File

@ -1,65 +1,28 @@
#!/bin/bash
#!/usr/bin/env bash
############################################################################
# tools/build-globals.sh
#
# 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.
#
############################################################################
#
# Script to create modlib_global.S which contains a structure define
# the API names and addresses we will export for resolving symbols in
# dynamic loaded shared objects. Typically these are libc APIs.
#
# Find an entrypoint using a binary search
#
findep()
{
CHECK=$1
SIZE=${#SYM[@]}
L=0
R=$((SIZE - 1))
OLDL=99999999
OLDR=99999999
while [ ${L} -le ${R} ]
do
T=$(( L + R ))
M=$(( T / 2 ))
N=$(( T % 2 ))
M=$(( M - N ))
if [ ${SYM[${M}]} \< ${CHECK} ]; then
L=$(( M + 1 ))
elif [ ${SYM[${M}]} = ${CHECK} ]; then
return 1
else
R=$(( M - 1 ))
fi
if [ ${OLDL} -eq ${L} -a ${OLDR} -eq ${R} ]; then
: return 0
fi
OLDL=${L}
OLDR=${R}
done
return 0
}
#
# Extract entrypoints from a library after applying a filter to
# exclude those we aren't interested in.
#
getEP()
{
for ((i = 0; i < ${#OBJ[@]}; i++))
do
if [ -f staging/${OBJ[$i]} ]; then
FUNCS=`${NM} -g --defined-only staging/${OBJ[$i]} 2>/dev/null | grep "^0" | awk '{print $3}' | sort | grep -Ev ${FILTER}`
FUNC=(${FUNCS})
for ((j = 0; j < ${#FUNC[@]}; j++))
do
findep ${FUNC[$j]}
if [ $? -eq 1 ]; then
EP[${I_EP}]=${FUNC[$j]}
I_EP=$((I_EP + 1))
fi
done
fi
done
}
#
# Symbols to ignore within the NuttX libraries
#
@ -75,20 +38,6 @@ fi
SYMS=`cat System.map | awk '{print $3}' | sort | grep -Ev ${FILTER}`
SYM=(${SYMS})
GLOBALS="libs/libc/modlib/modlib_globals.S"
I_EP=0
#
# Libraries to be searched
#
OBJS="libsched.a libdrivers.a libconfigs.a libstubs.a libkc.a libkmm.a libkarch.a libpass1.a libnet.a libcrypto.a libfs.a libbinfmt.a libxx.a libuc.a libumm.a libuarch.a libapps.a"
OBJ=(${OBJS})
#
# Perform the extraction from the libraries
#
getEP
EPS=`printf '%s\n' "${EP[@]}" | sort -u`
EP=(${EPS})
#
# Generate the modlib_xxxx_globals.S file
@ -96,7 +45,6 @@ EP=(${EPS})
cat >${GLOBALS} <<__EOF__
#ifdef __CYGWIN__
# define SYMBOL(s) _##s
# define WEAK .weak
# define GLOBAL .global
# define SECTION .data
.macro GLOBAL ep
@ -107,7 +55,6 @@ cat >${GLOBALS} <<__EOF__
.endm
#elif defined(__ELF__)
# define SYMBOL(s) s
# define WEAK .weak
# define SECTION .data
.macro GLOBAL ep
.global SYMBOL(\ep)
@ -118,7 +65,6 @@ cat >${GLOBALS} <<__EOF__
.endm
#else
# define SYMBOL(s) _##s
# define WEAK .weak_definition
# define SECTION .section __DATA,__data
.macro GLOBAL ep
.private_extern SYMBOL(\ep)
@ -130,14 +76,12 @@ cat >${GLOBALS} <<__EOF__
#if __SIZEOF_POINTER__ == 8
.macro globalEntry index, ep
WEAK SYMBOL(\ep)
.quad .l\index
.quad \ep
.endm
# define ALIGN 8
#else
.macro globalEntry index, ep
WEAK SYMBOL(\ep)
.long .l\index
.long \ep
.endm
@ -156,23 +100,23 @@ cat >${GLOBALS} <<__EOF__
#endif
.data
.align ALIGN
GLOBAL globalNames
GLOBAL globalNames
SYMBOL(globalNames):
__EOF__
for ((i = 0; i < ${#EP[@]}; i++))
for ((i = 0; i < ${#SYM[@]}; i++))
do
echo ".l${i}: .string \"${EP[$i]}\"" >>${GLOBALS}
echo ".l${i}: .string \"${SYM[$i]}\"" >>${GLOBALS}
done
cat >>${GLOBALS} <<__EOF__
SIZE globalNames
SIZE globalNames
.align ALIGN
GLOBAL nglobals
SYMBOL(nglobals):
.word ${#EP[@]}
SYMBOL(nglobals):
.word ${#SYM[@]}
SIZE nglobals
.align ALIGN
@ -180,13 +124,13 @@ SYMBOL(nglobals):
SYMBOL(global_table):
__EOF__
for ((i = 0; i < ${#EP[@]}; i++))
for ((i = 0; i < ${#SYM[@]}; i++))
do
echo " globalEntry ${i}, ${EP[$i]}" >>${GLOBALS}
echo " globalEntry ${i}, ${SYM[$i]}" >>${GLOBALS}
done
cat >>${GLOBALS} <<__EOF__
SIZE global_table
__EOF__
echo "${#EP[@]} symbols defined"
echo "${#SYM[@]} symbols defined"