diff --git a/common/sbus/Makefile b/common/sbus/Makefile index b04f9a99bab..60650f36526 100644 --- a/common/sbus/Makefile +++ b/common/sbus/Makefile @@ -29,7 +29,7 @@ IOP_INCS += \ IOP_OBJS_DIR = iop_obj/ -IOP_OBJS = ps2_sbus.o iop_sbus.o ps2_sif.o iop_sif2.o sif2cmd.o imports.o exports.o +IOP_OBJS = exports.o iop_sbus.o iop_sif2.o ps2_sbus.o ps2_sif.o sif2cmd.o imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/ee/Rules.lib.make diff --git a/iop/Rules.make b/iop/Rules.make index 0963358badc..42b69dd6fdc 100644 --- a/iop/Rules.make +++ b/iop/Rules.make @@ -145,8 +145,15 @@ $(IOP_BIN_STRIPPED_ELF): $(IOP_BIN_ELF) $(DIR_GUARD) $(IOP_STRIP) --strip-unneeded --remove-section=.pdr --remove-section=.comment --remove-section=.mdebug.abi32 --remove-section=.gnu.attributes -o $@ $< +# If the module has no export table, allow symbols at .text offset 0. +# The jal 0x0 hazard only matters when an export table can dispatch to offset 0. +IOP_SRXFIXUP_FLAGS := --rb --irx1 +ifeq ($(filter %exports.o,$(IOP_OBJS)),) +IOP_SRXFIXUP_FLAGS += --allow-zero-text +endif + $(IOP_BIN): $(IOP_BIN_STRIPPED_ELF) $(PS2SDKSRC)/tools/srxfixup/bin/srxfixup - $(PS2SDKSRC)/tools/srxfixup/bin/srxfixup --rb --irx1 -o $@ $< + $(PS2SDKSRC)/tools/srxfixup/bin/srxfixup $(IOP_SRXFIXUP_FLAGS) -o $@ $< $(IOP_LIB)_tmp$(MAKE_CURPID): $(IOP_OBJS) $(DIR_GUARD) diff --git a/iop/arcade/acatad/Makefile b/iop/arcade/acatad/Makefile index 6d71008159d..3461f393dc9 100644 --- a/iop/arcade/acatad/Makefile +++ b/iop/arcade/acatad/Makefile @@ -16,9 +16,9 @@ IOP_IMPORT_INCS += \ system/threadman IOP_OBJS = \ + exports.o \ acatad.o \ - imports.o \ - exports.o + imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/arcade/accdvd/Makefile b/iop/arcade/accdvd/Makefile index ed370b485dc..d7551385738 100644 --- a/iop/arcade/accdvd/Makefile +++ b/iop/arcade/accdvd/Makefile @@ -19,14 +19,14 @@ IOP_IMPORT_INCS += \ system/threadman IOP_OBJS = \ + exports.o \ accdvdi-entry.o \ acd.o \ cdc.o \ cdi.o \ cddrv.o \ cdfs.o \ - imports.o \ - exports.o + imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/arcade/acdev/Makefile b/iop/arcade/acdev/Makefile index 7b77aaaf341..08d13b3dc87 100644 --- a/iop/arcade/acdev/Makefile +++ b/iop/arcade/acdev/Makefile @@ -14,9 +14,9 @@ IOP_IMPORT_INCS += \ system/sysmem IOP_OBJS = \ + exports.o \ acdev.o \ - imports.o \ - exports.o + imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/arcade/acdev9/Makefile b/iop/arcade/acdev9/Makefile index cdffeb1fcab..730712e5dcd 100644 --- a/iop/arcade/acdev9/Makefile +++ b/iop/arcade/acdev9/Makefile @@ -12,9 +12,9 @@ IOP_IMPORT_INCS += \ system/stdio IOP_OBJS = \ + exports.o \ acdev9.o \ - imports.o \ - exports.o + imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/cdvd/cdvdfsv/Makefile b/iop/cdvd/cdvdfsv/Makefile index 938490765d0..7d57e3a5d4c 100644 --- a/iop/cdvd/cdvdfsv/Makefile +++ b/iop/cdvd/cdvdfsv/Makefile @@ -21,7 +21,7 @@ IOP_IMPORT_INCS += \ system/sysmem \ system/threadman -IOP_OBJS = cdvdfsv.o imports.o exports.o +IOP_OBJS = exports.o cdvdfsv.o imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/cdvd/cdvdman/Makefile b/iop/cdvd/cdvdman/Makefile index 979ecaa2a9a..017e8c2f82a 100644 --- a/iop/cdvd/cdvdman/Makefile +++ b/iop/cdvd/cdvdman/Makefile @@ -18,7 +18,7 @@ IOP_IMPORT_INCS += \ system/sysmem \ system/threadman -IOP_OBJS = cdvdman.o imports.o exports.o +IOP_OBJS = exports.o cdvdman.o imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/cdvd/cdvdstm/Makefile b/iop/cdvd/cdvdstm/Makefile index 88b480ecadb..adc32883603 100644 --- a/iop/cdvd/cdvdstm/Makefile +++ b/iop/cdvd/cdvdstm/Makefile @@ -19,7 +19,7 @@ IOP_IMPORT_INCS += \ system/sysmem \ system/threadman -IOP_OBJS = cdvdstm.o imports.o exports.o +IOP_OBJS = exports.o cdvdstm.o imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/debug/ioptrap/Makefile b/iop/debug/ioptrap/Makefile index 316d7adef1a..80c86902521 100644 --- a/iop/debug/ioptrap/Makefile +++ b/iop/debug/ioptrap/Makefile @@ -17,7 +17,7 @@ IOP_IMPORT_INCS += \ system/sysclib \ system/threadman -IOP_OBJS = ioptrap.o handler.o breakpoint.o exports.o imports.o +IOP_OBJS = exports.o ioptrap.o handler.o breakpoint.o imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/debug/sior/Makefile b/iop/debug/sior/Makefile index 863d4764fed..11b5dab2dac 100644 --- a/iop/debug/sior/Makefile +++ b/iop/debug/sior/Makefile @@ -13,7 +13,7 @@ IOP_IMPORT_INCS += \ system/sysclib \ system/threadman -IOP_OBJS = sior.o xprintf.o exports.o imports.o +IOP_OBJS = exports.o sior.o xprintf.o imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/dev9/pvrdrv/Makefile b/iop/dev9/pvrdrv/Makefile index 64d31a046d1..5a1f05c150f 100644 --- a/iop/dev9/pvrdrv/Makefile +++ b/iop/dev9/pvrdrv/Makefile @@ -16,7 +16,7 @@ IOP_IMPORT_INCS += \ system/sysmem \ system/threadman -IOP_OBJS = dvrdrv.o exports.o imports.o +IOP_OBJS = exports.o dvrdrv.o imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/fs/devfs/Makefile b/iop/fs/devfs/Makefile index 1633fd5244c..ec9d5938ec0 100644 --- a/iop/fs/devfs/Makefile +++ b/iop/fs/devfs/Makefile @@ -17,7 +17,7 @@ IOP_IMPORT_INCS += \ system/sysmem \ system/threadman -IOP_OBJS = devfs.o exports.o imports.o +IOP_OBJS = exports.o devfs.o imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/fs/romdrv/src/exports.tab b/iop/fs/romdrv/src/exports.tab index e394ad6f9f5..31ce609f83c 100644 --- a/iop/fs/romdrv/src/exports.tab +++ b/iop/fs/romdrv/src/exports.tab @@ -1,5 +1,3 @@ -void _retonly(void) {} - DECLARE_EXPORT_TABLE(romdrv, 2, 1) DECLARE_EXPORT(_start) DECLARE_EXPORT(_retonly) @@ -21,3 +19,5 @@ DECLARE_EXPORT_TABLE(romdrvX, 1, 1) DECLARE_EXPORT(romGetDevice) END_EXPORT_TABLE #endif + +void _retonly(void) {} diff --git a/iop/memorycard/mcman/Makefile b/iop/memorycard/mcman/Makefile index 826b310566f..eab9a0f5c7a 100644 --- a/iop/memorycard/mcman/Makefile +++ b/iop/memorycard/mcman/Makefile @@ -36,14 +36,14 @@ IOP_IMPORT_INCS += \ system/timrman IOP_OBJS = \ + exports.o \ main.o \ mcdev.o \ mciomanx_backing.o \ mcsio2.o \ ps2mc_fio.o \ ps1mc_fio.o \ - imports.o \ - exports.o + imports.o ifneq (x$(MCMAN_BUILDING_XMCMAN),x0) IOP_CFLAGS += -DBUILDING_XMCMAN diff --git a/iop/memorycard/mcserv/Makefile b/iop/memorycard/mcserv/Makefile index 928f57ebbd8..c2bd5de43b9 100644 --- a/iop/memorycard/mcserv/Makefile +++ b/iop/memorycard/mcserv/Makefile @@ -22,7 +22,7 @@ IOP_IMPORT_INCS += \ system/sysclib \ system/threadman -IOP_OBJS = mcserv.o imports.o exports.o +IOP_OBJS = exports.o mcserv.o imports.o ifneq (x$(MCMAN_BUILDING_XMCSERV),x0) IOP_CFLAGS += -DBUILDING_XMCSERV diff --git a/iop/network/netman/src/exports.tab b/iop/network/netman/src/exports.tab index 5b1f6ff4083..e4e1c9dcf03 100644 --- a/iop/network/netman/src/exports.tab +++ b/iop/network/netman/src/exports.tab @@ -1,5 +1,3 @@ -void _retonly(){}; - DECLARE_EXPORT_TABLE(netman, 3, 1) DECLARE_EXPORT(_start) DECLARE_EXPORT(_retonly) @@ -23,3 +21,5 @@ DECLARE_EXPORT_TABLE(netman, 3, 1) DECLARE_EXPORT(NetManTxPacketNext) DECLARE_EXPORT(NetManTxPacketDeQ) END_EXPORT_TABLE + +void _retonly(){}; diff --git a/iop/network/smap-none/Makefile b/iop/network/smap-none/Makefile index 37f8800c8f9..eaa0adc00a6 100644 --- a/iop/network/smap-none/Makefile +++ b/iop/network/smap-none/Makefile @@ -14,4 +14,7 @@ IOP_INC_DIR = $(PS2SDKSRC)/iop/network/smap/include/ SMAP_NETMAN ?= 0 SMAP_PS2IP ?= 0 +# No export table for this variant, exclude exports.o +IOP_OBJS = main.o smap.o xfer.o ipstack.o imports.o + include $(PS2SDKSRC)/iop/network/smap/Makefile diff --git a/iop/network/smap-ps2ip/Makefile b/iop/network/smap-ps2ip/Makefile index e6d4650e0b3..d4881f35811 100644 --- a/iop/network/smap-ps2ip/Makefile +++ b/iop/network/smap-ps2ip/Makefile @@ -14,4 +14,7 @@ IOP_INC_DIR = $(PS2SDKSRC)/iop/network/smap/include/ SMAP_NETMAN ?= 0 SMAP_PS2IP ?= 1 +# No export table for this variant, exclude exports.o +IOP_OBJS = main.o smap.o xfer.o ipstack.o imports.o + include $(PS2SDKSRC)/iop/network/smap/Makefile diff --git a/iop/network/smap/Makefile b/iop/network/smap/Makefile index af6f7496dce..e2746a1a33f 100644 --- a/iop/network/smap/Makefile +++ b/iop/network/smap/Makefile @@ -35,7 +35,7 @@ IOP_IMPORT_INCS += \ system/sysclib \ system/threadman -IOP_OBJS = ipstack.o main.o smap.o xfer.o imports.o exports.o +IOP_OBJS ?= exports.o main.o smap.o xfer.o ipstack.o imports.o ifneq (x$(LWIP_DHCP),x0) IOP_CFLAGS += -DLWIP_DHCP=1 diff --git a/iop/network/smap/src/exports.tab b/iop/network/smap/src/exports.tab index 1927a564957..78e426b9f72 100644 --- a/iop/network/smap/src/exports.tab +++ b/iop/network/smap/src/exports.tab @@ -1,6 +1,3 @@ - -void _retonly(){}; - #ifdef BUILDING_SMAP_NETMAN DECLARE_EXPORT_TABLE(smap, 1, 1) DECLARE_EXPORT(_retonly) @@ -19,3 +16,5 @@ DECLARE_EXPORT_TABLE(smapmodu, 1, 1) DECLARE_EXPORT(SmapModularGetExportTable) END_EXPORT_TABLE #endif + +void _retonly(){}; diff --git a/iop/network/udptty/src/exports.tab b/iop/network/udptty/src/exports.tab index 4f3033683ca..23c202620b0 100644 --- a/iop/network/udptty/src/exports.tab +++ b/iop/network/udptty/src/exports.tab @@ -1,5 +1,3 @@ -void _retonly(void) {} - DECLARE_EXPORT_TABLE(udptty, 1, 1) DECLARE_EXPORT(_start) DECLARE_EXPORT(_retonly) @@ -7,3 +5,5 @@ DECLARE_EXPORT_TABLE(udptty, 1, 1) DECLARE_EXPORT(_retonly) DECLARE_EXPORT(_retonly) END_EXPORT_TABLE + +void _retonly(void) {} diff --git a/iop/sound/libsd/Makefile b/iop/sound/libsd/Makefile index 7435daaccdc..a2b12f144e9 100644 --- a/iop/sound/libsd/Makefile +++ b/iop/sound/libsd/Makefile @@ -15,7 +15,7 @@ IOP_IMPORT_INCS += \ system/stdio \ system/sysclib -IOP_OBJS = freesd.o batch.o block.o effect.o voice.o exports.o imports.o +IOP_OBJS = exports.o freesd.o batch.o block.o effect.o voice.o imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/system/dmacman/Makefile b/iop/system/dmacman/Makefile index 642f99f78e6..623dcf2bcf1 100644 --- a/iop/system/dmacman/Makefile +++ b/iop/system/dmacman/Makefile @@ -13,7 +13,7 @@ IOP_IMPORT_INCS += \ system/loadcore \ system/sysmem -IOP_OBJS = dmacman.o exports.o imports.o +IOP_OBJS = exports.o dmacman.o imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/system/intrman/Makefile b/iop/system/intrman/Makefile index 554ee77bd78..1c4de61583b 100644 --- a/iop/system/intrman/Makefile +++ b/iop/system/intrman/Makefile @@ -15,7 +15,7 @@ IOP_IMPORT_INCS += \ system/excepman \ system/loadcore -IOP_OBJS = intrman.o exports.o imports.o +IOP_OBJS = exports.o intrman.o imports.o ifneq (x$(INTRMAN_PS1),x0) IOP_CFLAGS += -DBUILDING_INTRMANP diff --git a/iop/system/mtapman/Makefile b/iop/system/mtapman/Makefile index bbc79c1fe10..e4c9fbe8f00 100644 --- a/iop/system/mtapman/Makefile +++ b/iop/system/mtapman/Makefile @@ -16,7 +16,7 @@ IOP_IMPORT_INCS += \ system/stdio \ system/threadman -IOP_OBJS = freemtap.o rpcservers.o exports.o imports.o +IOP_OBJS = exports.o freemtap.o rpcservers.o imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/system/siftoo/Makefile b/iop/system/siftoo/Makefile index 5965390c763..fffcfbf8141 100644 --- a/iop/system/siftoo/Makefile +++ b/iop/system/siftoo/Makefile @@ -13,7 +13,7 @@ IOP_IMPORT_INCS += \ system/sifman \ system/stdio -IOP_OBJS = siftoo.o pipe.o exports.o imports.o +IOP_OBJS = exports.o siftoo.o pipe.o imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/system/stdio/Makefile b/iop/system/stdio/Makefile index 01f6b8b88d8..11253d0336a 100644 --- a/iop/system/stdio/Makefile +++ b/iop/system/stdio/Makefile @@ -13,7 +13,7 @@ IOP_IMPORT_INCS += \ system/loadcore \ system/sysclib -IOP_OBJS = stdio.o exports.o imports.o +IOP_OBJS = exports.o stdio.o imports.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/system/timrman/Makefile b/iop/system/timrman/Makefile index 7c2a1374787..b4055a5f1be 100644 --- a/iop/system/timrman/Makefile +++ b/iop/system/timrman/Makefile @@ -15,7 +15,7 @@ IOP_IMPORT_INCS += \ system/intrman \ system/loadcore -IOP_OBJS = timrman.o imports.o exports.o +IOP_OBJS = exports.o timrman.o imports.o ifneq (x$(TIMRMAN_PS1),x0) IOP_CFLAGS += -DBUILDING_TIMRMANP diff --git a/iop/tcpip/tcpip-netman/src/exports.tab b/iop/tcpip/tcpip-netman/src/exports.tab index 470bc1fcd03..8f9377d53bb 100644 --- a/iop/tcpip/tcpip-netman/src/exports.tab +++ b/iop/tcpip/tcpip-netman/src/exports.tab @@ -1,5 +1,3 @@ -void _retonly(void){} - DECLARE_EXPORT_TABLE(ps2ip, 2, 6) DECLARE_EXPORT(_start) DECLARE_EXPORT(_retonly) @@ -70,3 +68,5 @@ DECLARE_EXPORT_TABLE(ps2ip, 2, 6) DECLARE_EXPORT(tcpip_callback_with_block) DECLARE_EXPORT(pbuf_coalesce) END_EXPORT_TABLE + +void _retonly(void) {} \ No newline at end of file diff --git a/iop/tcpip/tcpip/Makefile b/iop/tcpip/tcpip/Makefile index fada0932d84..a8d2578898f 100644 --- a/iop/tcpip/tcpip/Makefile +++ b/iop/tcpip/tcpip/Makefile @@ -57,7 +57,7 @@ ifdef PS2IP_DNS ps2ip_OBJECTS += dns.o netdb.o endif -IOP_OBJS = ps2ip.o sys_arch.o exports.o imports.o $(ps2ip_OBJECTS) +IOP_OBJS = exports.o ps2ip.o sys_arch.o imports.o $(ps2ip_OBJECTS) include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/iop/Rules.bin.make diff --git a/iop/tcpip/tcpip/src/exports.tab b/iop/tcpip/tcpip/src/exports.tab index 470bc1fcd03..8f9377d53bb 100644 --- a/iop/tcpip/tcpip/src/exports.tab +++ b/iop/tcpip/tcpip/src/exports.tab @@ -1,5 +1,3 @@ -void _retonly(void){} - DECLARE_EXPORT_TABLE(ps2ip, 2, 6) DECLARE_EXPORT(_start) DECLARE_EXPORT(_retonly) @@ -70,3 +68,5 @@ DECLARE_EXPORT_TABLE(ps2ip, 2, 6) DECLARE_EXPORT(tcpip_callback_with_block) DECLARE_EXPORT(pbuf_coalesce) END_EXPORT_TABLE + +void _retonly(void) {} \ No newline at end of file diff --git a/tools/srxfixup/README.md b/tools/srxfixup/README.md index 7d00dc1645b..57006ad3839 100644 --- a/tools/srxfixup/README.md +++ b/tools/srxfixup/README.md @@ -26,3 +26,31 @@ This tool provides the following: To see usage and possible command line arguments that can be used with the program, run it without arguments. + +## Zero-.text symbol check + +When processing a relocatable ELF (`ET_REL`), `srxfixup` checks for function +or no-type symbols in the `.text` section whose `st_value` is exactly 0. Such +symbols indicate that real code was placed first in `.text` by the linker. +If an IOP export table has a zeroed or uninitialized entry, the dispatcher +will issue a `jal 0x0` — silently jumping into whatever function sits at +`.text` offset 0 instead of faulting. The symbols `_start` and `_ftext` are +excluded because they are entry points / linker labels that are never +dispatched through an export table. + +If any offending symbol is found, `srxfixup` prints an error like: + +``` +ERROR: foo.irx: symbol 'bar' (sym#3) is in .text with value 0 -- if this module has an export table, put exports.o first in IOP_OBJS and move _retonly after DECLARE_EXPORT_TABLE in exports.tab; otherwise use --allow-zero-text. +``` + +and exits with a non-zero status so the build fails. + +For modules **with** an export table, the fix is to ensure `exports.o` is +first in `IOP_OBJS` and that the `_retonly` definition appears after +`DECLARE_EXPORT_TABLE` in `exports.tab`. This places the export-table struct +(`STT_OBJECT`) at `.text` offset 0 instead of function code. + +For modules **without** an export table, the `jal 0x0` hazard does not apply. +Use `--allow-zero-text` to suppress the check. The IOP `Rules.make` +automatically passes this flag when `exports.o` is not present in `IOP_OBJS`. diff --git a/tools/srxfixup/src/srxfixup.c b/tools/srxfixup/src/srxfixup.c index d26c8beaec8..b7410c2838e 100644 --- a/tools/srxfixup/src/srxfixup.c +++ b/tools/srxfixup/src/srxfixup.c @@ -26,6 +26,7 @@ static unsigned int dispmod_flag = 0; static int irx1_flag = 0; static int br_conv = 0; static int print_config = 0; +static int allow_zero_text = 0; // clang-format off static const Opttable opttable[] = { @@ -42,6 +43,7 @@ static const Opttable opttable[] = { "--rb", ARG_HAVEARG_NONE, 'f', &br_conv }, { "--relative-branch", ARG_HAVEARG_NONE, 'f', &br_conv }, { "--print-internal-config", ARG_HAVEARG_NONE, 'f', &print_config }, + { "--allow-zero-text", ARG_HAVEARG_NONE, 'f', &allow_zero_text }, { NULL, 0, '\0', NULL }, }; static const Opttable stripopttable[] = @@ -63,6 +65,7 @@ static const Opttable stripopttable[] = static void display_module_info(elf_file *elf); static void convert_relative_branch_an_section(elf_section *relsect); static void convert_relative_branch(elf_file *elf); +static int check_zero_text_symbols(const char *source, const elf_file *elf); void usage(const char *myname) { @@ -79,7 +82,8 @@ void usage(const char *myname) " -o \n" " -r \n" " -e \n" - " --relative-branch or --rb\n"); + " --relative-branch or --rb\n" + " --allow-zero-text (skip check for .text symbols with value 0)\n"); if ( verbose ) { printf(" -t <.text start address>\n" @@ -251,6 +255,10 @@ int main(int argc, char **argv) switch ( elf->ehp->e_type ) { case ET_REL: + if ( !allow_zero_text && check_zero_text_symbols(source, elf) ) + { + exit(1); + } if ( convert_rel2srx(elf, entrysym, (rfile || ofile || ffile) ? 1 : 0, irx1_flag) ) { exit(1); @@ -487,3 +495,79 @@ static void convert_relative_branch(elf_file *elf) } } } + +static int check_zero_text_symbols(const char *source, const elf_file *elf) +{ + int text_idx; + int i; + int found; + + if ( elf->scp == NULL ) + { + return 0; + } + + /* Find the index of the .text section by name */ + text_idx = -1; + for ( i = 1; i < elf->ehp->e_shnum; i += 1 ) + { + if ( elf->scp[i]->name && strcmp(elf->scp[i]->name, ".text") == 0 ) + { + text_idx = i; + break; + } + } + if ( text_idx < 0 ) + { + return 0; /* No .text section — nothing to check */ + } + + found = 0; + for ( i = 1; i < elf->ehp->e_shnum; i += 1 ) + { + elf_section *sect; + unsigned int nsyms; + unsigned int j; + elf_syment **syms; + + sect = elf->scp[i]; + if ( sect->shr.sh_type != SHT_SYMTAB || sect->data == NULL || sect->shr.sh_entsize == 0 ) + { + continue; + } + nsyms = sect->shr.sh_size / sect->shr.sh_entsize; + syms = (elf_syment **)sect->data; + for ( j = 1; j < nsyms; j += 1 ) /* skip sym[0]: ELF null symbol */ + { + elf_syment *sym; + + sym = syms[j]; + /* _start is the IOP module entry point called via the .iopmod + * header, never via a jal from within the module. + * _ftext is a linker label at the start of .text, also never + * the target of an intra-module jal. Both are safe at .text+0. */ + if ( sym->name + && (strcmp(sym->name, "_start") == 0 || strcmp(sym->name, "_ftext") == 0) ) + { + continue; + } + if ( (unsigned int)sym->sym.st_shndx == (unsigned int)text_idx + && (sym->type == STT_FUNC || sym->type == STT_NOTYPE) + && sym->sym.st_value == 0 ) + { + fprintf( + stderr, + "ERROR: %s: symbol '%s' (sym#%u) is in .text with value 0" + " -- if this module has an export table, put exports.o" + " first in IOP_OBJS and move _retonly after" + " DECLARE_EXPORT_TABLE in exports.tab;" + " otherwise use --allow-zero-text.\n", + source, + (sym->name && sym->name[0]) ? sym->name : "", + j); + found = 1; + } + } + } + return found; +}