diff --git a/Defs.make b/Defs.make index 3740ae79e42..2c841f27f88 100644 --- a/Defs.make +++ b/Defs.make @@ -30,7 +30,7 @@ EE_PKG_CONFIG ?= $(EE_TOOL_PREFIX)pkg-config # Defintions for the IOP toolchain. # -IOP_TOOL_PREFIX ?= mipsel-ps2-irx- +IOP_TOOL_PREFIX ?= mipsel-none-elf- IOP_CC ?= $(IOP_TOOL_PREFIX)gcc IOP_AS ?= $(IOP_TOOL_PREFIX)as IOP_LD ?= $(IOP_TOOL_PREFIX)ld diff --git a/iop/Rules.make b/iop/Rules.make index d3346c3fe1f..d1097eb6363 100644 --- a/iop/Rules.make +++ b/iop/Rules.make @@ -40,7 +40,7 @@ ifeq ($(DEBUG),1) IOP_CFLAGS += -DDEBUG endif # Linker flags -IOP_LDFLAGS := -nostdlib -s $(IOP_LDFLAGS) +IOP_LDFLAGS := -nostdlib -dc -r $(IOP_LDFLAGS) # Additional C compiler flags for GCC >=v5.3.0 # -msoft-float is to "remind" GCC/Binutils that the soft-float ABI is to be used. This is due to a bug, which @@ -69,8 +69,17 @@ endif # Assembler flags IOP_ASFLAGS := $(ASFLAGS_TARGET) -EL -G0 $(IOP_ASFLAGS) +# Default link file +ifeq ($(IOP_LINKFILE),) +IOP_LINKFILE := $(PS2SDKSRC)/iop/startup/src/linkfile +endif + IOP_OBJS := $(IOP_OBJS:%=$(IOP_OBJS_DIR)%) +IOP_BIN_ELF := $(IOP_BIN:.irx=.notiopmod.elf) + +IOP_BIN_STRIPPED_ELF := $(IOP_BIN:.irx=.notiopmod.stripped.elf) + # Externally defined variables: IOP_BIN, IOP_OBJS, IOP_LIB # These macros can be used to simplify certain build rules. @@ -95,6 +104,9 @@ $(IOP_OBJS_DIR)%.o: $(IOP_SRC_DIR)%.s .INTERMEDIATE:: $(IOP_LIB)_tmp$(MAKE_CURPID) $(IOP_OBJS_DIR)build-imports.c $(IOP_OBJS_DIR)build-exports.c +$(PS2SDKSRC)/tools/srxfixup/bin/srxfixup: $(PS2SDKSRC)/tools/srxfixup + $(MAKEREC) $< + $(IOP_OBJS_DIR)template-imports.h: $(DIR_GUARD) $(PRINTF) '%s\n' "#include \"irx_imports.h\"" > $@ @@ -121,9 +133,16 @@ $(IOP_OBJS_DIR)exports.o: $(IOP_OBJS_DIR)build-exports.c $(DIR_GUARD) $(IOP_C_COMPILE) $(IOP_IETABLE_CFLAGS) -c $< -o $@ -$(IOP_BIN): $(IOP_OBJS) $(IOP_LIB_ARCHIVES) $(IOP_ADDITIONAL_DEPS) +$(IOP_BIN_ELF): $(IOP_OBJS) $(IOP_LIB_ARCHIVES) $(IOP_ADDITIONAL_DEPS) + $(DIR_GUARD) + $(IOP_C_COMPILE) -T$(IOP_LINKFILE) $(IOP_OPTFLAGS) -o $@ $(IOP_OBJS) $(IOP_LDFLAGS) $(IOP_LIB_ARCHIVES) $(IOP_LIBS) + +$(IOP_BIN_STRIPPED_ELF): $(IOP_BIN_ELF) $(DIR_GUARD) - $(IOP_C_COMPILE) $(IOP_OPTFLAGS) -o $(IOP_BIN) $(IOP_OBJS) $(IOP_LDFLAGS) $(IOP_LIB_ARCHIVES) $(IOP_LIBS) + $(IOP_STRIP) --strip-unneeded --remove-section=.pdr --remove-section=.comment --remove-section=.mdebug.abi32 --remove-section=.gnu.attributes -o $@ $< + +$(IOP_BIN): $(IOP_BIN_STRIPPED_ELF) $(PS2SDKSRC)/tools/srxfixup/bin/srxfixup + $(PS2SDKSRC)/tools/srxfixup/bin/srxfixup --irx1 -o $@ $< $(IOP_LIB)_tmp$(MAKE_CURPID): $(IOP_OBJS) $(DIR_GUARD) diff --git a/iop/startup/Makefile b/iop/startup/Makefile index 364218a7e95..8b5f47aeb0f 100644 --- a/iop/startup/Makefile +++ b/iop/startup/Makefile @@ -24,5 +24,5 @@ release: @$(PRINTF) 'Installing %slinkfile into %s/iop/startup\n' $(IOP_SRC_DIR) $(PS2SDK) $(ECHO) Installing $(IOP_SRC_DIR)linkfile into $(PS2SDK)/iop/startup cp -f $(IOP_SRC_DIR)linkfile $(PS2SDK)/iop/startup - @$(ECHO) Installing $(IOP_OBJS_DIR)crt0.o into $(PS2DEV)/ee/mipsel-ps2-irx/lib - cp -f $(IOP_OBJS_DIR)crt0.o $(PS2DEV)/iop/mipsel-ps2-irx/lib + @$(ECHO) Installing $(IOP_OBJS_DIR)crt0.o into $(PS2DEV)/iop/mipsel-none-elf/lib + cp -f $(IOP_OBJS_DIR)crt0.o $(PS2DEV)/iop/mipsel-none-elf/lib diff --git a/iop/startup/src/linkfile b/iop/startup/src/linkfile index 80081197d2e..0b684c5682f 100644 --- a/iop/startup/src/linkfile +++ b/iop/startup/src/linkfile @@ -3,110 +3,158 @@ # ____| | ____| | | |____| # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. #----------------------------------------------------------------------- -# Copyright 2001-2022, ps2dev - http://www.ps2dev.org +# Copyright ps2dev - http://www.ps2dev.org # Licenced under Academic Free License version 2.0 # Review ps2sdk README & LICENSE files for further details. # # Linkfile script for iop-ld */ -OUTPUT_FORMAT("elf32-littlemips") -SEARCH_DIR(""); +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) ENTRY(_start) -PHDRS -{ - irxhdr 0x70000080 FLAGS (PF_R); /* 0x70000080 -> PT_SCE_IOPMOD */ - defhdr PT_LOAD FLAGS (PF_X | PF_W | PF_R); -} + SEARCH_DIR(""); +/* FORCE_COMMON_ALLOCATION */ +/* Do we need any of these for elf? + __DYNAMIC = 0; */ SECTIONS { - . = SIZEOF_HEADERS; - - .text 0 : ALIGN(16) { - CREATE_OBJECT_SYMBOLS - PROVIDE (_ftext = .) ; - KEEP (* ( .module.imports )) ; - * ( .text ) - * ( .text.* ) - * ( .init ) - * ( .fini ) - KEEP (* ( .module.exports )) ; - PROVIDE (_etext = .) ; - } :defhdr = 0 - - .rodata : ALIGN(16) { - * ( .rdata ) - * ( .rodata ) - * ( .rodata1 ) - * ( .rodata.* ) - } :defhdr = 0 - - .data : ALIGN(16) { - * ( .data ) - * ( .data1 ) - * ( .data.* ) - CONSTRUCTORS - } :defhdr = 0 - - .bss : ALIGN(16) { - * ( .bss ) - * ( .bss.* ) - * ( COMMON ) - . = ALIGN(4) ; - } :defhdr - _gp = ALIGN(16) ; - - /* - * This is the .iopmod section for the IRX, it contains information that - * the IOP uses when loading the IRX. - * This section is placed in its own segment. - */ - .iopmod 0 (COPY) : ALIGN(4) { - /* - * The linker will replace this first LONG with a pointer to _irx_id - * if the symbol has been defined. - */ - LONG (DEFINED(_irx_id) ? ABSOLUTE(_irx_id) : 0xffffffff) ; - LONG (ABSOLUTE(_start)) ; - LONG (_gp) ; - LONG (SIZEOF(.text)) ; - LONG (SIZEOF(.data)) ; - LONG (SIZEOF(.bss)) ; - /* - * The linker will put a SHORT here with the version of the IRX - * (or zero if there is no version). - */ - /* - * The linker will put a null terminated string here containing the - * name of the IRX (or an empty string if the name is not known). - */ - KEEP (* ( .iopmod.version )) ; - KEEP (* ( .iopmod.name )) ; - FILL(0x00000000); - } :irxhdr = 0 - - /* - * These are the stuff that we don't want to be put in an IRX. - */ - /DISCARD/ : { - * ( .MIPS.abiflags ) - * ( .comment ) - * ( .debug_* ) - * ( .gnu.attributes ) - * ( .mdebug.* ) - * ( .reginfo ) - * ( .symtab ) - * ( .strtab ) - * ( .shstrtab ) - * ( .eh_frame ) - /* - * This must go because it confuses the IOP kernel (treated as a reloc section). - */ - * ( .pdr ) - /* - * Until I can figure out if there's a better way to rid ourselves of - * .rel.dyn this will have to do. - MRB - */ - * ( .rel.dyn ) - } + /* Read-only sections, merged into text segment: */ + . = 0x0400000; /* Can conditionally be changed to . = 0x5ffe0000 + SIZEOF_HEADERS; */ + .interp : { *(.interp) } /* Can conditionally be removed */ + .reginfo : { *(.reginfo) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0 + .plt : { *(.plt) } + .text : + { + PROVIDE(_ftext = . ); + *(.text) + *(.stub) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + *(.mips16.fn.*) *(.mips16.call.*) + } =0 + PROVIDE(_etext = .); + PROVIDE (etext = .); + .fini : { *(.fini) } =0 + .rodata : { *(.rodata) *(.rodata.*) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x40000) + (. & (0x40000 - 1)); /* Can conditionally be changed to . = .; */ + .data : + { + PROVIDE(_fdata = .); + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : + { + *(.ctors) + } + .dtors : + { + *(.dtors) + } + PROVIDE(_gp = ALIGN(16) + 0x7ff0); + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + PROVIDE(_edata = .); + PROVIDE (edata = .); + __bss_start = .; + PROVIDE(_fbss = .); + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + . = ALIGN(32 / 8); + PROVIDE(_end = .); + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } + /* + * These are the stuff that we don't want to be put in an IRX. + */ + /DISCARD/ : { + * ( .MIPS.abiflags ) + } } diff --git a/samples/Makefile.iopglobal_sample b/samples/Makefile.iopglobal_sample index 0f00a64e83f..94d72eb8b8f 100644 --- a/samples/Makefile.iopglobal_sample +++ b/samples/Makefile.iopglobal_sample @@ -38,7 +38,7 @@ IOP_DBGINFOFLAGS ?= -gdwarf-2 -gz # for finer-grained control over what goes into each IRX. IOP_CFLAGS := -D_IOP -fno-builtin -G0 $(IOP_OPTFLAGS) $(IOP_WARNFLAGS) $(IOP_DBGINFOFLAGS) $(IOP_INCS) $(IOP_CFLAGS) # linker flags -IOP_LDFLAGS := -nostdlib -s $(IOP_LDFLAGS) +IOP_LDFLAGS := -nostdlib -dc -r $(IOP_LDFLAGS) # Additional C compiler flags for GCC >=v5.3.0 # -msoft-float is to "remind" GCC/Binutils that the soft-float ABI is to be used. This is due to a bug, which @@ -67,8 +67,17 @@ endif # Assembler flags IOP_ASFLAGS := $(ASFLAGS_TARGET) -EL -G0 $(IOP_ASFLAGS) +# Default link file +ifeq ($(IOP_LINKFILE),) +IOP_LINKFILE := $(PS2SDK)/iop/startup/linkfile +endif + IOP_OBJS := $(IOP_OBJS:%=$(IOP_OBJS_DIR)%) +IOP_BIN_ELF := $(IOP_BIN:.irx=.notiopmod.elf) + +IOP_BIN_STRIPPED_ELF := $(IOP_BIN:.irx=.notiopmod.stripped.elf) + # Externally defined variables: IOP_BIN, IOP_OBJS, IOP_LIB # These macros can be used to simplify certain build rules. @@ -110,9 +119,17 @@ $(IOP_OBJS_DIR)exports.o: $(IOP_OBJS_DIR)build-exports.c $(DIR_GUARD) $(IOP_C_COMPILE) $(IOP_IETABLE_CFLAGS) -c $< -o $@ -$(IOP_BIN): $(IOP_OBJS) +$(IOP_BIN_ELF): $(IOP_OBJS) + $(DIR_GUARD) + $(IOP_C_COMPILE) -T$(IOP_LINKFILE) $(IOP_OPTFLAGS) -o $@ $(IOP_OBJS) $(IOP_LDFLAGS) $(IOP_LIBS) + +$(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 $@ $< + +$(IOP_BIN): $(IOP_BIN_STRIPPED_ELF) $(DIR_GUARD) - $(IOP_C_COMPILE) $(IOP_OPTFLAGS) -o $(IOP_BIN) $(IOP_OBJS) $(IOP_LDFLAGS) $(IOP_LIBS) + iopfixup --irx1 -o $@ $< $(IOP_LIB): $(IOP_OBJS) $(DIR_GUARD) diff --git a/samples/Makefile.pref_sample b/samples/Makefile.pref_sample index d03c793da70..7fd25f149d8 100644 --- a/samples/Makefile.pref_sample +++ b/samples/Makefile.pref_sample @@ -29,7 +29,7 @@ EE_RANLIB ?= $(EE_TOOL_PREFIX)ranlib # Defintions for the IOP toolchain. # -IOP_TOOL_PREFIX ?= mipsel-ps2-irx- +IOP_TOOL_PREFIX ?= mipsel-none-elf- IOP_CC ?= $(IOP_TOOL_PREFIX)gcc IOP_AS ?= $(IOP_TOOL_PREFIX)as IOP_LD ?= $(IOP_TOOL_PREFIX)ld diff --git a/samples/ps2dev_iop.cmake b/samples/ps2dev_iop.cmake index a4aa9b3b2ad..65a36221654 100644 --- a/samples/ps2dev_iop.cmake +++ b/samples/ps2dev_iop.cmake @@ -25,8 +25,8 @@ endif() SET(CMAKE_SYSTEM_NAME Generic) SET(CMAKE_SYSTEM_VERSION 1) SET(CMAKE_SYSTEM_PROCESSOR mips) -SET(CMAKE_C_COMPILER mipsel-ps2-irx-gcc) -SET(CMAKE_CXX_COMPILER mipsel-ps2-irx-g++) +SET(CMAKE_C_COMPILER mipsel-none-elf-gcc) +SET(CMAKE_CXX_COMPILER mipsel-none-elf-g++) SET(CMAKE_C_COMPILER_WORKS 1) #Hack by f0bes SET(CMAKE_CXX_COMPILER_WORKS 1) #Hack by f0bes diff --git a/tools/Makefile b/tools/Makefile index 1de80dfdd6d..272f2942a3b 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -12,6 +12,7 @@ SUBDIRS = \ ps2-irxgen \ ps2adpcm \ romimg \ + srxfixup \ # gensymtab include $(PS2SDKSRC)/Defs.make diff --git a/tools/srxfixup/.clang-format b/tools/srxfixup/.clang-format new file mode 100644 index 00000000000..61cbfd05b7c --- /dev/null +++ b/tools/srxfixup/.clang-format @@ -0,0 +1,62 @@ +--- +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: AlwaysBreak +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignOperands: AlignAfterOperator +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBraces: Allman +BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 120 +CommentPragmas: '^ (IWYU pragma:|NOLINT)' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 2 +DerivePointerAlignment: false +DisableFormat: false +ForEachMacros: [] +IndentCaseLabels: true +IndentWidth: 2 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInSquareBrackets: false +Standard: c++11 +TabWidth: 2 +UseTab: ForContinuationAndIndentation +SpacesInParens: Custom +SpacesInParensOptions: + InConditionalStatements: true diff --git a/tools/srxfixup/Makefile b/tools/srxfixup/Makefile new file mode 100644 index 00000000000..5dfe8800f4a --- /dev/null +++ b/tools/srxfixup/Makefile @@ -0,0 +1,27 @@ +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright 2001-2022, ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. + +TOOLS_BIN_ALTNAMES ?= eefixup erx-strip iopfixup irx-strip + +TOOLS_OBJS = \ + srxfixup.o \ + anaarg.o \ + ring.o \ + swapmem.o \ + elflib.o \ + elfdump.o \ + mipsdis.o \ + srxgen.o \ + readconf.o \ + iopfixconf.o \ + eefixconf.o + +include $(PS2SDKSRC)/Defs.make +include $(PS2SDKSRC)/tools/Rules.bin.make +include $(PS2SDKSRC)/tools/Rules.make +include $(PS2SDKSRC)/tools/Rules.release diff --git a/tools/srxfixup/README.md b/tools/srxfixup/README.md new file mode 100644 index 00000000000..7d00dc1645b --- /dev/null +++ b/tools/srxfixup/README.md @@ -0,0 +1,28 @@ +# srxfixup + +This tool mainly handles generation of IRX and ERX files, mainly used as +relocatable executables or libraries. +This tool performs the following tasks on relocatable ELF files in order to +ensure that loadcore can load it as a relocatable file: + +* Sets the ELF header `e_type` to `0xFF80`, `0xFF81`, or `0xFF91`, depending +on the features and architecture used + +* Creates the `.iopmod` or `.eemod` section and first program header, +containing metadata about the file, such as name, version, and section sizes/offsets + +* Rebuilds relocations + +## Aliases + +This tool provides the following: + +* `iopfixup` +* `irx-strip` +* `eefixup` +* `erx-strip` + +## Usage + +To see usage and possible command line arguments that can be used with the +program, run it without arguments. diff --git a/tools/srxfixup/src/anaarg.c b/tools/srxfixup/src/anaarg.c new file mode 100644 index 00000000000..afd4bd7b2a3 --- /dev/null +++ b/tools/srxfixup/src/anaarg.c @@ -0,0 +1,178 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "srxfixup_internal.h" +#include +#include +#include +#include + +int analize_arguments(const Opttable *dopttable, int argc, char **argv) +{ + Opt_strings *optstr; + const char *opt; + Opttable *otp; + Opttable *igadd; + Opttable *opttable; + char *cp; + char **argvp; + char **nargv; + int nargc; + int i; + int argca; + char **argva; + + for ( i = 0; dopttable[i].option; i += 1 ) + { + ; + } + opttable = (Opttable *)__builtin_alloca((argc + i) * sizeof(Opttable)); + memset(opttable, 0, (argc + i) * sizeof(Opttable)); + memcpy(opttable, dopttable, i * sizeof(Opttable)); + igadd = &opttable[i]; + nargv = (char **)__builtin_alloca((argc + 1) * sizeof(char *)); + memset(nargv, 0, (argc + 1) * sizeof(char *)); + argvp = argv; + *nargv = *argv; + nargc = 1; + for ( argca = argc - 1, argva = argv + 1;; argca -= 1, argva += 1 ) + { + if ( argca <= 0 ) + { + for ( i = 0; i < nargc + 1; i += 1 ) + { + argvp[i] = nargv[i]; + } + for ( i = 0; opttable[i].option; i += 1 ) + { + if ( opttable[i].vartype == 'l' ) + { + *(SLink **)opttable[i].var = ring_to_liner(*(SLink **)opttable[i].var); + } + } + return nargc; + } + if ( **argva == '-' ) + { + opt = 0; + for ( i = 0; opttable[i].option; i += 1 ) + { + if ( opttable[i].havearg == ARG_HAVEARG_UNK3 ) + { + if ( !strcmp(opttable[i].option, *argva) ) + { + break; + } + } + else + { + if ( !strncmp(opttable[i].option, *argva, strlen(opttable[i].option)) ) + { + break; + } + } + } + if ( !opttable[i].option ) + { + return -1; + } + if ( opttable[i].havearg != ARG_HAVEARG_NONE && opttable[i].havearg != ARG_HAVEARG_UNK3 ) + { + if ( opttable[i].havearg == ARG_HAVEARG_UNK4 || (*argva)[strlen(opttable[i].option)] ) + { + opt = &(*argva)[strlen(opttable[i].option)]; + } + else if ( argca > 1 ) + { + opt = argva[1]; + argva += 1; + argca -= 1; + } + } + if ( opttable[i].havearg != ARG_HAVEARG_REQUIRED || opt ) + { + switch ( opttable[i].vartype ) + { + case 'F': + case 'f': + if ( (*argva)[strlen(opttable[i].option)] ) + { + *(uint32_t *)opttable[i].var = strtoul(&(*argva)[strlen(opttable[i].option)], NULL, 16); + } + else + { + *(uint32_t *)opttable[i].var = (opttable[i].vartype == 'f') ? 1 : 0; + } + break; + case 'h': + if ( opt != NULL ) + { + *(uint32_t *)opttable[i].var = strtoul(opt, 0, 16); + } + break; + case 'i': + if ( opt != NULL ) + { + for ( otp = igadd; opttable < otp; otp -= 1 ) + { + *otp = otp[-1]; + } + igadd += 1; + opttable->option = opt; + opttable->vartype = 'n'; + opttable->havearg = ARG_HAVEARG_UNK3; + cp = strchr(opttable->option, ':'); + if ( cp ) + { + *cp = 0; + switch ( cp[1] ) + { + case 'c': + opttable->havearg = ARG_HAVEARG_UNK4; + break; + case 'n': + opttable->havearg = ARG_HAVEARG_REQUIRED; + break; + case 'o': + opttable->havearg = ARG_HAVEARG_UNK1; + break; + default: + break; + } + } + } + break; + case 'l': + optstr = (Opt_strings *)calloc(1, sizeof(Opt_strings)); + optstr->string = opt; + *(SLink **)opttable[i].var = add_ring_tail(*(SLink **)opttable[i].var, (SLink *)optstr); + break; + case 'n': + break; + case 's': + *(const char **)opttable[i].var = opt; + break; + default: + fprintf(stderr, "internal error\n"); + return -1; + } + } + else + { + return -1; + } + } + else + { + nargv[nargc] = *argva; + nargc += 1; + } + } +} diff --git a/tools/srxfixup/src/eefixconf.c b/tools/srxfixup/src/eefixconf.c new file mode 100644 index 00000000000..f958371380d --- /dev/null +++ b/tools/srxfixup/src/eefixconf.c @@ -0,0 +1,101 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "srxfixup_internal.h" + +// clang-format off +const char *ee_defaultconf = + " @EE\n" + " .reginfo { @remove }\n" + "\n" + " # Elf-header\n" + " # Program-header-table\n" + " .eemod\n" + "\n" + " @Define {\n" + " @Segments_name { TEXT DATA BSS GLOBALDATA AFTER_SHT }\n" + " @Memory_segment { TEXT DATA BSS GLOBALDATA }\n" + " @Program_header_order { .eemod { TEXT DATA BSS } }\n" + " @CreateSymbols {\n" + " ## name bind type segment shindex base\n" + " ## .section\n" + " { _ftext GLOBAL OBJECT TEXT 0 start }\n" + " { etext GLOBAL OBJECT TEXT SHN_RADDR end }\n" + " { _etext GLOBAL OBJECT TEXT SHN_RADDR end }\n" + " { _fdata GLOBAL OBJECT DATA 0 start }\n" + " { edata GLOBAL OBJECT DATA SHN_RADDR end }\n" + " { _edata GLOBAL OBJECT DATA SHN_RADDR end }\n" + " { _fbss GLOBAL OBJECT BSS SHN_RADDR start }\n" + " { end GLOBAL OBJECT BSS SHN_RADDR end }\n" + " { _end GLOBAL OBJECT BSS SHN_RADDR end }\n" + " { _gp GLOBAL OBJECT GLOBALDATA SHN_RADDR gpbase }\n" + " }\n" + " }\n" + "\n" + " # TEXT segment\n" + " .init { @segment {TEXT} } .rel.init { @segment {AFTER_SHT} }\n" + " .text { @segment {TEXT} @createinfo{PROGBITS ALLOC EXECINSTR}}\n" + " .rel.text{ @segment {AFTER_SHT} }\n" + " .gnu.linkonce.t* { @segment {TEXT} }\n" + " .rel.gnu.linkonce.t* { @segment {AFTER_SHT} }\n" + " .fini { @segment {TEXT} } .rel.fini { @segment {AFTER_SHT} }\n" + " .vutext { @segment {TEXT} } .rel.vutext { @segment {AFTER_SHT} }\n" + "\n" + " # DATA segment\n" + " .ctors { @segment {DATA} } .rel.ctors { @segment {AFTER_SHT} }\n" + " .dtors { @segment {DATA} } .rel.dtors { @segment {AFTER_SHT} }\n" + " .eh_frame { @segment {DATA} } .rel.eh_frame { @segment {AFTER_SHT} }\n" + " .gcc_except_table { @segment {DATA} } .rel.gcc_except_table { @segment {AFTER_SHT} }\n" + " .erx.lib { @segment {DATA} } .rel.erx.lib { @segment {AFTER_SHT} }\n" + " .erx.stub{ @segment {DATA} } .rel.erx.stub { @segment {AFTER_SHT} }\n" + " .rodata { @segment {DATA} } .rel.rodata { @segment {AFTER_SHT} }\n" + " .rodata1 { @segment {DATA} } .rel.rodata1 { @segment {AFTER_SHT} }\n" + " .gnu.linkonce.r* { @segment {DATA} }\n" + " .rel.gnu.linkonce.r* { @segment {AFTER_SHT} }\n" + " .data { @segment {DATA} @createinfo {PROGBITS ALLOC WRITE} }\n" + " .rel.data{ @segment {AFTER_SHT} }\n" + " .data1 { @segment {DATA} } .rel.data1 { @segment {AFTER_SHT} }\n" + " .gnu.linkonce.d* { @segment {DATA} }\n" + " .rel.gnu.linkonce.d* { @segment {AFTER_SHT} }\n" + " .vudata { @segment {DATA} } .rel.vudata { @segment {AFTER_SHT} }\n" + "\n" + " .sdata { @segment {DATA GLOBALDATA} } .rel.sdata {@segment{AFTER_SHT}}\n" + " .lit8 { @segment {DATA GLOBALDATA} }\n" + " .lit4 { @segment {DATA GLOBALDATA} }\n" + " .gnu.linkonce.s* { @segment {DATA GLOBALDATA} }\n" + " .rel.gnu.linkonce.s* { @segment {AFTER_SHT} }\n" + "\n" + " # BSS segment\n" + " .sbss { @segment { BSS GLOBALDATA } }\n" + " .bss { @segment { BSS } }\n" + " .vubss { @segment { BSS } }\n" + "\n" + " @Program_header_data { 1 }\n" + "\n" + " .mdebug\n" + " .shstrtab\n" + "\n" + " @Section_header_table\n" + " @Segment_data { AFTER_SHT }\n" + "\n" + " .mdebug.* { @remove }\n" + " .DVP.* { @remove }\n" + " .rel.DVP.* { @remove }\n" + " .jcr { @remove }\n" + " .rel.jcr { @remove }\n" + " .rela.* { @remove }\n" + "\n" + " .symtab\n" + " .strtab\n" + " * ##### other sections\n" + "\n" + "" +; +// clang-format on diff --git a/tools/srxfixup/src/elfdump.c b/tools/srxfixup/src/elfdump.c new file mode 100644 index 00000000000..981647c2163 --- /dev/null +++ b/tools/srxfixup/src/elfdump.c @@ -0,0 +1,1171 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "srxfixup_internal.h" +#include +#include +#include +#include + +struct rellink +{ + int rid; + const elf_rel *rp; + const elf_rel *mhrp; +}; +struct name2num +{ + const char *name; + unsigned int num; +}; + +static void search_rel_section( + const elf_file *elf, const elf_section *scp, elf_rel **result, unsigned int *relentries, unsigned int *baseoff); +static void search_rel_data(const elf_rel *rpbase, unsigned int relentries, unsigned int addr, struct rellink *result); +static void dumpb(const char *head, unsigned int address, unsigned int size, const uint8_t *data); +static void dumph(const char *head, unsigned int address, unsigned int size, const uint16_t *data); +static void dumpw(const char *head, unsigned int address, unsigned int size, const uint32_t *data); +static const char *num2name(const struct name2num *table, unsigned int num); + +void print_elf(const elf_file *elf, unsigned int flag) +{ + if ( elf == NULL ) + { + return; + } + print_elf_ehdr(elf, flag); + print_elf_phdr(elf, flag); + print_elf_sections(elf, flag); + if ( (flag & 0x100) != 0 ) + { + Elf_file_slot *order; + + order = build_file_order_list(elf); + dump_file_order_list(elf, order); + free(order); + } +} + +// clang-format off +static const struct name2num Ei_class_name[] = +{ +#define X(d) { #d, d }, + XEACH_Ei_class_name_enum() +#undef X + { NULL, 0 }, +}; +static const struct name2num E_type_name[] = +{ +#define X(d) { #d, d }, + XEACH_E_type_name_enum() +#undef X + { NULL, 0 }, +}; +static const struct name2num Ei_data_name[] = +{ +#define X(d) { #d, d }, + XEACH_Ei_data_name_enum() +#undef X + { NULL, 0 }, +}; +static const struct name2num E_version_name[] = +{ +#define X(d) { #d, d }, + XEACH_E_version_name_enum() +#undef X + { NULL, 0 }, +}; +static const struct name2num E_machine_name[] = +{ +#define X(d) { #d, d }, + XEACH_E_machine_name_enum() +#undef X + { NULL, 0 }, +}; +// clang-format on + +void print_elf_ehdr(const elf_file *elf, unsigned int flag) +{ + if ( (flag & 1) == 0 ) + { + return; + } + printf(" Elf header\n"); + printf( + " e_ident = 0x%02x+\"%c%c%c\", class = %s, encode = %s\n", + elf->ehp->e_ident[0], + elf->ehp->e_ident[1], + elf->ehp->e_ident[2], + elf->ehp->e_ident[3], + num2name(Ei_class_name, elf->ehp->e_ident[4]), + num2name(Ei_data_name, elf->ehp->e_ident[5])); + printf(" version = %s\n", num2name(E_version_name, elf->ehp->e_ident[6])); + printf( + " e_type = %s, e_machine = %s, e_version = %s\n", + num2name(E_type_name, elf->ehp->e_type), + num2name(E_machine_name, elf->ehp->e_machine), + num2name(E_version_name, elf->ehp->e_version)); + printf( + " e_entry = 0x%08x, e_phoff = 0x%08x, e_shoff = 0x%08x\n", + elf->ehp->e_entry, + elf->ehp->e_phoff, + elf->ehp->e_shoff); + printf(" e_flags = 0x%08x ", elf->ehp->e_flags); + if ( (elf->ehp->e_flags & EF_MIPS_NOREORDER) != 0 ) + { + printf("EF_MIPS_NOREORDER "); + } + if ( (elf->ehp->e_flags & EF_MIPS_PIC) != 0 ) + { + printf("EF_MIPS_PIC"); + } + if ( (elf->ehp->e_flags & EF_MIPS_CPIC) != 0 ) + { + printf("EF_MIPS_CPIC"); + } + printf("\n"); + printf( + " e_ehsize = 0x%04x, e_phentsize = 0x%04x, e_phnum = 0x%04x\n", + elf->ehp->e_ehsize, + elf->ehp->e_phentsize, + elf->ehp->e_phnum); + printf( + " e_shentsize = 0x%04x, e_shnum = 0x%04x, e_shstrndx = 0x%04x\n", + elf->ehp->e_shentsize, + elf->ehp->e_shnum, + elf->ehp->e_shstrndx); +} + +// clang-format off +static const struct name2num P_type_name[] = +{ +#define X(d) { #d, d }, + XEACH_P_type_name_enum() +#undef X + { NULL, 0 }, +}; +// clang-format on + +void print_elf_phdr(const elf_file *elf, unsigned int flag) +{ + int i; + + if ( elf->php == NULL || (flag & 1) == 0 ) + { + return; + } + printf(" Program header\n"); + for ( i = 0; i < elf->ehp->e_phnum; i += 1 ) + { + printf(" %2d: p_type=%s, ", i, num2name(P_type_name, elf->php[i].phdr.p_type)); + printf( + "p_offset=0x%06x, p_vaddr,p_paddr=0x%06x,0x%06x\n", + elf->php[i].phdr.p_offset, + elf->php[i].phdr.p_vaddr, + elf->php[i].phdr.p_paddr); + printf( + " p_filesz=0x%06x, p_memsiz=0x%06x, p_align=%d\n", + elf->php[i].phdr.p_filesz, + elf->php[i].phdr.p_memsz, + (int)(elf->php[i].phdr.p_align)); + printf(" p_flags=0x%08x ( ", elf->php[i].phdr.p_flags); + if ( (elf->php[i].phdr.p_flags & PF_X) != 0 ) + { + printf("PF_X "); + } + if ( (elf->php[i].phdr.p_flags & PF_W) != 0 ) + { + printf("PF_W "); + } + if ( (elf->php[i].phdr.p_flags & PF_R) != 0 ) + { + printf("PF_R "); + } + printf(")\n"); + if ( elf->php[i].scp ) + { + int j; + + printf(" include sections = "); + for ( j = 0; elf->php[i].scp[j]; j += 1 ) + { + printf("%s ", elf->php[i].scp[j]->name); + } + printf("\n"); + } + } +} + +// clang-format off +static const struct name2num S_type_name[] = +{ +#define X(d) { #d, d }, + XEACH_S_type_name_enum() +#undef X + { NULL, 0 }, +}; +// clang-format on + +void print_elf_sections(const elf_file *elf, unsigned int flag) +{ + int i; + + if ( elf->scp == NULL ) + { + return; + } + if ( (flag & 1) != 0 ) + { + printf(" Section header\n"); + } + for ( i = 1; i < elf->ehp->e_shnum; i += 1 ) + { + if ( (flag & 1) != 0 || ((flag & 2) != 0 && elf->scp[i]->shr.sh_type == SHT_REL) ) + { + printf( + " %2d: %-12s sh_name=0x%04x sh_type=%s\n", + i, + elf->scp[i]->name, + elf->scp[i]->shr.sh_name, + num2name(S_type_name, elf->scp[i]->shr.sh_type)); + printf(" sh_flas=0x%08x ( ", elf->scp[i]->shr.sh_flags); + if ( (elf->scp[i]->shr.sh_flags & SHF_WRITE) != 0 ) + { + printf("SHF_WRITE "); + } + if ( (elf->scp[i]->shr.sh_flags & SHF_ALLOC) != 0 ) + { + printf("SHF_ALLOC "); + } + if ( (elf->scp[i]->shr.sh_flags & SHF_EXECINSTR) != 0 ) + { + printf("SHF_EXECINSTR "); + } + if ( (elf->scp[i]->shr.sh_flags & SHF_MIPS_GPREL) != 0 ) + { + printf("SHF_MIPS_GPREL "); + } + printf(")\n"); + printf( + " sh_addr,sh_offset,sh_size=0x%06x,0x%06x,0x%06x, sh_addralign=%2d\n", + elf->scp[i]->shr.sh_addr, + elf->scp[i]->shr.sh_offset, + elf->scp[i]->shr.sh_size, + (int)(elf->scp[i]->shr.sh_addralign)); + printf( + " sh_link=0x%08x, sh_info=0x%08x, sh_entsize=0x%02x(%d)\n", + elf->scp[i]->shr.sh_link, + elf->scp[i]->shr.sh_info, + elf->scp[i]->shr.sh_entsize, + (int)(elf->scp[i]->shr.sh_entsize)); + } + switch ( elf->scp[i]->shr.sh_type ) + { + case SHT_SYMTAB: + case SHT_DYNSYM: + print_elf_symtbl(elf->scp[i], flag); + continue; + case SHT_REL: + print_elf_reloc(elf->scp[i], flag); + continue; + case SHT_MIPS_DEBUG: + print_elf_mips_symbols((elf_mips_symbolic_data *)elf->scp[i]->data, flag); + continue; + case SHT_SCE_IOPMOD: + if ( (flag & 1) != 0 ) + { + const Elf32_IopMod *data; + + data = (Elf32_IopMod *)elf->scp[i]->data; + printf( + " moduleinfo=0x%08x, entry=0x%08x, gpvalue=0x%08x\n", data->moduleinfo, data->entry, data->gp_value); + printf( + " text_size=0x%08x, data_size=0x%08x, bss_size=0x%08x\n", + data->text_size, + data->data_size, + data->bss_size); + } + break; + case SHT_SCE_EEMOD: + if ( (flag & 1) != 0 ) + { + const Elf32_EeMod *data; + + data = (Elf32_EeMod *)elf->scp[i]->data; + printf( + " moduleinfo=0x%08x, entry=0x%08x, gpvalue=0x%08x\n", data->moduleinfo, data->entry, data->gp_value); + printf( + " text_size=0x%08x, data_size=0x%08x, bss_size=0x%08x\n", + data->text_size, + data->data_size, + data->bss_size); + printf(" erx_lib_addr=0x%08x, erx_lib_size=0x%08x\n", data->erx_lib_addr, data->erx_lib_size); + printf(" erx_stub_addr=0x%08x, erx_stub_size=0x%08x\n", data->erx_stub_addr, data->erx_stub_size); + } + break; + case SHT_MIPS_REGINFO: + if ( (flag & 1) != 0 ) + { + const Elf32_RegInfo *data; + + data = (Elf32_RegInfo *)elf->scp[i]->data; + printf( + " gpmask=0x08x, cprmask=%08x,%08x,%08x,%08x\n", + data->ri_gprmask, + data->ri_cprmask[0], + data->ri_cprmask[1], + data->ri_cprmask[3]); + printf(" gp=0x%08x\n", data->ri_gp_value); + } + break; + default: + break; + } + if ( elf->scp[i]->data ) + { + if ( (elf->scp[i]->shr.sh_flags & SHF_EXECINSTR) != 0 && elf->ehp->e_machine == EM_MIPS ) + { + if ( + ((elf->ehp->e_flags & EF_MIPS_MACH) == EF_MIPS_MACH_5900) + && ((elf->ehp->e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_3) ) + { + initdisasm(2, -1, 0, 0, 0); + } + else + { + initdisasm(1, -1, 0, 0, 0); + } + print_elf_disasm(elf, elf->scp[i], flag); + } + else + { + print_elf_datadump(elf, elf->scp[i], flag); + } + } + } +} + +// clang-format off +static const struct name2num R_MIPS_Type[] = +{ +#define X(d) { #d, d }, + XEACH_R_MIPS_Type_enum() +#undef X + { NULL, 0 }, +}; +// clang-format on + +void print_elf_reloc(const elf_section *scp, unsigned int flag) +{ + const elf_rel *rp; + unsigned int entrise; + unsigned int i; + + if ( (flag & 2) == 0 ) + { + return; + } + entrise = scp->shr.sh_size / scp->shr.sh_entsize; + if ( entrise != 0 ) + { + printf(" ###: r_offset r_type r_sym\n"); + printf(" --- -------- -------------------- -----------------------------------\n"); + } + rp = (elf_rel *)scp->data; + for ( i = 0; i < entrise; i += 1 ) + { + printf(" %3u: 0x%06x 0x%02x %-16s ", i, rp[i].rel.r_offset, rp[i].type, num2name(R_MIPS_Type, rp[i].type)); + if ( rp[i].symptr && rp[i].symptr->type == STT_SECTION ) + { + printf("0x%03x[%s]\n", rp[i].rel.r_info >> 8, rp[i].symptr->shptr->name); + } + else + { + printf("0x%03x %s\n", rp[i].rel.r_info >> 8, (rp[i].symptr && rp[i].symptr->name) ? rp[i].symptr->name : ""); + } + } + printf("\n"); +} + +void print_elf_disasm(const elf_file *elf, const elf_section *scp, unsigned int flag) +{ + int v7; + const elf_rel *rp; + elf_rel *rpbase; + struct rellink *rel; + Disasm_result **dis; + char pb[200]; + unsigned int baseoff; + unsigned int addr; + const unsigned int *codes; + unsigned int relentries; + size_t steps; + int d; + unsigned int i; + + if ( (flag & 8) == 0 ) + { + return; + } + steps = scp->shr.sh_size >> 2; + codes = (unsigned int *)scp->data; + dis = (Disasm_result **)malloc(steps * sizeof(Disasm_result *)); + search_rel_section(elf, scp, &rpbase, &relentries, &baseoff); + rel = (struct rellink *)calloc(steps, sizeof(struct rellink)); + for ( i = 0, addr = 0; i < steps; i += 1, addr += 4 ) + { + dis[i] = disassemble(addr, codes[i]); + gen_asmmacro(dis[i]); + search_rel_data(rpbase, relentries, baseoff + addr, &rel[i]); + } + for ( i = 0; i < steps; i += 1 ) + { + if ( rel[i].rp && rel[i].rp->type == R_MIPSSCE_MHI16 ) + { + unsigned int j; + + j = i; + for ( d = (int16_t)(codes[i] & 0xFFFF); d; d = (int16_t)(codes[j] & 0xFFFF) ) + { + j += d; + rel[j].rid = rel[i].rid; + rel[j].mhrp = rel[i].rp; + } + } + } + for ( i = 0; i < steps; i += 1 ) + { + format_disasm(dis[i], pb); + if ( rel[i].rp || rel[i].mhrp ) + { + size_t k; + + for ( k = strlen(pb); k <= 47; k += 1 ) + { + pb[k] = 32; + } + pb[48] = 0; + sprintf(&pb[strlen(pb)], "%3d:", rel[i].rid); + if ( rel[i].rp ) + { + rp = rel[i].rp; + strcat(pb, " "); + } + else + { + rp = rel[i].mhrp; + strcat(pb, ">"); + } + if ( rp->symptr && rp->symptr->type == STT_SECTION ) + { + sprintf( + &pb[strlen(pb)], + " %s %d '%s'", + num2name(R_MIPS_Type, rp->type), + (int)(rp->rel.r_info >> 8), + rp->symptr->shptr->name); + } + else + { + v7 = ' '; + if ( rp->symptr ) + { + switch ( rp->symptr->bind ) + { + case STB_GLOBAL: + v7 = 'E'; + break; + case STB_LOCAL: + v7 = 'l'; + break; + case STB_WEAK: + v7 = 'w'; + break; + default: + break; + } + } + sprintf( + &pb[strlen(pb)], + "%c %s %d %s", + v7, + num2name(R_MIPS_Type, rp->type), + (int)(rp->rel.r_info >> 8), + (rp->symptr && rp->symptr->name) ? rp->symptr->name : ""); + } + } + printf(" %s\n", pb); + free(dis[i]); + } + printf("\n"); + free(dis); + free(rel); +} + +static void search_rel_section( + const elf_file *elf, const elf_section *scp, elf_rel **result, unsigned int *relentries, unsigned int *baseoff) +{ + elf_section *relscp; + int i; + + relscp = 0; + for ( i = 1; i < elf->ehp->e_shnum; i += 1 ) + { + relscp = elf->scp[i]; + if ( relscp->shr.sh_type == SHT_REL && scp == relscp->info ) + { + break; + } + } + if ( i < elf->ehp->e_shnum ) + { + *result = (elf_rel *)relscp->data; + *relentries = relscp->shr.sh_size / relscp->shr.sh_entsize; + *baseoff = 0; + switch ( elf->ehp->e_type ) + { + case ET_SCE_IOPRELEXEC: + case ET_SCE_IOPRELEXEC2: + case ET_SCE_EERELEXEC: + case ET_SCE_EERELEXEC2: + *baseoff = scp->shr.sh_addr; + break; + default: + break; + } + } + else + { + *result = 0; + *relentries = 0; + *baseoff = 0; + } +} + +static void search_rel_data(const elf_rel *rpbase, unsigned int relentries, unsigned int addr, struct rellink *result) +{ + int j; + + result->rid = -1; + result->rp = 0; + for ( j = 0; j < (int)relentries; j += 1 ) + { + if ( rpbase[j].type != R_MIPSSCE_ADDEND && addr == rpbase[j].rel.r_offset ) + { + result->rid = j; + result->rp = &rpbase[j]; + return; + } + } +} + +static void dumpb(const char *head, unsigned int address, unsigned int size, const uint8_t *data) +{ + uint8_t cbuf[20]; + unsigned int addr; + unsigned int off2; + unsigned int off1; + + addr = address & ~0xF; + off1 = 0; + off2 = size; + strcpy((char *)cbuf, "........ ........"); + for ( ; off1 < off2; addr += 1 ) + { + if ( (addr & 0xF) == 0 ) + { + printf("%s%08x: ", head, addr); + } + if ( address > addr ) + { + printf("-- "); + } + else + { + printf("%02x ", data[off1]); + if ( data[off1] > 0x1F && data[off1] <= 0x7E ) + { + unsigned int v4; + uint8_t *v5; + + v4 = addr & 0xF; + if ( v4 <= 7 ) + { + v5 = &cbuf[v4]; + } + else + { + v5 = &cbuf[v4 + 1]; + } + *v5 = data[off1]; + } + } + if ( (((uint8_t)addr + 1) & 3) == 0 ) + { + printf(" "); + } + if ( (addr & 0xF) == 15 ) + { + printf("%s", cbuf); + printf("\n"); + strcpy((char *)cbuf, "........ ........"); + } + if ( address <= addr ) + { + off1 += 1; + } + } + for ( ; (addr & 0xF) != 0; addr += 1 ) + { + printf("-- "); + if ( (((uint8_t)addr + 1) & 3) == 0 ) + { + printf(" "); + } + if ( (addr & 0xF) == 15 ) + { + printf("%s", cbuf); + printf("\n"); + strcpy((char *)cbuf, "........ ........"); + } + } +} + +static void dumph(const char *head, unsigned int address, unsigned int size, const uint16_t *data) +{ + unsigned int addr; + unsigned int off2; + unsigned int off1; + + addr = address & ~0xF; + off2 = addr; + off1 = 0; + for ( ; off1 < size; off2 += 2 ) + { + if ( (off2 & 0xF) == 0 ) + { + printf("%s%08x: ", head, off2); + } + if ( address > off2 ) + { + printf("---- "); + } + else + { + printf("%04x ", data[off1 >> 1]); + } + if ( (((uint8_t)off2 + 2) & 3) == 0 ) + { + printf(" "); + } + if ( (off2 & 0xF) == 14 ) + { + printf("\n"); + } + if ( address <= off2 ) + { + off1 += 2; + } + } + for ( ; (off2 & 0xF) != 0; off2 += 2 ) + { + printf("---- "); + if ( (((uint8_t)off2 + 2) & 3) == 0 ) + { + printf(" "); + } + if ( (off2 & 0xF) == 14 ) + { + printf("\n"); + } + } +} + +static void dumpw(const char *head, unsigned int address, unsigned int size, const uint32_t *data) +{ + unsigned int off1; + unsigned int addr; + + addr = address & ~0xF; + off1 = 0; + for ( ; off1 < size; addr += 4 ) + { + if ( (addr & 0xF) == 0 ) + { + printf("%s%08x: ", head, addr); + } + if ( address > addr ) + { + printf("-------- "); + } + else + { + printf("%08x ", data[off1 >> 2]); + } + if ( (addr & 0xF) == 12 ) + { + printf("\n"); + } + if ( address <= addr ) + { + off1 += 4; + } + } + for ( ; (addr & 0xF) != 0; addr += 4 ) + { + printf("-------- "); + if ( (addr & 0xF) == 12 ) + { + printf("\n"); + } + } +} + +void print_elf_datadump(const elf_file *elf, const elf_section *scp, unsigned int flag) +{ + elf_rel *rpbase; + struct rellink rel; + unsigned int relentries; + unsigned int baseoff; + unsigned int *dumpbuf; + + if ( (flag & 0xF0) == 0 ) + { + return; + } + dumpbuf = (unsigned int *)calloc(1, scp->shr.sh_size + 4); + memcpy(dumpbuf, scp->data, scp->shr.sh_size); + switch ( scp->shr.sh_type ) + { + case SHT_PROGBITS: + case SHT_HASH: + case SHT_DYNAMIC: + case SHT_MIPS_REGINFO: + swapmemory(dumpbuf, "l", (scp->shr.sh_size + 1) >> 2); + break; + default: + break; + } + printf("\n"); + if ( (flag & 0x10) != 0 ) + { + dumpb("", 0, scp->shr.sh_size, (uint8_t *)dumpbuf); + printf("\n"); + } + if ( (flag & 0x20) != 0 ) + { + dumph(" ", 0, scp->shr.sh_size, (uint16_t *)dumpbuf); + printf("\n"); + } + if ( (flag & 0xC0) != 0 ) + { + unsigned int offset; + + search_rel_section(elf, scp, &rpbase, &relentries, &baseoff); + for ( offset = 0; offset < scp->shr.sh_size; offset += 16 ) + { + dumpw( + " ", + offset, + (scp->shr.sh_size > offset + 16) ? 16 : (scp->shr.sh_size - offset), + &dumpbuf[offset / 4]); + if ( (flag & 0x80) != 0 ) + { + int i; + + for ( i = 0; i <= 15 && (offset + i) < scp->shr.sh_size; i += 4 ) + { + search_rel_data(rpbase, relentries, baseoff + offset + i, &rel); + if ( rel.rid >= 0 ) + { + printf(" +%02x:", i); + printf(" [%3d]", rel.rid); + if ( rel.rp->symptr && rel.rp->symptr->type == STT_SECTION ) + { + printf( + " %s %d '%s'", + num2name(R_MIPS_Type, rel.rp->type), + (int)(rel.rp->rel.r_info >> 8), + rel.rp->symptr->shptr->name); + } + else + { + int v7; + + v7 = ' '; + if ( rel.rp->symptr ) + { + switch ( rel.rp->symptr->bind ) + { + case STB_GLOBAL: + v7 = 'E'; + break; + case STB_LOCAL: + v7 = 'l'; + break; + case STB_WEAK: + v7 = 'w'; + break; + default: + break; + } + } + printf( + "%c %s %d %s", + v7, + num2name(R_MIPS_Type, rel.rp->type), + (int)(rel.rp->rel.r_info >> 8), + (rel.rp->symptr && rel.rp->symptr->name) ? rel.rp->symptr->name : ""); + } + printf("\n"); + } + } + } + } + printf("\n"); + } + free(dumpbuf); +} + +// clang-format off +static const struct name2num SymbolBinding[] = +{ +#define X(d) { #d, d }, + XEACH_SymbolBinding_enum() +#undef X + { NULL, 0 }, +}; +static const struct name2num SymbolType[] = +{ +#define X(d) { #d, d }, + XEACH_SymbolType_enum() +#undef X + { NULL, 0 }, +}; +static const struct name2num SymbolSpSection[] = +{ +#define X(d) { #d, d }, + XEACH_SymbolSpSection_enum() +#undef X + { NULL, 0 }, +}; +// clang-format on + +void print_elf_symtbl(const elf_section *scp, unsigned int flag) +{ + elf_syment **syp; + unsigned int entirse; + unsigned int i; + + if ( (flag & 4) == 0 ) + { + return; + } + entirse = scp->shr.sh_size / scp->shr.sh_entsize; + syp = (elf_syment **)scp->data; + if ( entirse > 1 ) + { + printf(" ###: name bind type st_value st_size st_shndx\n"); + printf(" --- ----------- ---------- ----------- ---------- ------ ------------------\n"); + } + for ( i = 1; i < entirse; i += 1 ) + { + printf(" %3u: ", i); + if ( syp[i]->name && strlen(syp[i]->name) > 0xB ) + { + printf("%s\n ", syp[i]->name); + } + else + { + printf("%-11s ", syp[i]->name ?: ""); + } + printf( + "%-10s %-11s 0x%08x 0x%04x ", + num2name(SymbolBinding, syp[i]->bind), + num2name(SymbolType, syp[i]->type), + syp[i]->sym.st_value, + syp[i]->sym.st_size); + if ( syp[i]->shptr ) + { + printf("%2d '%s'", syp[i]->sym.st_shndx, syp[i]->shptr->name); + } + else + { + int st_shndx; + + st_shndx = syp[i]->sym.st_shndx; + printf("%s(0x%x)", num2name(SymbolSpSection, st_shndx), st_shndx); + } + if ( syp[i]->sym.st_other ) + { + printf(" st_other=0x%x", syp[i]->sym.st_other); + } + printf("\n"); + } + printf("\n"); +} + +static const char *num2name(const struct name2num *table, unsigned int num) +{ + static char buf_28[30]; + + for ( ; table->name; table += 1 ) + { + if ( num == table->num ) + { + return table->name; + } + } + sprintf(buf_28, "? 0x%x", num); + return buf_28; +} + +// clang-format off +static const struct name2num SymbolTypes[] = +{ +#define X(d) { #d, d }, + XEACH_SymbolTypes_enum() +#undef X + { NULL, 0 }, +}; +static const struct name2num StorageClasse[] = +{ +#define X(d) { #d, d }, + XEACH_StorageClasse_enum() +#undef X + { NULL, 0 }, +}; +// clang-format on + +void print_elf_mips_symbols(const elf_mips_symbolic_data *symbol, unsigned int flag) +{ + fdr *fdrp; + unsigned int ifd; + + if ( (flag & 0x200) == 0 || symbol == NULL ) + { + return; + } + printf(" Symbol header\n"); + printf(" magic=0x%x vstamp=0x%x\n", symbol->head.magic, symbol->head.vstamp); + printf( + " ilineMax= %4u cbLine= %6u cbLineOffset=%u(0x%05x)\n", + symbol->head.ilineMax, + symbol->head.cbLine, + symbol->head.cbLineOffset, + symbol->head.cbLineOffset); + printf( + " idnMax= %4u cbDnOffset= %6u(0x%05x)\n", + symbol->head.idnMax, + symbol->head.cbDnOffset, + symbol->head.cbDnOffset); + printf( + " ipdMax= %4u cbPdOffset= %6u(0x%05x)\n", + symbol->head.ipdMax, + symbol->head.cbPdOffset, + symbol->head.cbPdOffset); + printf( + " isymMax= %4u cbSymOffset= %6u(0x%05x)\n", + symbol->head.isymMax, + symbol->head.cbSymOffset, + symbol->head.cbSymOffset); + printf( + " ioptMax= %4u cbOptOffset= %6u(0x%05x)\n", + symbol->head.ioptMax, + symbol->head.cbOptOffset, + symbol->head.cbOptOffset); + printf( + " iauxMax= %4u cbAuxOffset= %6u(0x%05x)\n", + symbol->head.iauxMax, + symbol->head.cbAuxOffset, + symbol->head.cbAuxOffset); + printf( + " issMax= %4u cbSsOffset= %6u(0x%05x)\n", + symbol->head.issMax, + symbol->head.cbSsOffset, + symbol->head.cbSsOffset); + printf( + " issExtMax=%4u cbSsExtOffset=%6u(0x%05x)\n", + symbol->head.issExtMax, + symbol->head.cbSsExtOffset, + symbol->head.cbSsExtOffset); + printf( + " ifdMax= %4u cbFdOffset= %6u(0x%05x)\n", + symbol->head.ifdMax, + symbol->head.cbFdOffset, + symbol->head.cbFdOffset); + printf( + " crfd= %4u cbRfdOffset= %6u(0x%05x)\n", + symbol->head.crfd, + symbol->head.cbRfdOffset, + symbol->head.cbRfdOffset); + printf( + " iextMax= %4u cbExtOffset= %6u(0x%05x)\n", + symbol->head.iextMax, + symbol->head.cbExtOffset, + symbol->head.cbExtOffset); + printf("\n"); + if ( symbol->head.issMax > 0 ) + { + int i_1; + const char *cp_1; + const char *cpend_1; + + cp_1 = symbol->cbSs_Ptr; + cpend_1 = &cp_1[symbol->head.issMax]; + printf(" Local strings\n"); + for ( i_1 = 0; cp_1 < cpend_1; i_1 += 1 ) + { + printf(" %3d(%5d): %s\n", i_1, (int)(cp_1 - symbol->cbSs_Ptr), cp_1); + cp_1 += strlen(cp_1) + 1; + } + printf("\n"); + } + if ( symbol->head.issExtMax > 0 ) + { + int i_2; + const char *cp_2; + const char *cpend_2; + + cp_2 = symbol->cbSsExt_Ptr; + cpend_2 = &cp_2[symbol->head.issExtMax]; + printf(" External strings\n"); + for ( i_2 = 0; cp_2 < cpend_2; i_2 += 1 ) + { + printf(" %3d(%5d): %s\n", i_2, (int)(cp_2 - symbol->cbSsExt_Ptr), cp_2); + cp_2 += strlen(cp_2) + 1; + } + printf("\n"); + } + if ( symbol->head.iextMax > 0 ) + { + extr *ep; + unsigned int i_3; + + ep = (extr *)symbol->cbExt_Ptr; + printf(" External symbols\n"); + for ( i_3 = 0; i_3 < symbol->head.iextMax; i_3 += 1 ) + { + unsigned int idx_1; + unsigned int class_1; + unsigned int type_1; + + type_1 = ep->asym.sy_bits & 0x3F; + class_1 = (ep->asym.sy_bits >> 6) & 0x1F; + idx_1 = ep->asym.sy_bits >> 12; + printf(" %3u: res,ifd=%04x,%04hx", i_3, ep->reserved, (unsigned short)(ep->ifd)); + printf(", 0x%08x", ep->asym.value); + printf(", %8s:%-7s 0x%05x ", num2name(SymbolTypes, type_1), num2name(StorageClasse, class_1), idx_1); + printf("%s\n", &symbol->cbSsExt_Ptr[ep->asym.iss]); + ep += 1; + } + printf("\n"); + } + printf(" Local informations\n"); + fdrp = (fdr *)symbol->cbFd_Ptr; + for ( ifd = 0; ifd < symbol->head.ifdMax; ifd += 1 ) + { + const char *issBase; + + issBase = &symbol->cbSs_Ptr[fdrp->issBase]; + printf(" %3u: %-40s addr=0x%08x \n", ifd, &issBase[fdrp->rss], fdrp->adr); + if ( fdrp->csym > 0 ) + { + symr *syp_1; + int i_4; + + syp_1 = (symr *)&symbol->cbSym_Ptr[sizeof(symr) * fdrp->isymBase]; + printf(" Local symbols\n"); + for ( i_4 = 0; i_4 < fdrp->csym; i_4 += 1 ) + { + unsigned int idx_2; + unsigned int class_2; + unsigned int type_2; + + type_2 = syp_1->sy_bits & 0x3F; + class_2 = (syp_1->sy_bits >> 6) & 0x1F; + idx_2 = syp_1->sy_bits >> 12; + printf(" %3d: 0x%08x", i_4, syp_1->value); + printf(", %10s:%-10s 0x%05x ", num2name(SymbolTypes, type_2), num2name(StorageClasse, class_2), idx_2); + printf("%s\n", &issBase[syp_1->iss]); + syp_1 += 1; + } + } + if ( fdrp->cline > 0 ) + { + printf(" Line numbers\n"); + printf(" ilinBase = %d, cline= %d\n", fdrp->ilineBase, fdrp->cline); + } + if ( fdrp->copt > 0 ) + { + printf(" Optimization entries\n"); + printf(" ioptBase = %d, copt = %d\n", fdrp->ioptBase, fdrp->copt); + } + if ( fdrp->cpd > 0 ) + { + pdr *pdrp_2; + const symr *syp_2; + int i_5; + + syp_2 = (symr *)&symbol->cbSym_Ptr[sizeof(symr) * fdrp->isymBase]; + pdrp_2 = (pdr *)&symbol->cbPd_Ptr[sizeof(pdr) * fdrp->ipdFirst]; + printf(" Procedures\n"); + for ( i_5 = 0; i_5 < fdrp->cpd; i_5 += 1 ) + { + printf(" %3d: 0x%08x %s\n", i_5, pdrp_2->adr, &issBase[syp_2[pdrp_2->isym].iss]); + printf( + " regmask=0x%08x, regoffset=%d, fregmask=0x%08x, fregoffset=%d\n", + pdrp_2->regmask, + pdrp_2->regoffset, + pdrp_2->fregmask, + pdrp_2->fregoffset); + printf( + " iopt=%d, frameoffset=%d, framereg=%d, pcreg=%d, line %d..%d\n", + pdrp_2->iopt, + pdrp_2->frameoffset, + pdrp_2->framereg, + pdrp_2->pcreg, + pdrp_2->lnLow, + pdrp_2->lnHigh); + printf(" iline=%d, cbLineOffset=%d\n", pdrp_2->iline, (int)(pdrp_2->cbLineOffset)); + pdrp_2 += 1; + } + } + if ( fdrp->caux > 0 ) + { + const unsigned int *ip_1; + int i_6; + + printf(" Auxillary symbol entries\n"); + ip_1 = (unsigned int *)&symbol->cbAux_Ptr[sizeof(unsigned int) * fdrp->iauxBase]; + for ( i_6 = 0; i_6 < fdrp->caux; i_6 += 1 ) + { + printf(" %3d: 0x%08lx \n", i_6, (unsigned long)(*ip_1)); + ip_1 += 1; + } + } + if ( fdrp->crfd > 0 ) + { + const unsigned int *ip_2; + int i_7; + + printf(" File indirect entries\n"); + ip_2 = (unsigned int *)&symbol->cbRfd_Ptr[sizeof(unsigned int) * fdrp->rfdBase]; + for ( i_7 = 0; i_7 < fdrp->crfd; i_7 += 1 ) + { + printf(" %3d: 0x%08lx \n", i_7, (unsigned long)(*ip_2)); + ip_2 += 1; + } + } + printf("\n"); + fdrp += 1; + } + printf("\n"); +} diff --git a/tools/srxfixup/src/elflib.c b/tools/srxfixup/src/elflib.c new file mode 100644 index 00000000000..b370b81dfb1 --- /dev/null +++ b/tools/srxfixup/src/elflib.c @@ -0,0 +1,1666 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "srxfixup_internal.h" +#include +#include +#include +#include + +static int is_in_range(unsigned int top, unsigned int size, unsigned int pos); +static void read_symtab(elf_file *elf, int sctindex, FILE *fp); +static void read_rel(elf_file *elf, int sctindex, FILE *fp); +static elf_mips_symbolic_data *read_mips_symbolic(FILE *fp); +static void renumber_a_symtab(elf_section *scp); +static void renumber_symtab(elf_file *elf); +static void write_symtab(elf_file *elf, int sctindex, FILE *fp); +static void write_rel(elf_file *elf, int sctindex, FILE *fp); +static void write_mips_symbolic(elf_mips_symbolic_data *sycb, unsigned int basepos, FILE *fp); +static void reorder_an_symtab(elf_file *elf, elf_section *scp); +static size_t search_string_table(const char *tbltop, size_t endindex, const char *str); +static void rebuild_a_symbol_name_strings(elf_section *scp); +static int comp_Elf_file_slot(const void *a1, const void *a2); + +elf_file *read_elf(const char *filename) +{ + uint32_t ident; + elf_file *elf; + FILE *fp; + + fp = fopen(filename, "rbe"); + if ( !fp ) + { + fprintf(stderr, "`%s' can't open\n", filename); + return 0; + } + elf = (elf_file *)calloc(1, sizeof(elf_file)); + elf->ehp = (Elf32_Ehdr *)malloc(sizeof(Elf32_Ehdr)); + if ( fread(elf->ehp, sizeof(Elf32_Ehdr), 1, fp) != 1 ) + { + fprintf(stderr, "%s: Could not read ELF header\n", filename); + exit(1); + } + swapmemory(elf->ehp, "ccccccccccccccccsslllllssssss", 1); + ident = *(uint32_t *)elf->ehp->e_ident; + swapmemory(&ident, "l", 1); + if ( ident != 0x464C457F ) + { + fprintf(stderr, "%s: not elf format\n", filename); + free(elf->ehp); + free(elf); + fclose(fp); + return 0; + } + if ( elf->ehp->e_ident[4] != ELFCLASS32 || elf->ehp->e_ident[5] != ELFDATA2LSB || elf->ehp->e_ident[6] != EV_CURRENT ) + { + fprintf(stderr, "%s: Not 32-bit object or Not little endian or Invalid Elf version\n", filename); + free(elf->ehp); + free(elf); + fclose(fp); + return 0; + } + if ( elf->ehp->e_machine != EM_MIPS ) + { + fprintf(stderr, "%s: not EM_MIPS\n", filename); + free(elf->ehp); + free(elf); + fclose(fp); + return 0; + } + if ( elf->ehp->e_phentsize && elf->ehp->e_phentsize != sizeof(Elf32_Phdr) ) + { + fprintf(stderr, "%s: Unknown program header size\n", filename); + free(elf->ehp); + free(elf); + fclose(fp); + return 0; + } + if ( elf->ehp->e_shentsize && elf->ehp->e_shentsize != sizeof(Elf32_Shdr) ) + { + fprintf(stderr, "%s: Unknown sectoin header size\n", filename); + free(elf->ehp); + free(elf); + fclose(fp); + return 0; + } + if ( elf->ehp->e_phnum && elf->ehp->e_phentsize ) + { + signed int count_1; + unsigned int pos_1; + int i_1; + + count_1 = elf->ehp->e_phnum; + pos_1 = elf->ehp->e_phoff; + elf->php = (elf_proghead *)calloc(count_1, sizeof(elf_proghead)); + fseek(fp, pos_1, SEEK_SET); + for ( i_1 = 0; count_1 > i_1; i_1 += 1 ) + { + if ( fread(&elf->php[i_1], sizeof(Elf32_Phdr), 1, fp) != 1 ) + { + fprintf(stderr, "%s: Could not read ELF program header\n", filename); + exit(1); + } + swapmemory(&elf->php[i_1], "llllllll", 1); + } + } + if ( elf->ehp->e_shnum && elf->ehp->e_shentsize ) + { + signed int count_2; + unsigned int pos_2; + int i_2; + int i_3; + int i_4; + + pos_2 = elf->ehp->e_shoff; + count_2 = elf->ehp->e_shnum; + elf->scp = (elf_section **)calloc(count_2 + 1, sizeof(elf_section *)); + fseek(fp, pos_2, SEEK_SET); + for ( i_2 = 0; count_2 > i_2; i_2 += 1 ) + { + elf->scp[i_2] = (elf_section *)calloc(1, sizeof(elf_section)); + if ( fread(elf->scp[i_2], sizeof(Elf32_Shdr), 1, fp) != 1 ) + { + fprintf(stderr, "%s: Could not read ELF section header\n", filename); + exit(1); + } + swapmemory(elf->scp[i_2], "llllllllll", 1); + } + for ( i_3 = 0; count_2 > i_3; i_3 += 1 ) + { + switch ( elf->scp[i_3]->shr.sh_type ) + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" + case SHT_RELA: + case SHT_REL: + elf->scp[i_3]->info = elf->scp[elf->scp[i_3]->shr.sh_info]; + case SHT_SYMTAB: + case SHT_HASH: + case SHT_DYNAMIC: + case SHT_DYNSYM: + elf->scp[i_3]->link = elf->scp[elf->scp[i_3]->shr.sh_link]; + break; +#pragma GCC diagnostic pop + default: + break; + } + if ( i_3 == elf->ehp->e_shstrndx ) + { + elf->shstrptr = elf->scp[i_3]; + } + } + for ( i_4 = 0;; i_4 += 1 ) + { + unsigned int size; + unsigned int pos_3; + + if ( count_2 <= i_4 ) + { + int i_5; + int i_6; + int i_7; + int i_8; + + for ( i_5 = 0; count_2 > i_5; i_5 += 1 ) + { + unsigned int pos_4; + + pos_4 = elf->scp[i_5]->shr.sh_offset; + switch ( elf->scp[i_5]->shr.sh_type ) + { + case SHT_SYMTAB: + case SHT_DYNSYM: + if ( pos_4 != 0 && elf->scp[i_5]->shr.sh_size ) + { + fseek(fp, pos_4, SEEK_SET); + read_symtab(elf, i_5, fp); + } + break; + default: + break; + } + } + for ( i_6 = 0; count_2 > i_6; i_6 += 1 ) + { + unsigned int pos_5; + + pos_5 = elf->scp[i_6]->shr.sh_offset; + if ( elf->scp[i_6]->shr.sh_type == SHT_REL && pos_5 != 0 && elf->scp[i_6]->shr.sh_size ) + { + fseek(fp, pos_5, SEEK_SET); + read_rel(elf, i_6, fp); + } + } + for ( i_7 = 0; count_2 > i_7; i_7 += 1 ) + { + elf->scp[i_7]->name = + strdup((elf->shstrptr != NULL) ? ((char *)&elf->shstrptr->data[elf->scp[i_7]->shr.sh_name]) : ""); + } + for ( i_8 = 0; i_8 < elf->ehp->e_phnum; i_8 += 1 ) + { + int d; + int s; + + switch ( elf->php[i_8].phdr.p_type ) + { + case PT_LOAD: + elf->php[i_8].scp = (elf_section **)calloc(count_2, sizeof(elf_section *)); + d = 0; + for ( s = 1; s < count_2; s += 1 ) + { + unsigned int p_filesz; + unsigned int p_offset; + + p_offset = elf->php[i_8].phdr.p_offset; + p_filesz = elf->php[i_8].phdr.p_filesz; + switch ( elf->scp[s]->shr.sh_type ) + { + case SHT_PROGBITS: + if ( + is_in_range(p_offset, p_filesz, elf->scp[s]->shr.sh_offset) + || (!elf->scp[s]->shr.sh_size && elf->scp[s]->shr.sh_offset == p_filesz + p_offset) ) + { + elf->php[i_8].scp[d] = elf->scp[s]; + d += 1; + } + break; + case SHT_NOBITS: + if ( + is_in_range(elf->php[i_8].phdr.p_vaddr, elf->php[i_8].phdr.p_memsz, elf->scp[s]->shr.sh_addr) + || (!elf->scp[s]->shr.sh_size && elf->scp[s]->shr.sh_offset == p_filesz + p_offset) ) + { + elf->php[i_8].scp[d] = elf->scp[s]; + d += 1; + } + break; + default: + break; + } + } + break; + case PT_MIPS_REGINFO: + elf->php[i_8].scp = (elf_section **)calloc(2, sizeof(elf_section *)); + *elf->php[i_8].scp = search_section(elf, SHT_MIPS_REGINFO); + break; + case PT_SCE_IOPMOD: + elf->php[i_8].scp = (elf_section **)calloc(2, sizeof(elf_section *)); + *elf->php[i_8].scp = search_section(elf, SHT_SCE_IOPMOD); + break; + case PT_SCE_EEMOD: + elf->php[i_8].scp = (elf_section **)calloc(2, sizeof(elf_section *)); + *elf->php[i_8].scp = search_section(elf, SHT_SCE_EEMOD); + break; + default: + break; + } + } + // Workaround for malformed file: make distance between sh_addr agree with sh_offset + switch ( elf->ehp->e_type ) + { + case ET_SCE_IOPRELEXEC: + case ET_SCE_IOPRELEXEC2: + case ET_SCE_EERELEXEC: + case ET_SCE_EERELEXEC2: + for ( i_8 = 0; i_8 < elf->ehp->e_phnum; i_8 += 1 ) + { + int s; + elf_section **scp; + + switch ( elf->php[i_8].phdr.p_type ) + { + case PT_LOAD: + scp = elf->php[i_8].scp; + for ( s = 1; scp[s]; s += 1 ) + { + if ( scp[s]->shr.sh_type != SHT_NOBITS ) + { + unsigned int addrdiff; + unsigned int offsetdiff; + + addrdiff = scp[s]->shr.sh_addr - scp[s - 1]->shr.sh_addr; + offsetdiff = scp[s]->shr.sh_offset - scp[s - 1]->shr.sh_offset; + if ( addrdiff != offsetdiff ) + { + scp[s]->shr.sh_addr = scp[s - 1]->shr.sh_addr + offsetdiff; + } + } + } + break; + default: + break; + } + } + break; + default: + break; + } + return elf; + } + pos_3 = elf->scp[i_4]->shr.sh_offset; + size = elf->scp[i_4]->shr.sh_size; + if ( pos_3 != 0 && size != 0 ) + { + fseek(fp, pos_3, SEEK_SET); + switch ( elf->scp[i_4]->shr.sh_type ) + { + case SHT_PROGBITS: + case SHT_RELA: + case SHT_HASH: + case SHT_DYNAMIC: + case SHT_MIPS_REGINFO: + elf->scp[i_4]->data = (uint8_t *)malloc(size); + if ( fread(elf->scp[i_4]->data, size, 1, fp) != 1 ) + { + fprintf(stderr, "%s: Could not read ELF section contents\n", filename); + exit(1); + } + swapmemory(elf->scp[i_4]->data, "l", size >> 2); + break; + case SHT_SYMTAB: + case SHT_NOBITS: + case SHT_DYNSYM: + break; + case SHT_MIPS_DEBUG: + elf->scp[i_4]->data = (uint8_t *)read_mips_symbolic(fp); + break; + case SHT_SCE_IOPMOD: + elf->scp[i_4]->data = (uint8_t *)malloc(size); + if ( fread(elf->scp[i_4]->data, size, 1, fp) != 1 ) + { + fprintf(stderr, "%s: Could not read ELF section contents\n", filename); + exit(1); + } + swapmemory(elf->scp[i_4]->data, "lllllls", 1); + break; + case SHT_SCE_EEMOD: + elf->scp[i_4]->data = (uint8_t *)malloc(size); + if ( fread(elf->scp[i_4]->data, size, 1, fp) != 1 ) + { + fprintf(stderr, "%s: Could not read ELF section contents\n", filename); + exit(1); + } + swapmemory(elf->scp[i_4]->data, "lllllllllls", 1); + break; + default: + elf->scp[i_4]->data = (uint8_t *)malloc(size); + if ( fread(elf->scp[i_4]->data, size, 1, fp) != 1 ) + { + fprintf(stderr, "%s: Could not read ELF section contents\n", filename); + exit(1); + } + break; + } + } + } + } + fclose(fp); + return elf; +} + +static int is_in_range(unsigned int top, unsigned int size, unsigned int pos) +{ + if ( pos >= top && pos < size + top ) + { + return 1; + } + return 0; +} + +static void read_symtab(elf_file *elf, int sctindex, FILE *fp) +{ + elf_syment **result; + elf_section *sp_x; + unsigned int entrise; + unsigned int i; + + sp_x = elf->scp[sctindex]; + entrise = sp_x->shr.sh_size / sp_x->shr.sh_entsize; + result = (elf_syment **)calloc(entrise, sizeof(elf_syment *)); + sp_x->data = (uint8_t *)result; + for ( i = 0; entrise > i; i += 1 ) + { + result[i] = (elf_syment *)calloc(1, sizeof(elf_syment)); + if ( fread(result[i], sp_x->shr.sh_entsize, 1, fp) != 1 ) + { + fprintf(stderr, "elflib: Could not read ELF symbol table\n"); + exit(1); + } + swapmemory(result[i], "lllccs", 1); + result[i]->bind = result[i]->sym.st_info >> 4; + result[i]->type = result[i]->sym.st_info & 0xF; + result[i]->name = 0; + if ( result[i]->sym.st_name ) + { + result[i]->name = strdup((char *)&sp_x->link->data[result[i]->sym.st_name]); + } + if ( result[i]->sym.st_shndx && result[i]->sym.st_shndx <= 0xFEFF ) + { + result[i]->shptr = elf->scp[result[i]->sym.st_shndx]; + } + else + { + result[i]->shptr = 0; + } + } +} + +static void read_rel(elf_file *elf, int sctindex, FILE *fp) +{ + elf_syment **symp; + elf_rel *result; + elf_section *sp_x; + unsigned int entrise; + unsigned int i; + + sp_x = elf->scp[sctindex]; + entrise = sp_x->shr.sh_size / sp_x->shr.sh_entsize; + result = (elf_rel *)calloc(entrise, sizeof(elf_rel)); + sp_x->data = (uint8_t *)result; + symp = (elf_syment **)sp_x->link->data; + for ( i = 0; entrise > i; i += 1 ) + { + if ( fread(&result[i], sp_x->shr.sh_entsize, 1, fp) != 1 ) + { + fprintf(stderr, "elflib: Could not read ELF relocations\n"); + exit(1); + } + swapmemory(&result[i], "ll", 1); + result[i].type = result[i].rel.r_info & 0xFF; + // Workaround for malformed file: Handle case of missing .symtab/.strtab section + if ( symp ) + { + result[i].symptr = symp[result[i].rel.r_info >> 8]; + result[i].symptr->refcount += 1; + } + } +} + +static elf_mips_symbolic_data *read_mips_symbolic(FILE *fp) +{ + elf_mips_symbolic_data *sycb; + + sycb = (elf_mips_symbolic_data *)malloc(sizeof(elf_mips_symbolic_data)); + if ( fread(sycb, sizeof(hdrr), 1, fp) != 1 ) + { + fprintf(stderr, "elflib: Could not read ELF debug info contents\n"); + exit(1); + } + swapmemory(sycb, "sslllllllllllllllllllllll", 1); + if ( sycb->head.cbLineOffset > 0 ) + { + size_t size_1; + + size_1 = sycb->head.cbLine; + sycb->cbLine_Ptr = (char *)malloc(size_1); + fseek(fp, sycb->head.cbLineOffset, SEEK_SET); + if ( fread(sycb->cbLine_Ptr, size_1, 1, fp) != 1 ) + { + fprintf(stderr, "elflib: Could not read ELF debug info contents\n"); + exit(1); + } + } + if ( sycb->head.cbDnOffset > 0 ) + { + size_t size_2; + + size_2 = 8L * sycb->head.idnMax; + sycb->cbDn_Ptr = (char *)malloc(size_2); + fseek(fp, sycb->head.cbDnOffset, SEEK_SET); + if ( fread(sycb->cbDn_Ptr, size_2, 1, fp) != 1 ) + { + fprintf(stderr, "elflib: Could not read ELF debug info contents\n"); + exit(1); + } + swapmemory(sycb->cbDn_Ptr, "ll", sycb->head.idnMax); + } + if ( sycb->head.cbPdOffset > 0 ) + { + size_t size_3; + + size_3 = 52L * sycb->head.ipdMax; + sycb->cbPd_Ptr = (char *)malloc(size_3); + fseek(fp, sycb->head.cbPdOffset, SEEK_SET); + if ( fread(sycb->cbPd_Ptr, size_3, 1, fp) != 1 ) + { + fprintf(stderr, "elflib: Could not read ELF debug info contents\n"); + exit(1); + } + swapmemory(sycb->cbPd_Ptr, "lllllllllsslll", sycb->head.ipdMax); + } + if ( sycb->head.cbSymOffset > 0 ) + { + size_t size_4; + + size_4 = 12L * sycb->head.isymMax; + sycb->cbSym_Ptr = (char *)malloc(size_4); + fseek(fp, sycb->head.cbSymOffset, SEEK_SET); + if ( fread(sycb->cbSym_Ptr, size_4, 1, fp) != 1 ) + { + fprintf(stderr, "elflib: Could not read ELF debug info contents\n"); + exit(1); + } + swapmemory(sycb->cbSym_Ptr, "lll", sycb->head.isymMax); + } + if ( sycb->head.cbOptOffset > 0 ) + { + size_t size_5; + + size_5 = 12L * sycb->head.ioptMax; + sycb->cbOpt_Ptr = (char *)malloc(size_5); + fseek(fp, sycb->head.cbOptOffset, SEEK_SET); + if ( fread(sycb->cbOpt_Ptr, size_5, 1, fp) != 1 ) + { + fprintf(stderr, "elflib: Could not read ELF debug info contents\n"); + exit(1); + } + swapmemory(sycb->cbOpt_Ptr, "lll", sycb->head.ioptMax); + } + if ( sycb->head.cbAuxOffset > 0 ) + { + size_t size_6; + + size_6 = 4L * sycb->head.iauxMax; + sycb->cbAux_Ptr = (char *)malloc(size_6); + fseek(fp, sycb->head.cbAuxOffset, SEEK_SET); + if ( fread(sycb->cbAux_Ptr, size_6, 1, fp) != 1 ) + { + fprintf(stderr, "elflib: Could not read ELF debug info contents\n"); + exit(1); + } + swapmemory(sycb->cbAux_Ptr, "l", sycb->head.iauxMax); + } + if ( sycb->head.cbSsOffset > 0 ) + { + size_t size_7; + + size_7 = sycb->head.issMax; + sycb->cbSs_Ptr = (char *)malloc(size_7); + fseek(fp, sycb->head.cbSsOffset, SEEK_SET); + if ( fread(sycb->cbSs_Ptr, size_7, 1, fp) != 1 ) + { + fprintf(stderr, "elflib: Could not read ELF debug info contents\n"); + exit(1); + } + } + if ( sycb->head.cbSsExtOffset > 0 ) + { + size_t size_8; + + size_8 = sycb->head.issExtMax; + sycb->cbSsExt_Ptr = (char *)malloc(size_8); + fseek(fp, sycb->head.cbSsExtOffset, SEEK_SET); + if ( fread(sycb->cbSsExt_Ptr, size_8, 1, fp) != 1 ) + { + fprintf(stderr, "elflib: Could not read ELF debug info contents\n"); + exit(1); + } + } + if ( sycb->head.cbFdOffset > 0 ) + { + size_t size_9; + + size_9 = 72L * sycb->head.ifdMax; + sycb->cbFd_Ptr = (char *)malloc(size_9); + fseek(fp, sycb->head.cbFdOffset, SEEK_SET); + if ( fread(sycb->cbFd_Ptr, size_9, 1, fp) != 1 ) + { + fprintf(stderr, "elflib: Could not read ELF debug info contents\n"); + exit(1); + } + swapmemory(sycb->cbFd_Ptr, "llllllllllsslllllll", sycb->head.ifdMax); + } + if ( sycb->head.cbRfdOffset > 0 ) + { + size_t size_A; + + size_A = 4L * sycb->head.crfd; + sycb->cbRfd_Ptr = (char *)malloc(size_A); + fseek(fp, sycb->head.cbRfdOffset, SEEK_SET); + if ( fread(sycb->cbRfd_Ptr, size_A, 1, fp) != 1 ) + { + fprintf(stderr, "elflib: Could not read ELF debug info contents\n"); + exit(1); + } + swapmemory(sycb->cbRfd_Ptr, "l", sycb->head.crfd); + } + if ( sycb->head.cbExtOffset > 0 ) + { + size_t size_B; + + size_B = 16L * sycb->head.iextMax; + sycb->cbExt_Ptr = (char *)malloc(size_B); + fseek(fp, sycb->head.cbExtOffset, SEEK_SET); + if ( fread(sycb->cbExt_Ptr, size_B, 1, fp) != 1 ) + { + fprintf(stderr, "elflib: Could not read ELF debug info contents\n"); + exit(1); + } + swapmemory(sycb->cbExt_Ptr, "sslll", sycb->head.iextMax); + } + return sycb; +} + +int layout_elf_file(elf_file *elf) +{ + Elf_file_slot *order; + + reorder_symtab(elf); + rebuild_section_name_strings(elf); + rebuild_symbol_name_strings(elf); + order = build_file_order_list(elf); + shrink_file_order_list(order); + writeback_file_order_list(elf, order); + free(order); + return 0; +} + +int write_elf(elf_file *elf, const char *filename) +{ + FILE *fp; + + fp = fopen(filename, "wbe"); + if ( !fp ) + { + perror(filename); + return 1; + } + renumber_symtab(elf); + if ( elf->ehp->e_shnum && elf->ehp->e_shentsize ) + { + int i_1; + int i_2; + + for ( i_1 = 0; i_1 < elf->ehp->e_shnum; i_1 += 1 ) + { + elf->scp[i_1]->number = i_1; + } + for ( i_2 = 0; i_2 < elf->ehp->e_shnum; i_2 += 1 ) + { + switch ( elf->scp[i_2]->shr.sh_type ) + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" + case SHT_RELA: + case SHT_REL: + elf->scp[i_2]->shr.sh_info = elf->scp[i_2]->info->number; + case SHT_SYMTAB: + case SHT_HASH: + case SHT_DYNAMIC: + case SHT_DYNSYM: + elf->scp[i_2]->shr.sh_link = elf->scp[i_2]->link->number; + break; +#pragma GCC diagnostic pop + default: + break; + } + if ( elf->scp[i_2] == elf->shstrptr ) + { + elf->ehp->e_shstrndx = elf->scp[i_2]->number; + } + } + } + swapmemory(elf->ehp, "ccccccccccccccccsslllllssssss", 1); + fwrite(elf->ehp, sizeof(Elf32_Ehdr), 1, fp); + swapmemory(elf->ehp, "ccccccccccccccccsslllllssssss", 1); + if ( elf->ehp->e_phnum && elf->ehp->e_phentsize ) + { + int count_1; + int i_3; + + count_1 = elf->ehp->e_phnum; + fseek(fp, elf->ehp->e_phoff, SEEK_SET); + for ( i_3 = 0; count_1 > i_3; i_3 += 1 ) + { + swapmemory(&elf->php[i_3], "llllllll", 1); + fwrite(&elf->php[i_3], sizeof(Elf32_Phdr), 1, fp); + swapmemory(&elf->php[i_3], "llllllll", 1); + } + } + if ( elf->ehp->e_shnum && elf->ehp->e_shentsize ) + { + int count_2; + int i_4; + int i_5; + + count_2 = elf->ehp->e_shnum; + fseek(fp, elf->ehp->e_shoff, SEEK_SET); + for ( i_4 = 0; count_2 > i_4; i_4 += 1 ) + { + swapmemory(elf->scp[i_4], "llllllllll", 1); + fwrite(elf->scp[i_4], sizeof(Elf32_Shdr), 1, fp); + swapmemory(elf->scp[i_4], "llllllllll", 1); + } + for ( i_5 = 0; count_2 > i_5; i_5 += 1 ) + { + unsigned int size; + unsigned int pos; + + pos = elf->scp[i_5]->shr.sh_offset; + size = elf->scp[i_5]->shr.sh_size; + if ( pos != 0 && size != 0 ) + { + fseek(fp, pos, SEEK_SET); + switch ( elf->scp[i_5]->shr.sh_type ) + { + case SHT_PROGBITS: + case SHT_RELA: + case SHT_HASH: + case SHT_DYNAMIC: + case SHT_MIPS_REGINFO: + swapmemory(elf->scp[i_5]->data, "l", size >> 2); + fwrite(elf->scp[i_5]->data, size, 1, fp); + swapmemory(elf->scp[i_5]->data, "l", size >> 2); + break; + case SHT_SYMTAB: + case SHT_DYNSYM: + write_symtab(elf, i_5, fp); + break; + case SHT_NOBITS: + break; + case SHT_REL: + write_rel(elf, i_5, fp); + break; + case SHT_MIPS_DEBUG: + write_mips_symbolic((elf_mips_symbolic_data *)elf->scp[i_5]->data, pos, fp); + break; + case SHT_SCE_IOPMOD: + swapmemory(elf->scp[i_5]->data, "lllllls", 1); + fwrite(elf->scp[i_5]->data, size, 1, fp); + swapmemory(elf->scp[i_5]->data, "lllllls", 1); + break; + case SHT_SCE_EEMOD: + swapmemory(elf->scp[i_5]->data, "lllllllllls", 1); + fwrite(elf->scp[i_5]->data, size, 1, fp); + swapmemory(elf->scp[i_5]->data, "lllllllllls", 1); + break; + default: + fwrite(elf->scp[i_5]->data, size, 1, fp); + break; + } + } + } + } + fclose(fp); + return 0; +} + +static void renumber_a_symtab(elf_section *scp) +{ + elf_syment **syp; + unsigned int entrise; + unsigned int i; + + entrise = scp->shr.sh_size / scp->shr.sh_entsize; + syp = (elf_syment **)scp->data; + for ( i = 0; entrise > i; i += 1 ) + { + syp[i]->number = i; + } +} + +static void renumber_symtab(elf_file *elf) +{ + int sc; + + for ( sc = 1; sc < elf->ehp->e_shnum; sc += 1 ) + { + switch ( elf->scp[sc]->shr.sh_type ) + { + case SHT_SYMTAB: + case SHT_DYNSYM: + renumber_a_symtab(elf->scp[sc]); + break; + default: + break; + } + } +} + +static void write_symtab(elf_file *elf, int sctindex, FILE *fp) +{ + Elf32_Sym sym; + elf_syment **syp; + elf_section *sp_x; + unsigned int entrise; + unsigned int i; + + sp_x = elf->scp[sctindex]; + entrise = sp_x->shr.sh_size / sp_x->shr.sh_entsize; + syp = (elf_syment **)sp_x->data; + fseek(fp, sp_x->shr.sh_offset, SEEK_SET); + for ( i = 0; entrise > i; i += 1 ) + { + memcpy(&sym, syp[i], sizeof(sym)); + if ( syp[i]->shptr ) + { + sym.st_shndx = syp[i]->shptr->number; + } + swapmemory(&sym, "lllccs", 1); + fwrite(&sym, sizeof(Elf32_Sym), 1, fp); + } +} + +static void write_rel(elf_file *elf, int sctindex, FILE *fp) +{ + Elf32_Rel rel; + elf_rel *rp; + elf_section *sp_x; + unsigned int entrise; + unsigned int i; + + sp_x = elf->scp[sctindex]; + entrise = sp_x->shr.sh_size / sp_x->shr.sh_entsize; + rp = (elf_rel *)sp_x->data; + fseek(fp, sp_x->shr.sh_offset, SEEK_SET); + for ( i = 0; entrise > i; i += 1 ) + { + memcpy(&rel, &rp[i], sizeof(rel)); + if ( rp[i].symptr && rp[i].symptr->number == (unsigned int)(-1) ) + { + fprintf(stderr, "Internal error !!\n"); + fprintf(stderr, " relocation entry have no symbol\nabort\n"); + exit(1); + } + rel.r_info = ((rp[i].symptr ? rp[i].symptr->number : sp_x->info->number) << 8) + (rp[i].type & 0xFF); + swapmemory(&rel, "ll", 1); + fwrite(&rel, sizeof(Elf32_Rel), 1, fp); + } +} + +static void write_mips_symbolic(elf_mips_symbolic_data *sycb, unsigned int basepos, FILE *fp) +{ + unsigned int pos; + + pos = basepos + 96; + if ( sycb->head.cbLineOffset > 0 ) + { + size_t size_1; + + size_1 = sycb->head.cbLine; + sycb->head.cbLineOffset = pos; + pos += size_1; + fseek(fp, sycb->head.cbLineOffset, SEEK_SET); + fwrite(sycb->cbLine_Ptr, size_1, 1, fp); + } + if ( sycb->head.cbDnOffset > 0 ) + { + size_t size_2; + + size_2 = 8L * sycb->head.idnMax; + sycb->head.cbDnOffset = pos; + pos += size_2; + fseek(fp, sycb->head.cbDnOffset, SEEK_SET); + swapmemory(sycb->cbDn_Ptr, "ll", sycb->head.idnMax); + fwrite(sycb->cbDn_Ptr, size_2, 1, fp); + swapmemory(sycb->cbDn_Ptr, "ll", sycb->head.idnMax); + } + if ( sycb->head.cbPdOffset > 0 ) + { + size_t size_3; + + size_3 = 52L * sycb->head.ipdMax; + sycb->head.cbPdOffset = pos; + pos += size_3; + fseek(fp, sycb->head.cbPdOffset, SEEK_SET); + swapmemory(sycb->cbPd_Ptr, "lllllllllsslll", sycb->head.ipdMax); + fwrite(sycb->cbPd_Ptr, size_3, 1, fp); + swapmemory(sycb->cbPd_Ptr, "lllllllllsslll", sycb->head.ipdMax); + } + if ( sycb->head.cbSymOffset > 0 ) + { + size_t size_4; + + size_4 = 12L * sycb->head.isymMax; + sycb->head.cbSymOffset = pos; + pos += size_4; + fseek(fp, sycb->head.cbSymOffset, SEEK_SET); + swapmemory(sycb->cbSym_Ptr, "lll", sycb->head.isymMax); + fwrite(sycb->cbSym_Ptr, size_4, 1, fp); + swapmemory(sycb->cbSym_Ptr, "lll", sycb->head.isymMax); + } + if ( sycb->head.cbOptOffset > 0 ) + { + size_t size_5; + + size_5 = 12L * sycb->head.ioptMax; + pos += size_5; + fseek(fp, sycb->head.cbOptOffset, SEEK_SET); + swapmemory(sycb->cbOpt_Ptr, "lll", sycb->head.ioptMax); + fwrite(sycb->cbOpt_Ptr, size_5, 1, fp); + swapmemory(sycb->cbOpt_Ptr, "lll", sycb->head.ioptMax); + } + if ( sycb->head.cbAuxOffset > 0 ) + { + size_t size_6; + + size_6 = 4L * sycb->head.iauxMax; + sycb->head.cbAuxOffset = pos; + pos += size_6; + fseek(fp, sycb->head.cbAuxOffset, SEEK_SET); + swapmemory(sycb->cbAux_Ptr, "l", sycb->head.iauxMax); + fwrite(sycb->cbAux_Ptr, size_6, 1, fp); + swapmemory(sycb->cbAux_Ptr, "l", sycb->head.iauxMax); + } + if ( sycb->head.cbSsOffset > 0 ) + { + size_t size_7; + + size_7 = sycb->head.issMax; + sycb->head.cbSsOffset = pos; + pos += size_7; + fseek(fp, sycb->head.cbSsOffset, SEEK_SET); + fwrite(sycb->cbSs_Ptr, size_7, 1, fp); + } + if ( sycb->head.cbSsExtOffset > 0 ) + { + size_t size_8; + + size_8 = sycb->head.issExtMax; + sycb->head.cbSsExtOffset = pos; + pos += size_8; + fseek(fp, sycb->head.cbSsExtOffset, SEEK_SET); + fwrite(sycb->cbSsExt_Ptr, size_8, 1, fp); + } + if ( sycb->head.cbFdOffset > 0 ) + { + size_t size_9; + + size_9 = 72L * sycb->head.ifdMax; + sycb->head.cbFdOffset = pos; + pos += size_9; + fseek(fp, sycb->head.cbFdOffset, SEEK_SET); + swapmemory(sycb->cbFd_Ptr, "llllllllllsslllllll", sycb->head.ifdMax); + fwrite(sycb->cbFd_Ptr, size_9, 1, fp); + swapmemory(sycb->cbFd_Ptr, "llllllllllsslllllll", sycb->head.ifdMax); + } + if ( sycb->head.cbRfdOffset > 0 ) + { + size_t size_A; + + size_A = 4L * sycb->head.crfd; + sycb->head.cbRfdOffset = pos; + pos += size_A; + fseek(fp, sycb->head.cbRfdOffset, SEEK_SET); + swapmemory(sycb->cbRfd_Ptr, "l", sycb->head.crfd); + fwrite(sycb->cbRfd_Ptr, size_A, 1, fp); + swapmemory(sycb->cbRfd_Ptr, "l", sycb->head.crfd); + } + if ( sycb->head.cbExtOffset > 0 ) + { + size_t size_B; + + size_B = 16L * sycb->head.iextMax; + sycb->head.cbExtOffset = pos; + fseek(fp, sycb->head.cbExtOffset, SEEK_SET); + swapmemory(sycb->cbExt_Ptr, "sslll", sycb->head.iextMax); + fwrite(sycb->cbExt_Ptr, size_B, 1, fp); + swapmemory(sycb->cbExt_Ptr, "sslll", sycb->head.iextMax); + } + fseek(fp, basepos, SEEK_SET); + swapmemory(sycb, "sslllllllllllllllllllllll", 1); + fwrite(sycb, sizeof(hdrr), 1, fp); + swapmemory(sycb, "sslllllllllllllllllllllll", 1); +} + +void add_section(elf_file *elf, elf_section *scp) +{ + Elf32_Ehdr *ehp; + int count; + + ehp = elf->ehp; + ehp->e_shnum += 1; + count = ehp->e_shnum; + elf->scp = (elf_section **)realloc(elf->scp, (count + 1) * sizeof(elf_section *)); + elf->scp[count - 1] = scp; + elf->scp[count] = 0; + add_symbol(elf, 0, 0, 3, 0, scp, 0); +} + +elf_section *remove_section(elf_file *elf, Elf32_Word shtype) +{ + elf_section *rmsec; + int s; + + rmsec = 0; + for ( s = 1; s < elf->ehp->e_shnum; s += 1 ) + { + if ( shtype == elf->scp[s]->shr.sh_type ) + { + elf->ehp->e_shnum -= 1; + rmsec = elf->scp[s]; + break; + } + } + for ( ; s < elf->ehp->e_shnum; s += 1 ) + { + elf->scp[s] = elf->scp[s + 1]; + } + return rmsec; +} + +elf_section *remove_section_by_name(elf_file *elf, const char *secname) +{ + elf_section *rmsec; + int s; + + rmsec = 0; + for ( s = 1; s < elf->ehp->e_shnum; s += 1 ) + { + if ( !strcmp(elf->scp[s]->name, secname) ) + { + elf->ehp->e_shnum -= 1; + rmsec = elf->scp[s]; + break; + } + } + for ( ; s < elf->ehp->e_shnum; s += 1 ) + { + elf->scp[s] = elf->scp[s + 1]; + } + return rmsec; +} + +elf_section *search_section(elf_file *elf, Elf32_Word stype) +{ + int i; + + for ( i = 1; i < elf->ehp->e_shnum; i += 1 ) + { + if ( stype == elf->scp[i]->shr.sh_type ) + { + return elf->scp[i]; + } + } + return 0; +} + +elf_section *search_section_by_name(elf_file *elf, const char *secname) +{ + int i; + + for ( i = 1; i < elf->ehp->e_shnum; i += 1 ) + { + if ( !strcmp(elf->scp[i]->name, secname) ) + { + return elf->scp[i]; + } + } + return 0; +} + +unsigned int *get_section_data(elf_file *elf, unsigned int addr) +{ + int i; + + for ( i = 1; i < elf->ehp->e_shnum; i += 1 ) + { + if ( + elf->scp[i]->shr.sh_type == SHT_PROGBITS && addr >= elf->scp[i]->shr.sh_addr + && addr < elf->scp[i]->shr.sh_size + elf->scp[i]->shr.sh_addr ) + { + return (unsigned int *)&elf->scp[i]->data[addr - elf->scp[i]->shr.sh_addr]; + } + } + return 0; +} + +elf_syment *search_global_symbol(const char *name, elf_file *elf) +{ + unsigned int entrise; + unsigned int i; + elf_syment **syp; + elf_section *scp; + + scp = search_section(elf, SHT_SYMTAB); + if ( !scp ) + { + return 0; + } + entrise = scp->shr.sh_size / scp->shr.sh_entsize; + syp = (elf_syment **)scp->data; + for ( i = 1; entrise > i; i += 1 ) + { + if ( syp[i]->name && syp[i]->bind == STB_GLOBAL && !strcmp(syp[i]->name, name) ) + { + return syp[i]; + } + } + return 0; +} + +int is_defined_symbol(const elf_syment *sym) +{ + if ( !sym ) + { + return 0; + } + if ( !sym->sym.st_shndx ) + { + return 0; + } + if ( sym->sym.st_shndx <= 0xFEFF ) + { + return 1; + } + return sym->sym.st_shndx == SHN_ABS; +} + +elf_syment *add_symbol(elf_file *elf, const char *name, int bind, int type, int value, elf_section *scp, int st_shndx) +{ + unsigned int entrise; + elf_syment *sym; + elf_syment **newtab; + elf_section *symtbl; + + symtbl = search_section(elf, SHT_SYMTAB); + if ( !symtbl ) + { + return 0; + } + entrise = symtbl->shr.sh_size / symtbl->shr.sh_entsize; + newtab = (elf_syment **)realloc(symtbl->data, (entrise + 1) * sizeof(elf_syment *)); + sym = (elf_syment *)calloc(1, sizeof(elf_syment)); + newtab[entrise] = sym; + symtbl->shr.sh_size += symtbl->shr.sh_entsize; + symtbl->data = (uint8_t *)newtab; + if ( name ) + { + sym->name = strdup(name); + } + sym->bind = bind; + sym->type = type; + sym->sym.st_info = (type & 0xF) + 16 * bind; + sym->sym.st_value = value; + sym->shptr = scp; + if ( scp ) + { + sym->sym.st_shndx = 1; + } + else + { + sym->sym.st_shndx = st_shndx; + } + return sym; +} + +unsigned int get_symbol_value(const elf_syment *sym, const elf_file *elf) +{ + if ( !is_defined_symbol(sym) ) + { + return 0; + } + if ( sym->sym.st_shndx != SHN_ABS && elf->ehp->e_type == ET_REL ) + { + return sym->shptr->shr.sh_addr + sym->sym.st_value; + } + return sym->sym.st_value; +} + +static void reorder_an_symtab(elf_file *elf, elf_section *scp) +{ + int sections; + elf_syment **oldtab; + elf_syment **newtab; + unsigned int entrise; + int sc; + unsigned int d; + unsigned int i; + unsigned int j; + unsigned int k; + unsigned int m; + + sections = elf->ehp->e_shnum; + entrise = scp->shr.sh_size / scp->shr.sh_entsize; + oldtab = (elf_syment **)malloc(entrise * sizeof(elf_syment *)); + memcpy(oldtab, (elf_syment **)scp->data, entrise * sizeof(elf_syment *)); + newtab = (elf_syment **)calloc(entrise, sizeof(elf_syment *)); + scp->data = (uint8_t *)newtab; + *newtab = *oldtab; + d = 1; + for ( sc = 1; sections > sc; sc += 1 ) + { + for ( i = 1; entrise > i; i += 1 ) + { + if ( + oldtab[i] && oldtab[i]->type == STT_SECTION && !oldtab[i]->name && oldtab[i]->shptr + && !strcmp(oldtab[i]->shptr->name, elf->scp[sc]->name) ) + { + newtab[d] = oldtab[i]; + d += 1; + oldtab[i] = 0; + break; + } + } + } + for ( j = 1; entrise > j; j += 1 ) + { + if ( oldtab[j] && oldtab[j]->type == STT_SECTION && !oldtab[j]->name ) + { + oldtab[j] = 0; + } + } + for ( k = 1; entrise > k; k += 1 ) + { + if ( oldtab[k] && !oldtab[k]->bind ) + { + newtab[d] = oldtab[k]; + d += 1; + oldtab[k] = 0; + } + } + scp->shr.sh_info = d; + for ( m = 1; entrise > m; m += 1 ) + { + if ( oldtab[m] ) + { + newtab[d] = oldtab[m]; + d += 1; + oldtab[m] = 0; + } + } + scp->shr.sh_size = scp->shr.sh_entsize * d; + free(oldtab); +} + +void reorder_symtab(elf_file *elf) +{ + int s; + + for ( s = 1; s < elf->ehp->e_shnum; s += 1 ) + { + switch ( elf->scp[s]->shr.sh_type ) + { + case SHT_SYMTAB: + case SHT_DYNSYM: + reorder_an_symtab(elf, elf->scp[s]); + break; + default: + break; + } + } +} + +unsigned int adjust_align(unsigned int value, unsigned int align) +{ + return ~(align - 1) & (align + value - 1); +} + +void rebuild_section_name_strings(elf_file *elf) +{ + unsigned int offset; + size_t namesize; + int i_1; + int i_2; + + namesize = 1; + if ( elf->scp == NULL ) + { + return; + } + for ( i_1 = 1; i_1 < elf->ehp->e_shnum; i_1 += 1 ) + { + namesize += strlen(elf->scp[i_1]->name) + 1; + } + if ( elf->shstrptr->data ) + { + free(elf->shstrptr->data); + } + elf->shstrptr->data = (uint8_t *)calloc(1, namesize); + elf->shstrptr->shr.sh_size = namesize; + offset = 1; + for ( i_2 = 1; i_2 < elf->ehp->e_shnum; i_2 += 1 ) + { + strcpy((char *)&elf->shstrptr->data[offset], elf->scp[i_2]->name); + elf->scp[i_2]->shr.sh_name = offset; + offset += strlen(elf->scp[i_2]->name) + 1; + } +} + +static size_t search_string_table(const char *tbltop, size_t endindex, const char *str) +{ + size_t idx; + + for ( idx = 1; idx < endindex; idx += strlen(&tbltop[idx]) + 1 ) + { + if ( !strcmp(str, &tbltop[idx]) ) + { + return idx; + } + } + return 0; +} + +static void rebuild_a_symbol_name_strings(elf_section *scp) +{ + elf_section *strtab; + elf_syment **syp; + size_t offset; + size_t namesize; + unsigned int entrise; + unsigned int i_1; + unsigned int i_2; + + entrise = scp->shr.sh_size / scp->shr.sh_entsize; + strtab = scp->link; + syp = (elf_syment **)scp->data; + namesize = 1; + for ( i_1 = 1; i_1 < entrise; i_1 += 1 ) + { + namesize = (syp[i_1] != NULL && syp[i_1]->name != NULL) ? (strlen(syp[i_1]->name) + namesize + 1) : namesize; + } + if ( strtab->data ) + { + free(strtab->data); + } + strtab->data = (uint8_t *)calloc(1, namesize); + offset = 1; + for ( i_2 = 1; i_2 < entrise; i_2 += 1 ) + { + if ( syp[i_2] != NULL && syp[i_2]->name != NULL ) + { + syp[i_2]->sym.st_name = search_string_table((char *)strtab->data, offset, syp[i_2]->name); + if ( !syp[i_2]->sym.st_name ) + { + strcpy((char *)&strtab->data[offset], syp[i_2]->name); + syp[i_2]->sym.st_name = offset; + offset += strlen(syp[i_2]->name) + 1; + } + } + } + strtab->shr.sh_size = offset; +} + +void rebuild_symbol_name_strings(elf_file *elf) +{ + int sc; + + if ( elf->scp == NULL ) + { + return; + } + for ( sc = 1; sc < elf->ehp->e_shnum; sc += 1 ) + { + switch ( elf->scp[sc]->shr.sh_type ) + { + case SHT_SYMTAB: + case SHT_DYNSYM: + rebuild_a_symbol_name_strings(elf->scp[sc]); + break; + default: + break; + } + } +} + +static int comp_Elf_file_slot(const void *a1, const void *a2) +{ + const Elf_file_slot *p1; + const Elf_file_slot *p2; + + p1 = a1; + p2 = a2; + + if ( p1->type == EFS_TYPE_ELF_HEADER && p2->type == EFS_TYPE_ELF_HEADER ) + { + return 0; + } + if ( p1->type == EFS_TYPE_ELF_HEADER ) + { + return -1; + } + if ( p2->type == EFS_TYPE_ELF_HEADER ) + { + return 1; + } + if ( p1->type == EFS_TYPE_PROGRAM_HEADER_TABLE && p2->type == EFS_TYPE_PROGRAM_HEADER_TABLE ) + { + return 0; + } + if ( p1->type == EFS_TYPE_PROGRAM_HEADER_TABLE ) + { + return -1; + } + if ( p2->type == EFS_TYPE_PROGRAM_HEADER_TABLE ) + { + return 1; + } + if ( !p1->type && !p2->type ) + { + return 0; + } + if ( !p1->type ) + { + return 1; + } + if ( !p2->type ) + { + return -1; + } + if ( p1->type == EFS_TYPE_END && p2->type == EFS_TYPE_END ) + { + return 0; + } + if ( p1->type == EFS_TYPE_END ) + { + return 1; + } + if ( p2->type == EFS_TYPE_END ) + { + return -1; + } + if ( p1->type == EFS_TYPE_PROGRAM_HEADER_ENTRY && p2->type == EFS_TYPE_SECTION_HEADER_TABLE ) + { + return -1; + } + if ( p1->type == EFS_TYPE_SECTION_HEADER_TABLE && p2->type == EFS_TYPE_PROGRAM_HEADER_ENTRY ) + { + return 1; + } + if ( p2->offset == p1->offset ) + { + return 0; + } + if ( p2->offset >= p1->offset ) + { + return -1; + } + return 1; +} + +Elf_file_slot *build_file_order_list(const elf_file *elf) +{ + int sections; + elf_section **scp; + Elf_file_slot *resolt; + int s_2; + int d_1; + size_t d_2; + int maxent; + + sections = elf->ehp->e_shnum; + scp = (elf_section **)calloc(sections + 1, sizeof(elf_section *)); + memcpy(scp, elf->scp, sections * sizeof(elf_section *)); + maxent = elf->ehp->e_shnum + 2; + if ( elf->ehp->e_phnum ) + { + maxent = elf->ehp->e_phnum + elf->ehp->e_shnum + 3; + } + resolt = (Elf_file_slot *)calloc(maxent, sizeof(Elf_file_slot)); + resolt->type = EFS_TYPE_ELF_HEADER; + resolt->offset = 0; + resolt->size = sizeof(Elf32_Ehdr); + resolt->align = 4; + d_1 = 1; + if ( elf->ehp->e_phnum ) + { + int seg; + + resolt[1].type = EFS_TYPE_PROGRAM_HEADER_TABLE; + resolt[1].offset = resolt->size; + resolt[1].size = sizeof(Elf32_Phdr) * elf->ehp->e_phnum; + resolt[1].align = 4; + for ( seg = 0, d_1 = 2; seg < elf->ehp->e_phnum; seg += 1, d_1 += 1 ) + { + elf_section **phdscp; + + resolt[d_1].type = EFS_TYPE_PROGRAM_HEADER_ENTRY; + resolt[d_1].d.php = &elf->php[seg]; + resolt[d_1].offset = elf->php[seg].phdr.p_offset; + resolt[d_1].size = elf->php[seg].phdr.p_filesz; + resolt[d_1].align = elf->php[seg].phdr.p_align; + for ( phdscp = elf->php[seg].scp; *phdscp; phdscp += 1 ) + { + int s_1; + + for ( s_1 = 0; s_1 < sections; s_1 += 1 ) + { + if ( *phdscp == scp[s_1] ) + { + scp[s_1] = 0; + break; + } + } + } + } + } + resolt[d_1].type = EFS_TYPE_SECTION_HEADER_TABLE; + resolt[d_1].offset = elf->ehp->e_shoff ?: (Elf32_Off)(-256); + resolt[d_1].size = sizeof(Elf32_Shdr) * elf->ehp->e_shnum; + resolt[d_1].align = 4; + d_2 = d_1 + 1; + for ( s_2 = 1; s_2 < sections; s_2 += 1 ) + { + if ( scp[s_2] ) + { + resolt[d_2].type = EFS_TYPE_SECTION_DATA; + resolt[d_2].d.scp = scp[s_2]; + resolt[d_2].offset = scp[s_2]->shr.sh_offset; + resolt[d_2].size = scp[s_2]->shr.sh_size; + resolt[d_2].align = scp[s_2]->shr.sh_addralign; + scp[s_2] = 0; + d_2 += 1; + } + } + resolt[d_2].type = EFS_TYPE_END; + free(scp); + qsort(resolt, d_2, sizeof(Elf_file_slot), comp_Elf_file_slot); + return resolt; +} + +void shrink_file_order_list(Elf_file_slot *efs) +{ + unsigned int slot; + + slot = 0; + for ( ; efs->type != EFS_TYPE_END; efs += 1 ) + { + unsigned int foffset; + + foffset = adjust_align(slot, efs->align); + efs->offset = foffset; + slot = efs->size + foffset; + } +} + +void writeback_file_order_list(elf_file *elf, Elf_file_slot *efs) +{ + elf_section **scp; + unsigned int segoffset; + int i; + + for ( ; efs->type != EFS_TYPE_END; efs += 1 ) + { + switch ( efs->type ) + { + case EFS_TYPE_PROGRAM_HEADER_TABLE: + elf->ehp->e_phoff = efs->offset; + break; + case EFS_TYPE_PROGRAM_HEADER_ENTRY: + efs->d.php->phdr.p_offset = efs->offset; + scp = efs->d.php->scp; + segoffset = efs->offset; + (*scp)->shr.sh_offset = efs->offset; + for ( i = 1; scp[i]; i += 1 ) + { + if ( scp[i]->shr.sh_type != SHT_NOBITS ) + { + segoffset = scp[i]->shr.sh_addr + efs->offset - (*scp)->shr.sh_addr; + } + scp[i]->shr.sh_offset = segoffset; + if ( scp[i]->shr.sh_type != SHT_NOBITS ) + { + segoffset += scp[i]->shr.sh_size; + } + } + break; + case EFS_TYPE_SECTION_HEADER_TABLE: + elf->ehp->e_shoff = efs->offset; + break; + case EFS_TYPE_SECTION_DATA: + efs->d.php->phdr.p_filesz = efs->offset; + break; + default: + break; + } + } +} + +void dump_file_order_list(const elf_file *elf, const Elf_file_slot *efs) +{ + unsigned int offset; + unsigned int size_tmp; + unsigned int offset_tmp; + char tmp[100]; + const char *name; + elf_section **scp; + const Elf_file_slot *slot; + int i; + + offset_tmp = efs->offset; + printf("\n"); + for ( slot = efs; slot->type != EFS_TYPE_END; slot += 1 ) + { + unsigned int oldend_1; + unsigned int size_1; + unsigned int startpos_1; + + oldend_1 = slot->size; + startpos_1 = slot->offset; + if ( oldend_1 == 0 ) + { + offset = slot->offset; + } + else + { + offset = oldend_1 + startpos_1 - 1; + } + size_1 = offset; + switch ( slot->type ) + { + case EFS_TYPE_ELF_HEADER: + name = "[Elf header]"; + break; + case EFS_TYPE_PROGRAM_HEADER_TABLE: + name = "[Proram Header Table]"; + break; + case EFS_TYPE_PROGRAM_HEADER_ENTRY: + sprintf(tmp, "[Proram Header entry %d]", (int)(0xCCCCCCCD * ((char *)slot->d.php - (char *)elf->php)) >> 3); + name = tmp; + break; + case EFS_TYPE_SECTION_HEADER_TABLE: + name = "[Section Header Table]"; + break; + case EFS_TYPE_SECTION_DATA: + sprintf(tmp, "%s data", slot->d.scp->name); + name = tmp; + break; + default: + name = "internal error Unknown EFS type !!!!"; + break; + } + if ( startpos_1 > offset_tmp + 1 ) + { + printf("%36s = %08x-%08x (%06x)\n", "**Blank**", offset_tmp + 1, startpos_1 - 1, startpos_1 - offset_tmp - 1); + } + offset_tmp = size_1; + printf("%36s = %08x-%08x (%06x)\n", name, startpos_1, size_1, oldend_1); + if ( slot->type == EFS_TYPE_PROGRAM_HEADER_ENTRY ) + { + scp = slot->d.php->scp; + (*scp)->shr.sh_offset = slot->offset; + size_tmp = slot->offset; + for ( i = 0; scp[i]; i += 1 ) + { + unsigned int oldend_2; + unsigned int size_2; + unsigned int startpos_2; + + if ( scp[i]->shr.sh_type == SHT_NOBITS ) + { + oldend_2 = 0; + } + else + { + oldend_2 = scp[i]->shr.sh_size; + } + startpos_2 = scp[i]->shr.sh_offset; + size_2 = (oldend_2 == 0) ? (scp[i]->shr.sh_offset) : (Elf32_Off)(oldend_2 + startpos_2 - 1); + sprintf(tmp, "(%s)", scp[i]->name); + name = tmp; + if ( startpos_2 > size_tmp + 1 ) + { + printf("%36s | %08x-%08x (%06x)\n", "**Blank**", size_tmp + 1, startpos_2 - 1, startpos_2 - size_tmp - 1); + } + size_tmp = size_2; + printf("%36s | %08x-%08x (%06x)\n", name, startpos_2, size_2, scp[i]->shr.sh_size); + } + } + } +} diff --git a/tools/srxfixup/src/iopfixconf.c b/tools/srxfixup/src/iopfixconf.c new file mode 100644 index 00000000000..114a105d1de --- /dev/null +++ b/tools/srxfixup/src/iopfixconf.c @@ -0,0 +1,82 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "srxfixup_internal.h" + +// clang-format off +const char *iop_defaultconf = + " @IOP\n" + " .reginfo { @remove }\n" + "\n" + " # Elf-header\n" + " # Program-header-table\n" + " .iopmod\n" + "\n" + " @Define {\n" + " @Segments_name { TEXT DATA BSS GLOBALDATA AFTER_SHT }\n" + " @Memory_segment { TEXT DATA BSS GLOBALDATA }\n" + " @Program_header_order { .iopmod { TEXT DATA BSS } }\n" + " @CreateSymbols {\n" + " ## name bind type segment shindex base\n" + " ## .section\n" + " { _ftext GLOBAL OBJECT TEXT 0 start }\n" + " { etext GLOBAL OBJECT TEXT SHN_RADDR end }\n" + " { _etext GLOBAL OBJECT TEXT SHN_RADDR end }\n" + " { _fdata GLOBAL OBJECT DATA 0 start }\n" + " { edata GLOBAL OBJECT DATA SHN_RADDR end }\n" + " { _edata GLOBAL OBJECT DATA SHN_RADDR end }\n" + " { _fbss GLOBAL OBJECT BSS SHN_RADDR start }\n" + " { end GLOBAL OBJECT BSS SHN_RADDR end }\n" + " { _end GLOBAL OBJECT BSS SHN_RADDR end }\n" + " { _gp GLOBAL OBJECT GLOBALDATA SHN_RADDR gpbase }\n" + " }\n" + " }\n" + "\n" + " # TEXT segment\n" + " .init { @segment {TEXT} } .rel.init { @segment {AFTER_SHT} }\n" + " .text { @segment {TEXT} @createinfo{PROGBITS ALLOC EXECINSTR}}\n" + " .rel.text{ @segment {AFTER_SHT} }\n" + " .fini { @segment {TEXT} } .rel.fini { @segment {AFTER_SHT} }\n" + "# .irx.lib { @segment {DATA} } .rel.irx.lib { @segment {AFTER_SHT} }\n" + "# .irx.stub{ @segment {DATA} } .rel.irx.stub { @segment {AFTER_SHT} }\n" + "\n" + " # DATA segment\n" + " .rodata { @segment {DATA} } .rel.rodata { @segment {AFTER_SHT} }\n" + " .rodata1 { @segment {DATA} } .rel.rodata1 { @segment {AFTER_SHT} }\n" + " .data { @segment {DATA} @createinfo {PROGBITS ALLOC WRITE} }\n" + " .rel.data{ @segment {AFTER_SHT} }\n" + " .data1 { @segment {DATA} } .rel.data1 { @segment {AFTER_SHT} }\n" + "\n" + " .ctors { @segment {DATA} } .rel.ctors { @segment {AFTER_SHT} }\n" + " .dtors { @segment {DATA} } .rel.dtors { @segment {AFTER_SHT} }\n" + " .eh_frame { @segment {DATA} } .rel.eh_frame { @segment {AFTER_SHT} }\n" + "\n" + " .sdata { @segment {DATA GLOBALDATA} } .rel.sdata {@segment{AFTER_SHT}}\n" + " .lit8 { @segment {DATA GLOBALDATA} }\n" + " .lit4 { @segment {DATA GLOBALDATA} }\n" + "\n" + " # BSS segment\n" + " .sbss { @segment { BSS GLOBALDATA } }\n" + " .bss { @segment { BSS } }\n" + "\n" + " @Program_header_data { 1 }\n" + "\n" + " .mdebug\n" + " .shstrtab\n" + "\n" + " @Section_header_table\n" + " @Segment_data { AFTER_SHT }\n" + "\n" + " .symtab\n" + " .strtab\n" + " * ##### other sections\n" + "\n" +; +// clang-format on diff --git a/tools/srxfixup/src/mipsdis.c b/tools/srxfixup/src/mipsdis.c new file mode 100644 index 00000000000..48be26046e6 --- /dev/null +++ b/tools/srxfixup/src/mipsdis.c @@ -0,0 +1,1648 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "srxfixup_internal.h" +#include +#include +#include +#include + +static void getrs(unsigned int data, Operand *opr); +static void getrt(unsigned int data, Operand *opr); +static void getrd(unsigned int data, Operand *opr); +static void getc0rd_iop(unsigned int data, Operand *opr); +static void getc0rd_ee(unsigned int data, Operand *opr); +static void getczrd(unsigned int data, Operand *opr); +static void getshamt(unsigned int data, Operand *opr); +static void getfs(unsigned int data, Operand *opr); +static void getft(unsigned int data, Operand *opr); +static void getfd(unsigned int data, Operand *opr); +static void getczfs(unsigned int data, Operand *opr); +static void getbroff(unsigned int addr, unsigned int data, Operand *opr); +static void Rs(Disasm_result *result); +static void Rd(Disasm_result *result); +static void Rdrs(Disasm_result *result); +static void Rsrt(Disasm_result *result); +static void Rtc0rd_iop(Disasm_result *result); +static void Rtc0rd_ee(Disasm_result *result); +static void Rtczrd(Disasm_result *result); +static void Rdrsrt(Disasm_result *result); +static void Rdrtrs(Disasm_result *result); +static void Rdrtshamt(Disasm_result *result); +static void Rsseimm(Disasm_result *result); +static void Rtrsseimm(Disasm_result *result); +static void Rtrsimm(Disasm_result *result); +#if 0 +static void Rdimm(Disasm_result *result); +static void Rsimm(Disasm_result *result); +#endif +static void Rtimm(Disasm_result *result); +static void Rsrtbroff(Disasm_result *result); +static void Rsbroff(Disasm_result *result); +static void Rtoffbase(Disasm_result *result); +static void Fdfs(Disasm_result *result); +static void Fsft(Disasm_result *result); +static void Fdfsft(Disasm_result *result); +static void Rtczfs(Disasm_result *result); +static void Code20(Disasm_result *result); +static void Jtarget(Disasm_result *result); +static void Cofun(Disasm_result *result); +static void Bcft(Disasm_result *result); + +// clang-format off +static int regnmsw[5] = { 1, 1, 0, 1, 0 }; +static const char * const REGNAME[2][32] = +{ + { + "$0", + "$at", + "$2", + "$3", + "$4", + "$5", + "$6", + "$7", + "$8", + "$9", + "$10", + "$11", + "$12", + "$13", + "$14", + "$15", + "$16", + "$17", + "$18", + "$19", + "$20", + "$21", + "$22", + "$23", + "$24", + "$25", + "$26", + "$27", + "$gp", + "$sp", + "$30", + "$31" + }, + { + "zero", + "at", + "v0", + "v1", + "a0", + "a1", + "a2", + "a3", + "t0", + "t1", + "t2", + "t3", + "t4", + "t5", + "t6", + "t7", + "s0", + "s1", + "s2", + "s3", + "s4", + "s5", + "s6", + "s7", + "t8", + "t9", + "k0", + "k1", + "gp", + "sp", + "fp", + "ra" + } +}; +static const char * const REGC0_iop[2][32] = +{ + { + "$0", + "$1", + "$2", + "$3", + "$4", + "$5", + "$6", + "$7", + "$8", + "$9", + "$10", + "$11", + "$12", + "$13", + "$14", + "$15", + "$16", + "$17", + "$18", + "$19", + "$20", + "$21", + "$22", + "$23", + "$24", + "$25", + "$26", + "$27", + "$28", + "$29", + "$30", + "$31" + }, + { + "$0", + "$1", + "$2", + "$bpc", + "$4", + "$bda", + "$tar", + "$dcic", + "$bada", + "$bdam", + "$10", + "$bpcm", + "$sr", + "$cause", + "$epc", + "$prid", + "$16", + "$17", + "$18", + "$19", + "$20", + "$21", + "$22", + "$23", + "$24", + "$25", + "$26", + "$27", + "$28", + "$29", + "$30", + "$31" + } +}; +static const char * const REGC0_ee[2][32] = +{ + { + "$0", + "$1", + "$2", + "$3", + "$4", + "$5", + "$6", + "$7", + "$8", + "$9", + "$10", + "$11", + "$12", + "$13", + "$14", + "$15", + "$16", + "$17", + "$18", + "$19", + "$20", + "$21", + "$22", + "$23", + "$24", + "$25", + "$26", + "$27", + "$28", + "$29", + "$30", + "$31" + }, + { + "$index", + "$random", + "$entrylo0", + "$entrylo1", + "$context", + "$pagemask", + "$wired", + "$7", + "$badvaddr", + "$count", + "$entryhi", + "$compare", + "$status", + "$cause", + "$epc", + "$prid", + "$config", + "$17", + "$18", + "$19", + "$20", + "$21", + "$22", + "$badpaddr", + "$hwbk", + "$pccr", + "$26", + "$27", + "$taglo", + "$taghi", + "$errorepc", + "$31" + } +}; +static const char * const REGC1[2][32] = +{ + { + "$f0", + "$f1", + "$f2", + "$f3", + "$f4", + "$f5", + "$f6", + "$f7", + "$f8", + "$f9", + "$f10", + "$f11", + "$f12", + "$f13", + "$f14", + "$f15", + "$f16", + "$f17", + "$f18", + "$f19", + "$f20", + "$f21", + "$f22", + "$f23", + "$f24", + "$f25", + "$f26", + "$f27", + "$f28", + "$f29", + "$f30", + "$f31" + }, + { + "$fv0", + "$fv1", + "$ft0", + "$ft1", + "$ft2", + "$ft3", + "$ft4", + "$ft5", + "$ft6", + "$ft7", + "$ft8", + "$ft9", + "$fa0", + "$fa1", + "$fa2", + "$fa3", + "$fa4", + "$fa5", + "$fa6", + "$fa7", + "$fs0", + "$fs1", + "$fs2", + "$fs3", + "$fs4", + "$fs5", + "$fs6", + "$fs7", + "$fs8", + "$fs9", + "$fs10", + "$fs11" + } +}; +// clang-format on + +typedef void (*Operand_func)(Disasm_result *result); +typedef struct opcode_table_entry_ +{ + const char *mnemonic; + const struct opcode_table_ *subtable; + Operand_func opfunc; +} Opcode_table_entry; +typedef struct opcode_table_ +{ + int bit_pos; + unsigned int bit_mask; + const Opcode_table_entry *entries; +} Opcode_table; + +static void getrs(unsigned int data, Operand *opr) +{ + opr->tag = OprTag_reg; + opr->reg = (data >> 21) & 0x1F; +} + +static void getrt(unsigned int data, Operand *opr) +{ + opr->tag = OprTag_reg; + opr->reg = (data >> 16) & 0x1F; +} + +static void getrd(unsigned int data, Operand *opr) +{ + opr->tag = OprTag_reg; + opr->reg = (data >> 11) & 0x1F; +} + +static void getc0rd_iop(unsigned int data, Operand *opr) +{ + opr->tag = OprTag_c0reg_iop; + opr->reg = (data >> 11) & 0x1F; +} + +static void getc0rd_ee(unsigned int data, Operand *opr) +{ + opr->tag = OprTag_c0reg_ee; + opr->reg = (data >> 11) & 0x1F; +} + +static void getczrd(unsigned int data, Operand *opr) +{ + opr->tag = OprTag_czreg; + opr->reg = (data >> 11) & 0x1F; +} + +static void getshamt(unsigned int data, Operand *opr) +{ + opr->tag = OprTag_shamt; + opr->data = (data >> 6) & 0x1F; +} + +static void getfs(unsigned int data, Operand *opr) +{ + opr->tag = OprTag_c1reg; + opr->reg = (data >> 11) & 0x1F; +} + +static void getft(unsigned int data, Operand *opr) +{ + opr->tag = OprTag_c1reg; + opr->reg = (data >> 16) & 0x1F; +} + +static void getfd(unsigned int data, Operand *opr) +{ + opr->tag = OprTag_c1reg; + opr->reg = (data >> 6) & 0x1F; +} + +static void getczfs(unsigned int data, Operand *opr) +{ + opr->tag = OprTag_c1reg; + opr->reg = (data >> 11) & 0x1F; +} + +static void getbroff(unsigned int addr, unsigned int data, Operand *opr) +{ + opr->tag = OprTag_jtarget; + if ( (data & 0x8000) != 0 ) + { + opr->data = 4 * (uint16_t)data - 0x40000; + } + else + { + opr->data = 4 * (uint16_t)data; + } + opr->data += 4 + addr; +} + +static void Rs(Disasm_result *result) +{ + getrs(result->data, result->operands); +} + +static void Rd(Disasm_result *result) +{ + getrd(result->data, result->operands); +} + +static void Rdrs(Disasm_result *result) +{ + getrd(result->data, result->operands); + getrs(result->data, &result->operands[1]); +} + +static void Rsrt(Disasm_result *result) +{ + getrs(result->data, result->operands); + getrt(result->data, &result->operands[1]); +} + +static void Rtc0rd_iop(Disasm_result *result) +{ + getrt(result->data, result->operands); + getc0rd_iop(result->data, &result->operands[1]); +} + +static void Rtc0rd_ee(Disasm_result *result) +{ + getrt(result->data, result->operands); + getc0rd_ee(result->data, &result->operands[1]); +} + +static void Rtczrd(Disasm_result *result) +{ + getrt(result->data, result->operands); + getczrd(result->data, &result->operands[1]); +} + +static void Rdrsrt(Disasm_result *result) +{ + getrd(result->data, result->operands); + getrs(result->data, &result->operands[1]); + getrt(result->data, &result->operands[2]); +} + +static void Rdrtrs(Disasm_result *result) +{ + getrd(result->data, result->operands); + getrt(result->data, &result->operands[1]); + getrs(result->data, &result->operands[2]); +} + +static void Rdrtshamt(Disasm_result *result) +{ + getrd(result->data, result->operands); + getrt(result->data, &result->operands[1]); + getshamt(result->data, &result->operands[2]); +} + +static void Rsseimm(Disasm_result *result) +{ + unsigned int imm; + + getrs(result->data, result->operands); + if ( (int16_t)(result->data & 0xFFFF) < 0 ) + { + imm = (result->data & 0xFFFF) - 0x10000; + } + else + { + imm = (result->data & 0xFFFF); + } + result->operands[1].tag = OprTag_imm; + result->operands[1].data = imm; +} + +static void Rtrsseimm(Disasm_result *result) +{ + unsigned int imm; + + getrt(result->data, result->operands); + getrs(result->data, &result->operands[1]); + if ( (int16_t)(result->data & 0xFFFF) < 0 ) + { + imm = (result->data & 0xFFFF) - 0x10000; + } + else + { + imm = (result->data & 0xFFFF); + } + result->operands[2].tag = OprTag_imm; + result->operands[2].data = imm; +} + +static void Rtrsimm(Disasm_result *result) +{ + getrt(result->data, result->operands); + getrs(result->data, &result->operands[1]); + result->operands[2].tag = OprTag_imm; + result->operands[2].data = (result->data & 0xFFFF); +} + +#if 0 +static void Rdimm(Disasm_result *result) +{ + getrd(result->data, result->operands); + result->operands[1].tag = OprTag_imm; + result->operands[1].data = (result->data & 0xFFFF); +} + +static void Rsimm(Disasm_result *result) +{ + getrs(result->data, result->operands); + result->operands[1].tag = OprTag_imm; + result->operands[1].data = (result->data & 0xFFFF); +} +#endif + +static void Rtimm(Disasm_result *result) +{ + getrt(result->data, result->operands); + result->operands[1].tag = OprTag_imm; + result->operands[1].data = (result->data & 0xFFFF); +} + +static void Rsrtbroff(Disasm_result *result) +{ + getrs(result->data, result->operands); + getrt(result->data, &result->operands[1]); + getbroff(result->addr, result->data, &result->operands[2]); +} + +static void Rsbroff(Disasm_result *result) +{ + getrs(result->data, result->operands); + getbroff(result->addr, result->data, &result->operands[1]); +} + +static void Rtoffbase(Disasm_result *result) +{ + unsigned int off; + + if ( (int16_t)(result->data & 0xFFFF) < 0 ) + { + off = (result->data & 0xFFFF) - 0x10000; + } + else + { + off = (result->data & 0xFFFF); + } + getrt(result->data, result->operands); + result->operands[1].tag = OprTag_regoffset; + result->operands[1].data = off; + result->operands[1].reg = (result->data >> 21) & 0x1F; +} + +static void Fdfs(Disasm_result *result) +{ + getfd(result->data, result->operands); + getfs(result->data, &result->operands[1]); +} + +static void Fsft(Disasm_result *result) +{ + getfs(result->data, result->operands); + getft(result->data, &result->operands[1]); +} + +static void Fdfsft(Disasm_result *result) +{ + getfd(result->data, result->operands); + getfs(result->data, &result->operands[1]); + getft(result->data, &result->operands[2]); +} + +static void Rtczfs(Disasm_result *result) +{ + getrt(result->data, result->operands); + getczfs(result->data, &result->operands[1]); +} + +static void Code20(Disasm_result *result) +{ + result->operands[0].tag = OprTag_code20; + result->operands[0].data = (result->data >> 6) & 0xFFFFF; +} + +static void Jtarget(Disasm_result *result) +{ + result->operands[0].tag = OprTag_jtarget; + result->operands[0].data = (4 * (result->data & 0x3FFFFFF)) | (result->addr & 0xF0000000); +} + +static void Cofun(Disasm_result *result) +{ + result->operands[0].tag = OprTag_code25; + result->operands[0].data = result->data & 0x1FFFFFF; +} + +static void Bcft(Disasm_result *result) +{ + result->mnemonic[0] = 'b'; + result->mnemonic[1] = 'c'; + result->mnemonic[2] = result->mnemonic[3]; + if ( (result->data & 0x10000) != 0 ) + { + result->mnemonic[3] = 't'; + } + else + { + result->mnemonic[3] = 'f'; + } + if ( (result->data & 0x20000) != 0 ) + { + result->mnemonic[4] = 'l'; + } + else + { + result->mnemonic[4] = '\x00'; + } + result->mnemonic[5] = '\x00'; + getbroff(result->addr, result->data, result->operands); +} + +// clang-format off +static const Opcode_table_entry iop_SPECIAL_entries[] = +{ + { "sll", NULL, &Rdrtshamt }, + { NULL, NULL, NULL }, + { "srl", NULL, &Rdrtshamt }, + { "sra", NULL, &Rdrtshamt }, + { "sllv", NULL, &Rdrtrs }, + { NULL, NULL, NULL }, + { "srlv", NULL, &Rdrtrs }, + { "srav", NULL, &Rdrtrs }, + { "jr", NULL, &Rs }, + { "jalr", NULL, &Rdrs }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "syscall", NULL, &Code20 }, + { "break", NULL, &Code20 }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "mfhi", NULL, &Rd }, + { "mthi", NULL, &Rs }, + { "mflo", NULL, &Rd }, + { "mtlo", NULL, &Rs }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "mult", NULL, &Rsrt }, + { "multu", NULL, &Rsrt }, + { "div", NULL, &Rsrt }, + { "divu", NULL, &Rsrt }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "add", NULL, &Rdrsrt }, + { "addu", NULL, &Rdrsrt }, + { "sub", NULL, &Rdrsrt }, + { "subu", NULL, &Rdrsrt }, + { "and", NULL, &Rdrsrt }, + { "or", NULL, &Rdrsrt }, + { "xor", NULL, &Rdrsrt }, + { "nor", NULL, &Rdrsrt }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "slt", NULL, &Rdrsrt }, + { "sltu", NULL, &Rdrsrt }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL } +}; +static const Opcode_table iop_SPECIAL = { 0, 63, iop_SPECIAL_entries }; +static const Opcode_table_entry ee_SPECIAL_entries[] = +{ + { "sll", NULL, &Rdrtshamt }, + { NULL, NULL, NULL }, + { "srl", NULL, &Rdrtshamt }, + { "sra", NULL, &Rdrtshamt }, + { "sllv", NULL, &Rdrtrs }, + { NULL, NULL, NULL }, + { "srlv", NULL, &Rdrtrs }, + { "srav", NULL, &Rdrtrs }, + { "jr", NULL, &Rs }, + { "jalr", NULL, &Rdrs }, + { "movz", NULL, &Rdrtrs }, + { "movn", NULL, &Rdrtrs }, + { "syscall", NULL, &Code20 }, + { "break", NULL, &Code20 }, + { NULL, NULL, NULL }, + { "sync", NULL, NULL }, + { "mfhi", NULL, &Rd }, + { "mthi", NULL, &Rs }, + { "mflo", NULL, &Rd }, + { "mtlo", NULL, &Rs }, + { "dsllv", NULL, &Rdrtrs }, + { NULL, NULL, NULL }, + { "dsrlv", NULL, &Rdrtrs }, + { "dsrav", NULL, &Rdrtrs }, + { "mult", NULL, &Rsrt }, + { "multu", NULL, &Rsrt }, + { "div", NULL, &Rsrt }, + { "divu", NULL, &Rsrt }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "add", NULL, &Rdrsrt }, + { "addu", NULL, &Rdrsrt }, + { "sub", NULL, &Rdrsrt }, + { "subu", NULL, &Rdrsrt }, + { "and", NULL, &Rdrsrt }, + { "or", NULL, &Rdrsrt }, + { "xor", NULL, &Rdrsrt }, + { "nor", NULL, &Rdrsrt }, + { "mfsa", NULL, &Rd }, + { "mtsa", NULL, &Rs }, + { "slt", NULL, &Rdrsrt }, + { "sltu", NULL, &Rdrsrt }, + { "dadd", NULL, &Rdrsrt }, + { "daddu", NULL, &Rdrsrt }, + { "dsub", NULL, &Rdrsrt }, + { "dsubu", NULL, &Rdrsrt }, + { "tge", NULL, &Rsrt }, + { "tgeu", NULL, &Rsrt }, + { "tlt", NULL, &Rsrt }, + { "tltu", NULL, &Rsrt }, + { "teq", NULL, &Rsrt }, + { NULL, NULL, NULL }, + { "tne", NULL, &Rsrt }, + { NULL, NULL, NULL }, + { "dsll", NULL, &Rdrtshamt }, + { NULL, NULL, NULL }, + { "dsrl", NULL, &Rdrtshamt }, + { "dsra", NULL, &Rdrtshamt }, + { "dsll32", NULL, &Rdrtshamt }, + { NULL, NULL, NULL }, + { "dsrl32", NULL, &Rdrtshamt }, + { "dsra32", NULL, &Rdrtshamt } +}; +static const Opcode_table ee_SPECIAL = { 0, 63, ee_SPECIAL_entries }; +static const Opcode_table_entry BCOND_entries[] = +{ + { "bltz", NULL, &Rsbroff }, + { "bgez", NULL, &Rsbroff }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "bltzal", NULL, &Rsbroff }, + { "bgezal", NULL, &Rsbroff }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL } +}; +static const Opcode_table BCOND = { 16, 31, BCOND_entries }; +static const Opcode_table_entry ee_REGIMM_entries[] = +{ + { "bltz", NULL, &Rsbroff }, + { "bgez", NULL, &Rsbroff }, + { "bltzl", NULL, &Rsbroff }, + { "bgezl", NULL, &Rsbroff }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "tgei", NULL, &Rsseimm }, + { "tgeiu", NULL, &Rsseimm }, + { "tlti", NULL, &Rsseimm }, + { "tltiu", NULL, &Rsseimm }, + { "teqi", NULL, &Rsseimm }, + { NULL, NULL, NULL }, + { "tnei", NULL, &Rsseimm }, + { NULL, NULL, NULL }, + { "bltzal", NULL, &Rsbroff }, + { "bgezal", NULL, &Rsbroff }, + { "bltzall", NULL, &Rsbroff }, + { "bgezall", NULL, &Rsbroff }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "mtsab", NULL, &Rsseimm }, + { "mtsah", NULL, &Rsseimm }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL } +}; +static const Opcode_table ee_REGIMM = { 16, 31, ee_REGIMM_entries }; +static const Opcode_table_entry iop_COP0CO_entries[] = +{ + { NULL, NULL, NULL }, + { "tlbr", NULL, NULL }, + { "tlbwi", NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "tlbwr", NULL, NULL }, + { NULL, NULL, NULL }, + { "tlbp", NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "rfe", NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL } +}; +static const Opcode_table iop_COP0CO = { 0, 63, iop_COP0CO_entries }; +static const Opcode_table_entry ee_COP0CO_entries[] = +{ + { NULL, NULL, NULL }, + { "tlbr", NULL, NULL }, + { "tlbwi", NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "tlbwr", NULL, NULL }, + { NULL, NULL, NULL }, + { "tlbp", NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "eret", NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "ei", NULL, NULL }, + { "di", NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL } +}; +static const Opcode_table ee_COP0CO = { 0, 63, ee_COP0CO_entries }; +static const Opcode_table_entry iop_COP0_entries[] = +{ + { "mfc0", NULL, &Rtc0rd_iop }, + { NULL, NULL, NULL }, + { "cfc0", NULL, &Rtc0rd_iop }, + { NULL, NULL, NULL }, + { "mtc0", NULL, &Rtc0rd_iop }, + { NULL, NULL, NULL }, + { "ctc0", NULL, &Rtc0rd_iop }, + { NULL, NULL, NULL }, + { "cop0", NULL, &Bcft }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "cop0", NULL, &Bcft }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, &iop_COP0CO, NULL }, + { NULL, &iop_COP0CO, NULL }, + { NULL, &iop_COP0CO, NULL }, + { NULL, &iop_COP0CO, NULL }, + { NULL, &iop_COP0CO, NULL }, + { NULL, &iop_COP0CO, NULL }, + { NULL, &iop_COP0CO, NULL }, + { NULL, &iop_COP0CO, NULL }, + { NULL, &iop_COP0CO, NULL }, + { NULL, &iop_COP0CO, NULL }, + { NULL, &iop_COP0CO, NULL }, + { NULL, &iop_COP0CO, NULL }, + { NULL, &iop_COP0CO, NULL }, + { NULL, &iop_COP0CO, NULL }, + { NULL, &iop_COP0CO, NULL }, + { NULL, &iop_COP0CO, NULL } +}; +static const Opcode_table iop_COP0 = { 21, 31, iop_COP0_entries }; +static const Opcode_table_entry ee_COP0_entries[] = +{ + { "mfc0", NULL, &Rtc0rd_ee }, + { NULL, NULL, NULL }, + { "cfc0", NULL, &Rtc0rd_ee }, + { NULL, NULL, NULL }, + { "mtc0", NULL, &Rtc0rd_ee }, + { NULL, NULL, NULL }, + { "ctc0", NULL, &Rtc0rd_ee }, + { NULL, NULL, NULL }, + { "cop0", NULL, &Bcft }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "cop0", NULL, &Bcft }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, &ee_COP0CO, NULL }, + { NULL, &ee_COP0CO, NULL }, + { NULL, &ee_COP0CO, NULL }, + { NULL, &ee_COP0CO, NULL }, + { NULL, &ee_COP0CO, NULL }, + { NULL, &ee_COP0CO, NULL }, + { NULL, &ee_COP0CO, NULL }, + { NULL, &ee_COP0CO, NULL }, + { NULL, &ee_COP0CO, NULL }, + { NULL, &ee_COP0CO, NULL }, + { NULL, &ee_COP0CO, NULL }, + { NULL, &ee_COP0CO, NULL }, + { NULL, &ee_COP0CO, NULL }, + { NULL, &ee_COP0CO, NULL }, + { NULL, &ee_COP0CO, NULL }, + { NULL, &ee_COP0CO, NULL } +}; +static const Opcode_table ee_COP0 = { 21, 31, ee_COP0_entries }; +static const Opcode_table_entry ee_COP1CO_entries[] = +{ + { "add.s", NULL, &Fdfsft }, + { "sub.s", NULL, &Fdfsft }, + { "mul.s", NULL, &Fdfsft }, + { "div.s", NULL, &Fdfsft }, + { "sqrt.s", NULL, &Fdfs }, + { "abs.s", NULL, &Fdfs }, + { "mov.s", NULL, &Fdfs }, + { "neg.s", NULL, &Fdfs }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "rsqrt.s", NULL, &Fdfs }, + { NULL, NULL, NULL }, + { "adda.s", NULL, &Fsft }, + { "suba.s", NULL, &Fsft }, + { "mula.s", NULL, &Fsft }, + { NULL, NULL, NULL }, + { "madd.s", NULL, &Fdfsft }, + { "msub.s", NULL, &Fdfsft }, + { "madda.s", NULL, &Fsft }, + { "msuba.s", NULL, &Fsft }, + { "cvt", NULL, &Fdfs }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "cvt", NULL, &Fdfs }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "max.s", NULL, &Fdfs }, + { "min.s", NULL, &Fdfs }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "c.f.s", NULL, &Fsft }, + { NULL, NULL, NULL }, + { "c.eq.s", NULL, &Fsft }, + { NULL, NULL, NULL }, + { "c.lt.s", NULL, &Fsft }, + { NULL, NULL, NULL }, + { "c.le.s", NULL, &Fsft }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL } +}; +static const Opcode_table ee_COP1CO = { 0, 63, ee_COP1CO_entries }; +static const Opcode_table_entry iop_COP1_entries[] = +{ + { "mfc1", NULL, &Rtczrd }, + { NULL, NULL, NULL }, + { "cfc1", NULL, &Rtczrd }, + { NULL, NULL, NULL }, + { "mtc1", NULL, &Rtczrd }, + { NULL, NULL, NULL }, + { "ctc1", NULL, &Rtczrd }, + { NULL, NULL, NULL }, + { "cop1", NULL, &Bcft }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "cop1", NULL, &Bcft }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "cop1", NULL, &Cofun }, + { "cop1", NULL, &Cofun }, + { "cop1", NULL, &Cofun }, + { "cop1", NULL, &Cofun }, + { "cop1", NULL, &Cofun }, + { "cop1", NULL, &Cofun }, + { "cop1", NULL, &Cofun }, + { "cop1", NULL, &Cofun }, + { "cop1", NULL, &Cofun }, + { "cop1", NULL, &Cofun }, + { "cop1", NULL, &Cofun }, + { "cop1", NULL, &Cofun }, + { "cop1", NULL, &Cofun }, + { "cop1", NULL, &Cofun }, + { "cop1", NULL, &Cofun }, + { "cop1", NULL, &Cofun } +}; +static const Opcode_table iop_COP1 = { 21, 31, iop_COP1_entries }; +static const Opcode_table_entry ee_COP1_entries[] = +{ + { "mfc1", NULL, &Rtczfs }, + { NULL, NULL, NULL }, + { "cfc1", NULL, &Rtczfs }, + { NULL, NULL, NULL }, + { "mtc1", NULL, &Rtczfs }, + { NULL, NULL, NULL }, + { "ctc1", NULL, &Rtczfs }, + { NULL, NULL, NULL }, + { "cop1", NULL, &Bcft }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "cop1", NULL, &Bcft }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, &ee_COP1CO, NULL }, + { NULL, &ee_COP1CO, NULL }, + { NULL, &ee_COP1CO, NULL }, + { NULL, &ee_COP1CO, NULL }, + { NULL, &ee_COP1CO, NULL }, + { NULL, &ee_COP1CO, NULL }, + { NULL, &ee_COP1CO, NULL }, + { NULL, &ee_COP1CO, NULL }, + { NULL, &ee_COP1CO, NULL }, + { NULL, &ee_COP1CO, NULL }, + { NULL, &ee_COP1CO, NULL }, + { NULL, &ee_COP1CO, NULL }, + { NULL, &ee_COP1CO, NULL }, + { NULL, &ee_COP1CO, NULL }, + { NULL, &ee_COP1CO, NULL }, + { NULL, &ee_COP1CO, NULL } +}; +static const Opcode_table ee_COP1 = { 21, 31, ee_COP1_entries }; +static const Opcode_table_entry iop_COP2_entries[] = +{ + { "mfc2", NULL, &Rtczrd }, + { NULL, NULL, NULL }, + { "cfc2", NULL, &Rtczrd }, + { NULL, NULL, NULL }, + { "mtc2", NULL, &Rtczrd }, + { NULL, NULL, NULL }, + { "ctc2", NULL, &Rtczrd }, + { NULL, NULL, NULL }, + { "cop2", NULL, &Bcft }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "cop2", NULL, &Bcft }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun } +}; +static const Opcode_table iop_COP2 = { 21, 31, iop_COP2_entries }; +static const Opcode_table_entry ee_COP2_entries[] = +{ + { "mfc2", NULL, &Rtczrd }, + { "qmfc2", NULL, &Rtczrd }, + { "cfc2", NULL, &Rtczrd }, + { NULL, NULL, NULL }, + { "mtc2", NULL, &Rtczrd }, + { "qmtc2", NULL, &Rtczrd }, + { "ctc2", NULL, &Rtczrd }, + { NULL, NULL, NULL }, + { "cop2", NULL, &Bcft }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "cop2", NULL, &Bcft }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun }, + { "cop2", NULL, &Cofun } +}; +static const Opcode_table ee_COP2 = { 21, 31, ee_COP2_entries }; +static const Opcode_table_entry COP3_entries[] = +{ + { "mfc3", NULL, &Rtczrd }, + { NULL, NULL, NULL }, + { "cfc3", NULL, &Rtczrd }, + { NULL, NULL, NULL }, + { "mtc3", NULL, &Rtczrd }, + { NULL, NULL, NULL }, + { "ctc3", NULL, &Rtczrd }, + { NULL, NULL, NULL }, + { "cop3", NULL, &Bcft }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "cop3", NULL, &Bcft }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "cop3", NULL, &Cofun }, + { "cop3", NULL, &Cofun }, + { "cop3", NULL, &Cofun }, + { "cop3", NULL, &Cofun }, + { "cop3", NULL, &Cofun }, + { "cop3", NULL, &Cofun }, + { "cop3", NULL, &Cofun }, + { "cop3", NULL, &Cofun }, + { "cop3", NULL, &Cofun }, + { "cop3", NULL, &Cofun }, + { "cop3", NULL, &Cofun }, + { "cop3", NULL, &Cofun }, + { "cop3", NULL, &Cofun }, + { "cop3", NULL, &Cofun }, + { "cop3", NULL, &Cofun }, + { "cop3", NULL, &Cofun } +}; +static const Opcode_table COP3 = { 21, 31, COP3_entries }; +static const Opcode_table_entry iop_opcode_root_table_entries[] = +{ + { NULL, &iop_SPECIAL, NULL }, + { NULL, &BCOND, NULL }, + { "j", NULL, &Jtarget }, + { "jal", NULL, &Jtarget }, + { "beq", NULL, &Rsrtbroff }, + { "bne", NULL, &Rsrtbroff }, + { "blez", NULL, &Rsbroff }, + { "bgtz", NULL, &Rsbroff }, + { "addi", NULL, &Rtrsseimm }, + { "addiu", NULL, &Rtrsseimm }, + { "slti", NULL, &Rtrsseimm }, + { "sltiu", NULL, &Rtrsseimm }, + { "andi", NULL, &Rtrsimm }, + { "ori", NULL, &Rtrsimm }, + { "xori", NULL, &Rtrsimm }, + { "lui", NULL, &Rtimm }, + { NULL, &iop_COP0, NULL }, + { NULL, &iop_COP1, NULL }, + { NULL, &iop_COP2, NULL }, + { NULL, &COP3, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "lb", NULL, &Rtoffbase }, + { "lh", NULL, &Rtoffbase }, + { "lwl", NULL, &Rtoffbase }, + { "lw", NULL, &Rtoffbase }, + { "lbu", NULL, &Rtoffbase }, + { "lhu", NULL, &Rtoffbase }, + { "lwr", NULL, &Rtoffbase }, + { NULL, NULL, NULL }, + { "sb", NULL, &Rtoffbase }, + { "sh", NULL, &Rtoffbase }, + { "swl", NULL, &Rtoffbase }, + { "sw", NULL, &Rtoffbase }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "swr", NULL, &Rtoffbase }, + { NULL, NULL, NULL }, + { "lwc0", NULL, &Rtoffbase }, + { "lwc1", NULL, &Rtoffbase }, + { "lwc2", NULL, &Rtoffbase }, + { "lwc3", NULL, &Rtoffbase }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "swc0", NULL, &Rtoffbase }, + { "swc1", NULL, &Rtoffbase }, + { "swc2", NULL, &Rtoffbase }, + { "swc3", NULL, &Rtoffbase }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL } +}; +static const Opcode_table_entry ee_opcode_root_table_entries[] = +{ + { NULL, &ee_SPECIAL, NULL }, + { NULL, &ee_REGIMM, NULL }, + { "j", NULL, &Jtarget }, + { "jal", NULL, &Jtarget }, + { "beq", NULL, &Rsrtbroff }, + { "bne", NULL, &Rsrtbroff }, + { "blez", NULL, &Rsbroff }, + { "bgtz", NULL, &Rsbroff }, + { "addi", NULL, &Rtrsseimm }, + { "addiu", NULL, &Rtrsseimm }, + { "slti", NULL, &Rtrsseimm }, + { "sltiu", NULL, &Rtrsseimm }, + { "andi", NULL, &Rtrsimm }, + { "ori", NULL, &Rtrsimm }, + { "xori", NULL, &Rtrsimm }, + { "lui", NULL, &Rtimm }, + { NULL, &ee_COP0, NULL }, + { NULL, &ee_COP1, NULL }, + { NULL, &ee_COP2, NULL }, + { NULL, &COP3, NULL }, + { "beql", NULL, &Rsrtbroff }, + { "bnel", NULL, &Rsrtbroff }, + { "blezl", NULL, &Rsbroff }, + { "bgtzl", NULL, &Rsbroff }, + { "daddi", NULL, &Rtrsseimm }, + { "daddiu", NULL, &Rtrsseimm }, + { "ldl", NULL, &Rtoffbase }, + { "ldr", NULL, &Rtoffbase }, + { "mmi", NULL, NULL }, + { NULL, NULL, NULL }, + { "lq", NULL, &Rtoffbase }, + { "sq", NULL, &Rtoffbase }, + { "lb", NULL, &Rtoffbase }, + { "lh", NULL, &Rtoffbase }, + { "lwl", NULL, &Rtoffbase }, + { "lw", NULL, &Rtoffbase }, + { "lbu", NULL, &Rtoffbase }, + { "lhu", NULL, &Rtoffbase }, + { "lwr", NULL, &Rtoffbase }, + { NULL, NULL, NULL }, + { "sb", NULL, &Rtoffbase }, + { "sh", NULL, &Rtoffbase }, + { "swl", NULL, &Rtoffbase }, + { "sw", NULL, &Rtoffbase }, + { "sdl", NULL, &Rtoffbase }, + { "sdr", NULL, &Rtoffbase }, + { "swr", NULL, &Rtoffbase }, + { "cache", NULL, NULL }, + { "lwc0", NULL, &Rtoffbase }, + { "lwc1", NULL, &Rtoffbase }, + { "lwc2", NULL, &Rtoffbase }, + { "pref", NULL, &Rtoffbase }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "lqc2", NULL, &Rtoffbase }, + { "ld", NULL, &Rtoffbase }, + { "swc0", NULL, &Rtoffbase }, + { "swc1", NULL, &Rtoffbase }, + { "swc2", NULL, &Rtoffbase }, + { "swc3", NULL, &Rtoffbase }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { "sqc2", NULL, &Rtoffbase }, + { "sd", NULL, &Rtoffbase } +}; +static const Opcode_table iop_opcode_root_table = { 26, 63, iop_opcode_root_table_entries }; +static const Opcode_table ee_opcode_root_table = { 26, 63, ee_opcode_root_table_entries }; +static const Opcode_table * opcode_root_table = &iop_opcode_root_table; +// clang-format on + +void gen_asmmacro(Disasm_result *result) +{ + if ( result->data ) + { + if ( + !strcmp("beq", result->mnemonic) && result->operands[0].tag == OprTag_reg && result->operands[1].tag == OprTag_reg + && result->operands[1].reg == result->operands[0].reg ) + { + strcpy(result->mnemonic, "b"); + result->operands[0] = result->operands[2]; + result->operands[1].tag = OprTag_none; + } + else if ( !strcmp("bgezal", result->mnemonic) && result->operands[0].tag == OprTag_reg && !result->operands[0].reg ) + { + strcpy(result->mnemonic, "bal"); + result->operands[0] = result->operands[1]; + result->operands[1].tag = OprTag_none; + } + else if ( !strcmp("cvt", result->mnemonic) ) + { + if ( ((result->data >> 21) & 0x1F) == 20 ) + { + strcpy(result->mnemonic, "cvt.s.w"); + } + else if ( ((result->data >> 21) & 0x1F) == 16 ) + { + strcpy(result->mnemonic, "cvt.w.s"); + } + } + } + else + { + strcpy(result->mnemonic, "nop"); + result->operands[0].tag = OprTag_none; + } +} + +void initdisasm(int arch, int regform0, int regform1, int regform2, int regform3) +{ + switch ( arch ) + { + case 1: + opcode_root_table = &iop_opcode_root_table; + break; + case 2: + opcode_root_table = &ee_opcode_root_table; + break; + default: + break; + } + if ( regform0 != -1 ) + { + if ( !regform0 || regform0 == 1 ) + { + regnmsw[0] = regform0; + } + if ( !regform1 || regform1 == 1 ) + { + regnmsw[1] = regform0; + } + if ( !regform2 || regform2 == 1 ) + { + regnmsw[2] = regform0; + } + if ( !regform3 || regform3 == 1 ) + { + regnmsw[3] = regform3; + } + } +} + +Disasm_result *disassemble(unsigned int addr, unsigned int data) +{ + Disasm_result *v3; + const Opcode_table_entry *op; + const Opcode_table *optable; + + optable = opcode_root_table; + v3 = (Disasm_result *)calloc(1, sizeof(Disasm_result)); + for ( ;; ) + { + op = &optable->entries[(data >> optable->bit_pos) & optable->bit_mask]; + if ( !op->subtable ) + { + break; + } + optable = op->subtable; + } + v3->addr = addr; + v3->data = data; + if ( op->mnemonic ) + { + strcpy(v3->mnemonic, op->mnemonic); + if ( op->opfunc ) + { + op->opfunc(v3); + } + } + return v3; +} + +void shex(char *buf, unsigned int data) +{ + if ( (data & 0x80000000) != 0 ) + { + sprintf(buf, "-0x%x", -data); + } + else + { + sprintf(buf, "0x%x", data); + } +} + +void format_operand(const Operand *opr, char *buf) +{ + switch ( opr->tag ) + { + case OprTag_reg: + strcpy(buf, REGNAME[regnmsw[0]][opr->reg]); + break; + case OprTag_c0reg_iop: + strcpy(buf, REGC0_iop[regnmsw[0]][opr->reg]); + break; + case OprTag_c0reg_ee: + strcpy(buf, REGC0_ee[regnmsw[0]][opr->reg]); + break; + case OprTag_czreg: + sprintf(buf, "$%d", opr->reg); + break; + case OprTag_c1reg: + strcpy(buf, REGC1[regnmsw[1]][opr->reg]); + break; + case OprTag_imm: + case OprTag_jtarget: + shex(buf, opr->data); + break; + case OprTag_shamt: + sprintf(buf, "%d", (int)(opr->data)); + break; + case OprTag_regoffset: + shex(buf, opr->data); + sprintf(&buf[strlen(buf)], "(%s)", REGNAME[regnmsw[0]][opr->reg]); + break; + case OprTag_code20: + case OprTag_code25: + sprintf(buf, "0x%x", opr->data); + break; + default: + sprintf(buf, "?type?(0x%x)", opr->tag); + fprintf(stderr, "Panic unknown oprand type 0x%x\n", opr->tag); + break; + } +} + +void format_disasm(Disasm_result *dis, char *buf) +{ + char *s; + + sprintf(buf, "%08x: %08x", dis->addr, dis->data); + s = &buf[strlen(buf)]; + if ( dis->mnemonic[0] ) + { + int i; + char *sa; + + sprintf(s, " %-8s", dis->mnemonic); + sa = &s[strlen(s)]; + for ( i = 0; dis->operands[i].tag; i += 1 ) + { + format_operand(&dis->operands[i], sa); + if ( dis->operands[i + 1].tag ) + { + strcat(sa, ", "); + } + sa += strlen(sa); + } + } +} diff --git a/tools/srxfixup/src/readconf.c b/tools/srxfixup/src/readconf.c new file mode 100644 index 00000000000..eb8c42effd2 --- /dev/null +++ b/tools/srxfixup/src/readconf.c @@ -0,0 +1,976 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "srxfixup_internal.h" +#include +#include +#include +#include + +typedef struct lowtoken_ +{ + const char *str; + int line; + int col; +} LowToken; +enum TokenCode +{ + TC_NULL = 0, + TC_STRING = 1, + TC_VECTOR = 2, + TC_IOP = 3, + TC_EE = 4, + TC_Define = 5, + TC_Segments_name = 6, + TC_Memory_segment = 7, + TC_remove = 8, + TC_Program_header_order = 9, + TC_Program_header_data = 10, + TC_Segment_data = 11, + TC_segment = 12, + TC_createinfo = 13, + TC_Section_header_table = 14, + TC_CreateSymbols = 15, + TC_MAX_NUMBER = 16 +}; +typedef struct TokenTree_ +{ + enum TokenCode tkcode; + union TokenTree_value + { + struct TokenTree_ *subtree; + LowToken *lowtoken; + } value; +} TokenTree; +struct fstrbuf +{ + int line; + int col; + const char *cp; + const char *ep; + char buf[]; +}; + +static int bgetc(struct fstrbuf *fb); +static void bungetc(struct fstrbuf *fb); +static int skipsp(struct fstrbuf *fb); +static int skip_to_eol(struct fstrbuf *fb); +static int gettoken(char **strbuf, struct fstrbuf *fb); +static void split_conf(LowToken *result, char *strbuf, struct fstrbuf *fb); +static TokenTree *make_conf_vector(LowToken **lowtokens); +static TokenTree *make_conf_tree(LowToken *lowtokens); +static int get_vector_len(TokenTree *ttp); +static int get_stringvector_len(const char **str); +static const char **add_stringvector(const char **str, const char *newstr); +static int setup_reserved_symbol_table(CreateSymbolConf *result, TokenTree *ttp, Srx_gen_table *conf); +static int gen_define(TokenTree *ttp, Srx_gen_table *result); +static void get_section_type_flag(TokenTree *ttp, int *rtype, int *rflag); +static elf_section *make_empty_section(const char *name, int type, int flag); +static Srx_gen_table *make_srx_gen_table(TokenTree *tokentree); +static void check_change_bit(unsigned int oldbit, unsigned int newbit, unsigned int *up, unsigned int *down); +static int check_srx_gen_table(Srx_gen_table *tp); + +Srx_gen_table *read_conf(const char *indata, const char *infile, int dumpopt) +{ + LowToken *lowtokens; + struct fstrbuf *fbuf; + unsigned int fsize; + FILE *fp; + + fp = 0; + if ( !indata ) + { + fprintf(stderr, "internal error read_conf()\n"); + return 0; + } + if ( infile ) + { + fp = fopen(infile, "re"); + if ( !fp ) + { + fprintf(stderr, "\"%s\" can't open\n", infile); + return 0; + } + fseek(fp, 0, SEEK_END); + fsize = ftell(fp) + 4; + fseek(fp, 0, SEEK_SET); + } + else + { + fsize = strlen(indata); + } + lowtokens = (LowToken *)calloc( + ((sizeof(LowToken) + 2) * (fsize + 1) + (sizeof(LowToken) - 1)) / sizeof(LowToken), sizeof(LowToken)); + fbuf = (struct fstrbuf *)malloc(fsize + sizeof(struct fstrbuf) + 1); + fbuf->cp = fbuf->buf; + fbuf->line = 1; + fbuf->col = 1; + if ( infile ) + { + fbuf->ep = &fbuf->cp[fread(fbuf->buf, 1, fsize, fp)]; + fclose(fp); + } + else + { + strcpy(fbuf->buf, indata); + fbuf->ep = &fbuf->cp[fsize]; + } + if ( dumpopt == 1 ) + { + for ( ;; ) + { + int ch_; + + ch_ = bgetc(fbuf); + if ( ch_ == -1 ) + { + break; + } + fputc(ch_, stdout); + } + free(lowtokens); + free(fbuf); + return 0; + } + TokenTree *tokentree; + Srx_gen_table *srx_gen_table; + + split_conf(lowtokens, (char *)&lowtokens[fsize + 1], fbuf); + free(fbuf); + tokentree = make_conf_tree(lowtokens); + srx_gen_table = make_srx_gen_table(tokentree); + free(tokentree); + if ( check_srx_gen_table(srx_gen_table) ) + { + free(srx_gen_table); + return 0; + } + return srx_gen_table; +} + +static int bgetc(struct fstrbuf *fb) +{ + int ret; + + if ( fb->ep <= fb->cp ) + { + return -1; + } + if ( *fb->cp == '\n' ) + { + fb->line += 1; + fb->col = 0; + } + else + { + fb->col += 1; + } + ret = (unsigned char)(*fb->cp); + fb->cp += 1; + return ret; +} + +static void bungetc(struct fstrbuf *fb) +{ + if ( fb->cp > fb->buf ) + { + fb->cp -= 1; + fb->col -= 1; + if ( *fb->cp == '\n' ) + { + fb->line -= 1; + } + } +} + +static int skipsp(struct fstrbuf *fb) +{ + int ch_; + + do + { + ch_ = bgetc(fb); + } while ( ch_ != -1 && isspace(ch_) != 0 ); + if ( ch_ != -1 ) + { + bungetc(fb); + } + return ch_ != -1; +} + +static int skip_to_eol(struct fstrbuf *fb) +{ + int ch_; + + do + { + ch_ = bgetc(fb); + } while ( ch_ != -1 && ch_ != '\n' && ch_ != '\r' ); + return ch_ != -1; +} + +static int gettoken(char **strbuf, struct fstrbuf *fb) +{ + int ch_; + char *cp; + + for ( cp = *strbuf;; *cp = 0 ) + { + ch_ = bgetc(fb); + if ( ch_ == -1 || (ch_ != '.' && ch_ != '_' && ch_ != '*' && isalnum(ch_) == 0) ) + { + break; + } + *cp = (char)(ch_ & 0xFF); + cp += 1; + } + if ( ch_ != -1 ) + { + bungetc(fb); + } + *strbuf = cp + 1; + return ch_ != -1; +} + +static void split_conf(LowToken *result, char *strbuf, struct fstrbuf *fb) +{ + char *cp; + + cp = strbuf; + for ( ; skipsp(fb); ) + { + int cuchar; + + cuchar = bgetc(fb); + if ( cuchar == '@' || cuchar == '.' || cuchar == '_' || cuchar == '*' || isalnum(cuchar) != 0 ) + { + result->str = cp; + result->line = fb->line; + result->col = fb->col; + result += 1; + result->str = 0; + *cp = (char)(cuchar & 0xFF); + cp += 1; + gettoken(&cp, fb); + } + else if ( cuchar == '#' ) + { + skip_to_eol(fb); + } + else if ( isprint(cuchar) != 0 ) + { + result->str = cp; + result->line = fb->line; + result->col = fb->col; + result += 1; + result->str = 0; + *cp = (char)(cuchar & 0xFF); + cp += 1; + *cp = 0; + cp += 1; + } + } +} + +// clang-format off +struct keyword_table_ +{ + int code; + const char * name; +} keyword_table[] = +{ + { 3, "IOP" }, + { 4, "EE" }, + { 5, "Define" }, + { 6, "Segments_name" }, + { 7, "Memory_segment" }, + { 8, "remove" }, + { 9, "Program_header_order" }, + { 10, "Program_header_data" }, + { 11, "Segment_data" }, + { 12, "segment" }, + { 13, "createinfo" }, + { 14, "Section_header_table" }, + { 15, "CreateSymbols" }, + { -1, NULL } +}; +// clang-format on + +static TokenTree *make_conf_vector(LowToken **lowtokens) +{ + struct keyword_table_ *kt; + const LowToken *sltp; + LowToken *ltp; + int entries; + TokenTree *v14; + + entries = 0; + ltp = *lowtokens; + v14 = (TokenTree *)calloc(1, sizeof(TokenTree)); + v14->tkcode = TC_NULL; + for ( ; ltp->str && strcmp(ltp->str, "}") != 0; ) + { + { + TokenTree *realloc_tmp = (TokenTree *)realloc(v14, (entries + 2) * sizeof(TokenTree)); + if ( realloc_tmp == NULL ) + { + fprintf(stderr, "Failure to allocate token tree\n"); + exit(1); + } + v14 = realloc_tmp; + } + + if ( !strcmp(ltp->str, "{") ) + { + sltp = ltp; + ltp += 1; + v14[entries].tkcode = TC_VECTOR; + v14[entries].value.subtree = make_conf_vector(<p); + if ( !ltp->str || strcmp(ltp->str, "}") != 0 ) + { + fprintf(stderr, "make_conf_vector(): missing '}' line:%d col=%d\n", sltp->line, sltp->col); + exit(1); + } + ltp += 1; + } + else + { + if ( *ltp->str != '@' && *ltp->str != '.' && *ltp->str != '_' && *ltp->str != '*' && isalnum(*ltp->str) == 0 ) + { + fprintf(stderr, "make_conf_vector(): unexcepted data '%s' line:%d col=%d\n", ltp->str, ltp->line, ltp->col); + exit(1); + } + if ( *ltp->str == '@' ) + { + for ( kt = keyword_table; kt->code >= 0 && strcmp(kt->name, ltp->str + 1) != 0; kt += 1 ) + { + ; + } + if ( kt->code < 0 ) + { + fprintf(stderr, "make_conf_vector(): unknown keyword '%s' line:%d col=%d\n", ltp->str, ltp->line, ltp->col); + exit(1); + } + v14[entries].tkcode = kt->code; + } + else + { + v14[entries].tkcode = TC_STRING; + } + v14[entries].value.subtree = (TokenTree *)ltp; + ltp += 1; + } + entries += 1; + v14[entries].tkcode = TC_NULL; + } + *lowtokens = ltp; + return v14; +} + +static TokenTree *make_conf_tree(LowToken *lowtokens) +{ + TokenTree *v4; + + v4 = (TokenTree *)calloc(1, sizeof(TokenTree)); + v4->tkcode = TC_VECTOR; + v4->value.subtree = make_conf_vector(&lowtokens); + if ( lowtokens->str ) + { + fprintf( + stderr, + "make_conf_tree(): unexcepted data '%s' line:%d col=%d\n", + lowtokens->str, + lowtokens->line, + lowtokens->col); + exit(1); + } + return v4; +} + +static int get_vector_len(TokenTree *ttp) +{ + int v2; + + for ( v2 = 0; ttp->tkcode; v2 += 1, ttp += 1 ) + { + ; + } + return v2; +} + +static int get_stringvector_len(const char **str) +{ + int v2; + + for ( v2 = 0; *str; v2 += 1, str += 1 ) + { + ; + } + return v2; +} + +static const char **add_stringvector(const char **str, const char *newstr) +{ + int stringvector_len; + const char **result; + int nstr; + + stringvector_len = get_stringvector_len(str); + nstr = stringvector_len + 1; + result = (const char **)realloc(str, (stringvector_len + 2) * sizeof(const char *)); + result[nstr - 1] = newstr; + result[nstr] = 0; + return result; +} + +static int setup_reserved_symbol_table(CreateSymbolConf *result, TokenTree *ttp, Srx_gen_table *conf) +{ + if ( !strcmp("GLOBAL", ttp[1].value.lowtoken->str) ) + { + result->bind = STB_GLOBAL; + } + else if ( !strcmp("LOCAL", ttp[1].value.lowtoken->str) ) + { + result->bind = STB_LOCAL; + } + else if ( !strcmp("WEAK", ttp[1].value.lowtoken->str) ) + { + result->bind = STB_WEAK; + } + else + { + fprintf(stderr, "Unsupported bind '%s' for '%s'\n", ttp[1].value.lowtoken->str, ttp->value.lowtoken->str); + return 1; + } + if ( strcmp("OBJECT", ttp[2].value.lowtoken->str) != 0 ) + { + fprintf(stderr, "Unsupported type '%s' for '%s'\n", ttp[2].value.lowtoken->str, ttp->value.lowtoken->str); + return 1; + } + result->type = STT_OBJECT; + result->segment = lookup_segment(conf, ttp[3].value.lowtoken->str, 0); + if ( !result->segment && ttp[3].value.lowtoken->str[0] == '.' ) + { + result->sectname = ttp[3].value.lowtoken->str; + } + else + { + result->sectname = 0; + if ( !result->segment ) + { + fprintf(stderr, "Unknown segment '%s' for '%s'\n", ttp[3].value.lowtoken->str, ttp->value.lowtoken->str); + return 1; + } + } + if ( !strcmp("SHN_RADDR", ttp[4].value.lowtoken->str) ) + { + result->shindex = 65311; + } + else if ( !strcmp("0", ttp[4].value.lowtoken->str) ) + { + result->shindex = 0; + } + else + { + fprintf(stderr, "Unknown shindex '%s' for '%s'\n", ttp[4].value.lowtoken->str, ttp->value.lowtoken->str); + return 1; + } + if ( !strcmp("start", ttp[5].value.lowtoken->str) ) + { + result->seflag = 0; + } + else if ( !strcmp("end", ttp[5].value.lowtoken->str) ) + { + result->seflag = 1; + } + else if ( !strcmp("gpbase", ttp[5].value.lowtoken->str) ) + { + result->seflag = 2; + } + else + { + fprintf(stderr, "Unknown base '%s' for '%s'\n", ttp[5].value.lowtoken->str, ttp->value.lowtoken->str); + return 1; + } + result->name = ttp->value.lowtoken->str; + return 0; +} + +static int gen_define(TokenTree *ttp, Srx_gen_table *result) +{ + PheaderInfo *phrlist; + SegConf *segp; + SegConf *seglist; + TokenTree *subarg; + TokenTree *arg; + int n; + int nseg; + int m; + int j; + int k; + int i; + int entries_1; + int entries_2; + int entries_3; + int entries_4; + + for ( ; ttp->tkcode; ttp += 2 ) + { + if ( ttp[1].tkcode != TC_VECTOR ) + { + fprintf( + stderr, + "argument not found for '%s' line:%d col=%d\n", + ttp->value.lowtoken->str, + ttp->value.lowtoken->line, + ttp->value.lowtoken->col); + return 1; + } + arg = ttp[1].value.subtree; + switch ( ttp->tkcode ) + { + case TC_Segments_name: + entries_1 = get_vector_len(arg); + seglist = (SegConf *)calloc(entries_1 + 1, sizeof(SegConf)); + result->segment_list = seglist; + for ( m = 0; m < entries_1; m += 1 ) + { + seglist[m].name = arg[m].value.lowtoken->str; + seglist[m].sect_name_patterns = (const char **)calloc(1, sizeof(const char *)); + } + break; + case TC_Memory_segment: + entries_4 = get_vector_len(arg); + for ( i = 0; i < entries_4; i += 1 ) + { + segp = lookup_segment(result, arg[i].value.lowtoken->str, 1); + if ( !segp ) + { + return 1; + } + segp->bitid = 1 << (segp - result->segment_list); + } + break; + case TC_Program_header_order: + entries_2 = get_vector_len(arg); + phrlist = (PheaderInfo *)calloc(entries_2 + 1, sizeof(PheaderInfo)); + result->program_header_order = phrlist; + for ( j = 0; j < entries_2; j += 1 ) + { + switch ( arg[j].tkcode ) + { + case TC_STRING: + phrlist[j].sw = SRX_PH_TYPE_MOD; + phrlist[j].d.section_name = arg[j].value.lowtoken->str; + break; + case TC_VECTOR: + subarg = arg[j].value.subtree; + nseg = get_vector_len(subarg); + phrlist[j].sw = SRX_PH_TYPE_TEXT; + phrlist[j].d.segment_list = (SegConf **)calloc(nseg + 1, sizeof(SegConf *)); + for ( n = 0; n < nseg; n += 1 ) + { + phrlist[j].d.segment_list[n] = lookup_segment(result, subarg[n].value.lowtoken->str, 1); + if ( !phrlist[j].d.segment_list[n] ) + { + return 1; + } + } + break; + default: + break; + } + } + break; + case TC_CreateSymbols: + entries_3 = get_vector_len(arg); + result->create_symbols = (CreateSymbolConf *)calloc(entries_3 + 1, sizeof(CreateSymbolConf)); + for ( k = 0; k < entries_3; k += 1 ) + { + if ( arg[k].tkcode != TC_VECTOR || get_vector_len(arg[k].value.subtree) != 6 ) + { + fprintf(stderr, "unexcepted data in @CreateSymbols\n"); + return 1; + } + if ( setup_reserved_symbol_table(&result->create_symbols[k], arg[k].value.subtree, result) ) + { + return 1; + } + } + break; + default: + fprintf( + stderr, + "unexcepted data '%s' line:%d col=%d\n", + ttp->value.lowtoken->str, + ttp->value.lowtoken->line, + ttp->value.lowtoken->col); + return 1; + } + } + return 0; +} + +static void get_section_type_flag(TokenTree *ttp, int *rtype, int *rflag) +{ + int flag; + int type; + + type = 0; + flag = 0; + for ( ; ttp->tkcode; ttp += 1 ) + { + const char *info; + + info = ttp->value.lowtoken->str; + if ( !strcmp(info, "PROGBITS") ) + { + type = SHT_PROGBITS; + } + else if ( !strcmp(info, "NOBITS") ) + { + type = SHT_NOBITS; + } + else if ( !strcmp(info, "WRITE") ) + { + flag |= SHF_WRITE; + } + else if ( !strcmp(info, "ALLOC") ) + { + flag |= SHF_ALLOC; + } + else if ( !strcmp(info, "EXECINSTR") ) + { + flag |= SHF_EXECINSTR; + } + } + *rtype = type; + *rflag = flag; +} + +static elf_section *make_empty_section(const char *name, int type, int flag) +{ + elf_section *result; + + result = (elf_section *)calloc(1, sizeof(elf_section)); + result->name = strdup(name); + result->shr.sh_type = type; + result->shr.sh_flags = flag; + result->shr.sh_size = 0; + result->shr.sh_addralign = 4; + result->shr.sh_entsize = 0; + return result; +} + +static Srx_gen_table *make_srx_gen_table(TokenTree *tokentree) +{ + SegConf *seg_1; + SegConf *seg_2; + const SegConf *seg_3; + TokenTree *nttp; + TokenTree *ttp2_1; + TokenTree *ttp2_2; + TokenTree *ttp1; + TokenTree *ttp; + Srx_gen_table *result; + int sectflag; + int secttype; + unsigned int bitid; + int nsect; + const char **strp; + const char *str; + char *str2; + + result = (Srx_gen_table *)calloc(1, sizeof(Srx_gen_table)); + if ( tokentree->tkcode != TC_VECTOR ) + { + fprintf(stderr, "Internal error:make_srx_gen_table();\n"); + free(result); + return 0; + } + ttp = tokentree->value.subtree; + nsect = 0; + result->section_table_order = (const char **)calloc(1, sizeof(const char *)); + result->file_layout_order = (const char **)calloc(1, sizeof(const char *)); + result->removesection_list = (const char **)calloc(1, sizeof(const char *)); + result->section_list = (SectConf *)calloc(1, sizeof(SectConf)); + for ( ; ttp->tkcode; ) + { + if ( ttp[1].tkcode == TC_VECTOR ) + { + ttp1 = ttp[1].value.subtree; + nttp = ttp + 2; + } + else + { + ttp1 = 0; + nttp = ttp + 1; + } + switch ( ttp->tkcode ) + { + case TC_STRING: + str = ttp->value.lowtoken->str; + result->section_table_order = add_stringvector(result->section_table_order, str); + if ( !ttp1 ) + { + result->file_layout_order = add_stringvector(result->file_layout_order, str); + ttp = nttp; + break; + } + if ( ttp1->tkcode == TC_remove ) + { + result->removesection_list = add_stringvector(result->removesection_list, str); + ttp = nttp; + break; + } + if ( ttp1->tkcode == TC_segment && ttp1[1].tkcode == TC_VECTOR ) + { + bitid = 0; + for ( ttp2_1 = ttp1[1].value.subtree; ttp2_1->tkcode; ttp2_1 += 1 ) + { + seg_1 = lookup_segment(result, ttp2_1->value.lowtoken->str, 1); + if ( !seg_1 ) + { + return 0; + } + seg_1->sect_name_patterns = add_stringvector(seg_1->sect_name_patterns, str); + bitid |= seg_1->bitid; + } + if ( bitid ) + { + result->section_list[nsect].sect_name_pattern = str; + result->section_list[nsect].flag = bitid; + nsect += 1; + result->section_list = (SectConf *)realloc(result->section_list, (nsect + 1) * sizeof(SectConf)); + result->section_list[nsect].sect_name_pattern = 0; + result->section_list[nsect].flag = 0; + result->section_list[nsect].secttype = 0; + result->section_list[nsect].sectflag = 0; + } + if ( ttp1[2].tkcode != TC_createinfo || ttp1[3].tkcode != TC_VECTOR ) + { + ttp = nttp; + break; + } + get_section_type_flag(ttp1[3].value.subtree, §type, §flag); + if ( secttype && sectflag ) + { + if ( bitid ) + { + result->section_list[nsect - 1].secttype = secttype; + result->section_list[nsect - 1].sectflag = sectflag; + } + seg_2 = NULL; + for ( ttp2_2 = ttp1[1].value.subtree;; ttp2_2 += 1 ) + { + if ( ttp2_2->tkcode == TC_NULL ) + { + ttp = nttp; + break; + } + seg_2 = lookup_segment(result, ttp2_2->value.lowtoken->str, 1); + if ( !seg_2 ) + { + break; + } + if ( !seg_2->empty_section ) + { + seg_2->empty_section = make_empty_section(str, secttype, sectflag); + } + } + if ( !seg_2 ) + { + free(result); + return 0; + } + } + else + { + fprintf( + stderr, "Illegal @createinfo line:%d col=%d\n", ttp1->value.lowtoken->line, ttp1->value.lowtoken->col); + free(result); + return 0; + } + } + else + { + fprintf( + stderr, + "unexcepted data '%s' line:%d col=%d\n", + ttp1->value.lowtoken->str, + ttp1->value.lowtoken->line, + ttp1->value.lowtoken->col); + free(result); + return 0; + } + break; + case TC_IOP: + result->target = SRX_TARGET_IOP; + ttp = nttp; + break; + case TC_EE: + result->target = SRX_TARGET_EE; + ttp = nttp; + break; + case TC_Define: + if ( !ttp1 ) + { + fprintf( + stderr, + "argument not found for '%s' line:%d col=%d\n", + ttp->value.lowtoken->str, + ttp->value.lowtoken->line, + ttp->value.lowtoken->col); + free(result); + return 0; + } + if ( !gen_define(ttp1, result) ) + { + ttp = nttp; + break; + } + free(result); + return 0; + case TC_Program_header_data: + if ( !ttp1 || ttp1->tkcode != TC_STRING ) + { + if ( ttp1 ) + { + fprintf( + stderr, + "unexcepted data '%s' line:%d col=%d\n", + ttp1->value.lowtoken->str, + ttp1->value.lowtoken->line, + ttp1->value.lowtoken->col); + } + else + { + fprintf( + stderr, + "%s missing '{ }' line:%d col=%d\n", + ttp->value.lowtoken->str, + ttp->value.lowtoken->line, + ttp->value.lowtoken->col); + } + free(result); + return 0; + } + str2 = (char *)malloc(0x32); + sprintf(str2, "@Program_header_data %s", ttp1->value.lowtoken->str); + result->file_layout_order = add_stringvector(result->file_layout_order, str2); + ttp = nttp; + break; + case TC_Segment_data: + for ( ;; ) + { + if ( ttp1 != NULL && ttp1->tkcode == TC_NULL ) + { + ttp = nttp; + break; + } + if ( ttp1 != NULL ) + { + seg_3 = lookup_segment(result, ttp1->value.lowtoken->str, 1); + if ( seg_3 ) + { + for ( strp = seg_3->sect_name_patterns; *strp; strp += 1 ) + { + result->file_layout_order = add_stringvector(result->file_layout_order, *strp); + } + ttp1 += 1; + continue; + } + } + free(result); + return 0; + } + break; + case TC_Section_header_table: + result->file_layout_order = add_stringvector(result->file_layout_order, "@Section_header_table"); + ttp = nttp; + break; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" + case TC_VECTOR: + ttp = ttp->value.subtree; + default: + if ( ttp->value.lowtoken != NULL ) + { + fprintf( + stderr, + "unexcepted data '%s' line:%d col=%d\n", + ttp->value.lowtoken->str, + ttp->value.lowtoken->line, + ttp->value.lowtoken->col); + } + free(result); + return 0; +#pragma GCC diagnostic pop + } + } + switch ( result->target ) + { + case 1: + case 2: + return result; + default: + fprintf(stderr, "@IOP or @EE not found error !\n"); + free(result); + return 0; + } +} + +static void check_change_bit(unsigned int oldbit, unsigned int newbit, unsigned int *up, unsigned int *down) +{ + *up = ~oldbit & newbit & (newbit ^ oldbit); + *down = ~newbit & oldbit & (newbit ^ oldbit); +} + +static int check_srx_gen_table(Srx_gen_table *tp) +{ + SegConf *scnfp; + SectConf *sctp; + int nsegment; + int b; + int error; + unsigned int defbitid; + unsigned int downdelta; + unsigned int updelta; + unsigned int oldbitid; + + nsegment = 0; + for ( scnfp = tp->segment_list; scnfp && scnfp->name; scnfp += 1 ) + { + nsegment += 1; + } + defbitid = 0; + oldbitid = 0; + error = 0; + for ( sctp = tp->section_list; sctp->sect_name_pattern; sctp += 1 ) + { + check_change_bit(oldbitid, sctp->flag, &updelta, &downdelta); + if ( (defbitid & updelta) != 0 ) + { + error += 1; + for ( b = 0; b < nsegment; b += 1 ) + { + if ( (sctp->flag & (1 << b)) != 0 ) + { + fprintf(stderr, "Segment '%s' restart by section `%s`\n", tp->segment_list[b].name, sctp->sect_name_pattern); + break; + } + } + } + oldbitid = sctp->flag; + check_change_bit(oldbitid, sctp[1].flag, &updelta, &downdelta); + defbitid |= downdelta; + } + return error; +} diff --git a/tools/srxfixup/src/ring.c b/tools/srxfixup/src/ring.c new file mode 100644 index 00000000000..36778e8e4ad --- /dev/null +++ b/tools/srxfixup/src/ring.c @@ -0,0 +1,77 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "srxfixup_internal.h" + +SLink *add_ring_top(SLink *tailp, SLink *elementp) +{ + if ( !elementp ) + { + return tailp; + } + if ( tailp ) + { + elementp->next = tailp->next; + tailp->next = elementp; + } + else + { + tailp = elementp; + elementp->next = elementp; + } + return tailp; +} + +SLink *add_ring_tail(SLink *tailp, SLink *elementp) +{ + SLink *tailpa; + + tailpa = add_ring_top(tailp, elementp); + if ( !elementp ) + { + return tailpa; + } + if ( tailpa ) + { + return tailpa->next; + } + return 0; +} + +SLink *joint_ring(SLink *tailp, SLink *otherring) +{ + SLink *othertop; + + if ( !otherring ) + { + return tailp; + } + if ( !tailp ) + { + return otherring; + } + othertop = otherring->next; + otherring->next = tailp->next; + tailp->next = othertop; + return tailp; +} + +SLink *ring_to_liner(SLink *tailp) +{ + SLink *top; + + if ( !tailp ) + { + return 0; + } + top = tailp->next; + tailp->next = 0; + return top; +} diff --git a/tools/srxfixup/src/srxfixup.c b/tools/srxfixup/src/srxfixup.c new file mode 100644 index 00000000000..d26c8beaec8 --- /dev/null +++ b/tools/srxfixup/src/srxfixup.c @@ -0,0 +1,489 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "srxfixup_internal.h" +#include +#include +#include +#include + +static const char *conffile = NULL; +static const char *ofile = NULL; +static const char *rfile = NULL; +static const char *ffile = NULL; +static unsigned int startaddr; +static const char *entrysym = NULL; +static unsigned int verbose = 0; +static unsigned int dumpflag = 0; +static unsigned int dispmod_flag = 0; +static int irx1_flag = 0; +static int br_conv = 0; +static int print_config = 0; +// clang-format off +static const Opttable opttable[] = +{ + { "-v", ARG_HAVEARG_NONE, 'f', &verbose }, + { "-d", ARG_HAVEARG_NONE, 'f', &dumpflag }, + { "-r", ARG_HAVEARG_REQUIRED, 's', &rfile }, + { "-o", ARG_HAVEARG_REQUIRED, 's', &ofile }, + { "-c", ARG_HAVEARG_REQUIRED, 's', &conffile }, + { "-f", ARG_HAVEARG_REQUIRED, 's', &ffile }, + { "-t", ARG_HAVEARG_REQUIRED, 'h', &startaddr }, + { "-e", ARG_HAVEARG_REQUIRED, 's', &entrysym }, + { "-m", ARG_HAVEARG_NONE, 'f', &dispmod_flag }, + { "--irx1", ARG_HAVEARG_NONE, 'f', &irx1_flag }, + { "--rb", ARG_HAVEARG_NONE, 'f', &br_conv }, + { "--relative-branch", ARG_HAVEARG_NONE, 'f', &br_conv }, + { "--print-internal-config", ARG_HAVEARG_NONE, 'f', &print_config }, + { NULL, 0, '\0', NULL }, +}; +static const Opttable stripopttable[] = +{ + { "-v", ARG_HAVEARG_NONE, 'f', &verbose }, + { "-d", ARG_HAVEARG_NONE, 'f', &dumpflag }, + { "-o", ARG_HAVEARG_REQUIRED, 's', &ofile }, + { "-c", ARG_HAVEARG_REQUIRED, 's', &conffile }, + { "-e", ARG_HAVEARG_REQUIRED, 's', &entrysym }, + { "-m", ARG_HAVEARG_NONE, 'f', &dispmod_flag }, + { "--irx1", ARG_HAVEARG_NONE, 'f', &irx1_flag }, + { "--rb", ARG_HAVEARG_NONE, 'f', &br_conv }, + { "--relative-branch", ARG_HAVEARG_NONE, 'f', &br_conv }, + { "--print-internal-config", ARG_HAVEARG_NONE, 'f', &print_config }, + { NULL, 0, '\0', NULL }, +}; +// clang-format on + +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); + +void usage(const char *myname) +{ + printf( + "IOP/EE relocatable object converter\n" + "%s\n" + "usage: %s [options] \n", + myname, + myname); + printf(" options:\n" + " -v\n" + " -m\n" + " --irx1\n" + " -o \n" + " -r \n" + " -e \n" + " --relative-branch or --rb\n"); + if ( verbose ) + { + printf(" -t <.text start address>\n" + " -f \n" + " -d\n" + " hex_flag bits:\n" + " bit0: dump section table\n" + " bit1: dump relocation record\n" + " bit2: dump symbol table\n" + " bit3: disassemble program code\n" + " bit4: dump .data/.rodata/.sdata... sections by byte\n" + " bit5: dump .data/.rodata/.sdata... sections by half word\n" + " bit6: dump .data/.rodata/.sdata... sections by word\n" + " bit7: dump .data/.rodata/.sdata... sections by word with relocation data\n" + " bit8: dump file layout\n" + " bit9: dump .mdebug section\n"); + } + if ( verbose > 1 ) + { + printf(" bit12: dump srx genaration table\n" + " -c \n" + " --print-internal-config\n"); + } +} + +void stripusage(const char *myname) +{ + printf( + "%s\n" + "usage: %s [options] \n", + myname, + myname); + printf(" options:\n" + " -v\n" + " -m\n" + " -o \n" + " --relative-branch or --rb\n"); +} + +int main(int argc, char **argv) +{ + Srx_gen_table *srxgen_1; + const char *defaultconf; + elf_file *elf; + const char *myname_1; + const char *myname_2; + const char *source; + + myname_1 = strrchr(*argv, '/'); + if ( !myname_1 ) + { + myname_1 = strrchr(*argv, '\\'); + } + if ( myname_1 ) + { + myname_2 = myname_1 + 1; + } + else + { + myname_2 = *argv; + } + if ( (strncmp(myname_2, "ee", 2) != 0) && (strncmp(myname_2, "EE", 2) != 0) ) + { + defaultconf = iop_defaultconf; + } + else + { + defaultconf = ee_defaultconf; + } + if ( strlen(*argv) > 5 && !strcmp(&(*argv)[strlen(*argv) - 5], "strip") ) + { + int argca; + + argca = analize_arguments(stripopttable, argc, argv); + if ( argca != 2 ) + { + Srx_gen_table *srxgen_2; + + srxgen_2 = read_conf(defaultconf, conffile, print_config); + if ( !srxgen_2 ) + { + exit(1); + } + if ( (dumpflag & 0x1000) != 0 ) + { + dump_srx_gen_table(srxgen_2); + exit(0); + } + } + if ( argca <= 1 ) + { + stripusage(*argv); + exit(1); + } + if ( argca > 2 ) + { + fprintf(stderr, "Too many input file\n"); + stripusage(*argv); + exit(1); + } + if ( !ofile ) + { + ofile = argv[1]; + } + } + else + { + int argcb; + + argcb = analize_arguments(opttable, argc, argv); + if ( argcb != 2 ) + { + Srx_gen_table *srxgen_3; + + srxgen_3 = read_conf(defaultconf, conffile, print_config); + if ( !srxgen_3 ) + { + exit(1); + } + if ( (dumpflag & 0x1000) != 0 ) + { + dump_srx_gen_table(srxgen_3); + exit(0); + } + } + if ( argcb <= 1 ) + { + usage(*argv); + exit(1); + } + if ( argcb > 2 ) + { + fprintf(stderr, "Too many input file\n"); + usage(*argv); + exit(1); + } + } + source = argv[1]; + elf = read_elf(source); + if ( !elf ) + { + exit(1); + } + if ( + ((elf->ehp->e_flags & EF_MIPS_MACH) == EF_MIPS_MACH_5900) + && ((elf->ehp->e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_3) ) + { + srxgen_1 = read_conf(ee_defaultconf, conffile, print_config); + } + else + { + srxgen_1 = read_conf(iop_defaultconf, conffile, print_config); + } + if ( !srxgen_1 ) + { + exit(1); + } + if ( (dumpflag & 0x1000) != 0 ) + { + dump_srx_gen_table(srxgen_1); + exit(0); + } + if ( (dumpflag & 0xFFF) != 0 ) + { + print_elf(elf, dumpflag & 0xFFF); + exit(0); + } + elf->optdata = (void *)srxgen_1; + switch ( elf->ehp->e_type ) + { + case ET_REL: + if ( convert_rel2srx(elf, entrysym, (rfile || ofile || ffile) ? 1 : 0, irx1_flag) ) + { + exit(1); + } + break; + case ET_SCE_IOPRELEXEC: + case ET_SCE_IOPRELEXEC2: + case ET_SCE_EERELEXEC2: + case ET_EXEC: + break; + default: + fprintf(stderr, "Error: '%s' is unsupport Type Elf file(type=%x)\n", source, elf->ehp->e_type); + exit(1); + break; + } + if ( dispmod_flag ) + { + display_module_info(elf); + } + switch ( elf->ehp->e_type ) + { + case ET_SCE_IOPRELEXEC: + case ET_SCE_IOPRELEXEC2: + case ET_SCE_EERELEXEC2: + if ( br_conv ) + { + convert_relative_branch(elf); + } + if ( rfile ) + { + if ( layout_srx_file(elf) ) + { + exit(1); + } + write_elf(elf, rfile); + } + if ( ofile ) + { + strip_elf(elf); + if ( layout_srx_file(elf) ) + { + exit(1); + } + write_elf(elf, ofile); + } + break; + default: + if ( rfile || ofile ) + { + fprintf(stderr, "Error: Cannot generate IRX/ERX file. '%s' file type is ET_EXEC.\n", source); + exit(1); + } + break; + } + if ( ffile || startaddr != (unsigned int)(-1) ) + { + switch ( elf->ehp->e_type ) + { + case ET_SCE_IOPRELEXEC: + case ET_SCE_IOPRELEXEC2: + case ET_SCE_EERELEXEC2: + elf->ehp->e_type = ET_EXEC; + fixlocation_elf(elf, startaddr); + break; + default: + break; + } + if ( ffile ) + { + if ( layout_srx_file(elf) ) + { + exit(1); + } + write_elf(elf, ffile); + } + } + return 0; +} + +static void display_module_info(elf_file *elf) +{ + elf_section *modsect_1; + elf_section *modsect_2; + + modsect_1 = search_section(elf, SHT_SCE_IOPMOD); + if ( modsect_1 ) + { + const Elf32_IopMod *iopmodinfo; + + iopmodinfo = (Elf32_IopMod *)modsect_1->data; + if ( iopmodinfo->moduleinfo != (Elf32_Word)(-1) ) + { + printf( + "name:%s version:%d.%d\n", + iopmodinfo->modulename, + (uint8_t)(iopmodinfo->moduleversion >> 24), + (uint8_t)iopmodinfo->moduleversion); + } + } + modsect_2 = search_section(elf, SHT_SCE_EEMOD); + if ( modsect_2 ) + { + const Elf32_EeMod *eemodinfo; + + eemodinfo = (Elf32_EeMod *)modsect_2->data; + if ( eemodinfo->moduleinfo != (Elf32_Word)(-1) ) + { + printf( + "name:%s version:%d.%d\n", + eemodinfo->modulename, + (uint8_t)(eemodinfo->moduleversion >> 24), + (uint8_t)eemodinfo->moduleversion); + } + } +} + +static void convert_relative_branch_an_section(elf_section *relsect) +{ + elf_syment **symp; + elf_rel *rp; + int rmcount; + unsigned int entrise; + unsigned int i; + + entrise = relsect->shr.sh_size / relsect->shr.sh_entsize; + rp = (elf_rel *)relsect->data; + symp = (elf_syment **)relsect->link->data; + rmcount = 0; + for ( i = 0; i < entrise; i += 1 ) + { + unsigned int type; + uint8_t *daddr; + + if ( rp->symptr && *symp != rp->symptr ) + { + fprintf(stderr, "Internal error: Illegal relocation entry\n"); + exit(1); + } + if ( + relsect->info->shr.sh_addr > rp->rel.r_offset + || rp->rel.r_offset >= relsect->info->shr.sh_size + relsect->info->shr.sh_addr ) + { + fprintf( + stderr, + "Panic !! relocation #%u offset=0x%x range out (section limit addr=0x%x-0x%x)\n", + i, + rp->rel.r_offset, + relsect->info->shr.sh_addr, + relsect->info->shr.sh_size + relsect->info->shr.sh_addr); + exit(1); + } + daddr = &relsect->info->data[rp->rel.r_offset - relsect->info->shr.sh_addr]; + type = rp->type; + if ( type ) + { + if ( type == R_MIPS_26 ) + { + uint32_t raddr; + unsigned int data; + + data = *(uint32_t *)daddr; + if ( rp->symptr && rp->symptr->bind != STB_LOCAL ) + { + fprintf(stderr, "R_MIPS_26 Unexcepted bind\n"); + exit(1); + } + raddr = rp->rel.r_offset + relsect->info->shr.sh_addr; + if ( + !((((rp->rel.r_offset & 0xF0000000) | (4 * (data & 0x3FFFFFF))) - 4 - raddr) >> 18) + || (((rp->rel.r_offset & 0xF0000000) | (4 * (data & 0x3FFFFFF))) - 4 - raddr) >> 18 == 0x3FFF ) + { + int jaddr; + + jaddr = (uint16_t)((((rp->rel.r_offset & 0xF0000000) | (4 * (data & 0x3FFFFFF))) - 4 - raddr) >> 2); + if ( data >> 26 == 2 ) + { + *(uint32_t *)daddr = jaddr | 0x10000000; + rp->type = R_MIPS_NONE; + rmcount += 1; + } + else if ( data >> 26 == 3 ) + { + *(uint32_t *)daddr = jaddr | 0x4110000; + rp->type = R_MIPS_NONE; + rmcount += 1; + } + } + } + } + else + { + rmcount += 1; + } + rp += 1; + } + if ( rmcount > 0 && (entrise - rmcount) > 0 ) + { + elf_rel *s; + elf_rel *d; + elf_rel *newtab; + unsigned int j; + + newtab = (elf_rel *)calloc(entrise - rmcount, sizeof(elf_rel)); + d = newtab; + s = (elf_rel *)relsect->data; + for ( j = 0; j < entrise; j += 1 ) + { + if ( s->type ) + { + memcpy(d, s, sizeof(elf_rel)); + d += 1; + } + s += 1; + } + free(relsect->data); + relsect->data = (uint8_t *)newtab; + relsect->shr.sh_size = relsect->shr.sh_entsize * (entrise - rmcount); + } +} + +static void convert_relative_branch(elf_file *elf) +{ + int i; + + if ( elf->scp == NULL ) + { + return; + } + for ( i = 1; i < elf->ehp->e_shnum; i += 1 ) + { + if ( elf->scp[i]->shr.sh_type == SHT_REL ) + { + convert_relative_branch_an_section(elf->scp[i]); + } + } +} diff --git a/tools/srxfixup/src/srxfixup_internal.h b/tools/srxfixup/src/srxfixup_internal.h new file mode 100644 index 00000000000..90f05bc43f9 --- /dev/null +++ b/tools/srxfixup/src/srxfixup_internal.h @@ -0,0 +1,946 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#ifndef __SRXFIXUP_INTERNAL_H__ +#define __SRXFIXUP_INTERNAL_H__ + +#include + +// Type definitions + +// srxfixup.c, elflib.c, elfdump.c, srxgen.c, readconf.c + +typedef short unsigned int Elf32_Half; +typedef unsigned int Elf32_Addr; +typedef unsigned int Elf32_Off; +typedef unsigned int Elf32_Word; +typedef int Elf32_SWord; +typedef struct _Elf32_ehdr +{ + unsigned char e_ident[16]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; +typedef struct _Elf32_Phdr +{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; +typedef struct _Elf32_Shdr +{ + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; +typedef struct _Elf32_Sym +{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} Elf32_Sym; +typedef struct _Elf_Note +{ + Elf32_Word namesz; + Elf32_Word descsz; + Elf32_Word type; + char name[]; +} Elf_Note; +typedef struct _Elf32_Rel +{ + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; +typedef struct _Elf32_RegInfo +{ + Elf32_Word ri_gprmask; + Elf32_Word ri_cprmask[4]; + Elf32_SWord ri_gp_value; +} Elf32_RegInfo; +typedef struct _Elf32_IopMod +{ + Elf32_Word moduleinfo; + Elf32_Addr entry; + Elf32_Addr gp_value; + Elf32_Word text_size; + Elf32_Word data_size; + Elf32_Word bss_size; + Elf32_Half moduleversion; + char modulename[]; +} Elf32_IopMod; +typedef struct _Elf32_EeMod +{ + Elf32_Word moduleinfo; + Elf32_Addr entry; + Elf32_Addr gp_value; + Elf32_Word text_size; + Elf32_Word data_size; + Elf32_Word bss_size; + Elf32_Addr erx_lib_addr; + Elf32_Word erx_lib_size; + Elf32_Addr erx_stub_addr; + Elf32_Word erx_stub_size; + Elf32_Half moduleversion; + char modulename[]; +} Elf32_EeMod; +typedef struct _hdrr +{ + short int magic; + short int vstamp; + unsigned int ilineMax; + unsigned int cbLine; + unsigned int cbLineOffset; + unsigned int idnMax; + unsigned int cbDnOffset; + unsigned int ipdMax; + unsigned int cbPdOffset; + unsigned int isymMax; + unsigned int cbSymOffset; + unsigned int ioptMax; + unsigned int cbOptOffset; + unsigned int iauxMax; + unsigned int cbAuxOffset; + unsigned int issMax; + unsigned int cbSsOffset; + unsigned int issExtMax; + unsigned int cbSsExtOffset; + unsigned int ifdMax; + unsigned int cbFdOffset; + unsigned int crfd; + unsigned int cbRfdOffset; + unsigned int iextMax; + unsigned int cbExtOffset; +} hdrr; +typedef struct _fdr +{ + unsigned int adr; + int rss; + int issBase; + int cbSs; + int isymBase; + int csym; + int ilineBase; + int cline; + int ioptBase; + int copt; + short unsigned int ipdFirst; + short int cpd; + int iauxBase; + int caux; + int rfdBase; + int crfd; + unsigned int fdr_bits; + int cbLineOffset; + int cbLine; +} fdr; +typedef struct _symr +{ + int iss; + int value; + unsigned int sy_bits; +} symr; +typedef struct _extr +{ + short int reserved; + short int ifd; + symr asym; +} extr; +typedef struct _dnr +{ + unsigned int d_rfd; + unsigned int d_index; +} dnr; +typedef struct _pdr +{ + unsigned int adr; + int isym; + int iline; + int regmask; + int regoffset; + int iopt; + int fregmask; + int fregoffset; + int frameoffset; + short int framereg; + short int pcreg; + int lnLow; + int lnHigh; + unsigned int cbLineOffset; +} pdr; +typedef struct _tir +{ + unsigned int fBitfield; + unsigned int continued; + unsigned int bt; + unsigned int tq4; + unsigned int tq5; + unsigned int tq0; + unsigned int tq1; + unsigned int tq2; + unsigned int tq3; +} tir; +typedef struct _rndxr +{ + unsigned int rfd; + unsigned int index; +} rndxr; +typedef union _auxu +{ + tir ti; + rndxr rndx; + int dnLow; + int dnHigh; + int isym; + int iss; + int width; + int count; +} auxu; +typedef struct _optr +{ + unsigned int optr_bits; + rndxr rndx; + unsigned int offset; +} optr; +typedef int rfdt; +typedef struct _elf_mips_symbolic +{ + hdrr head; + char *cbLine_Ptr; + char *cbDn_Ptr; + char *cbPd_Ptr; + char *cbSym_Ptr; + char *cbOpt_Ptr; + char *cbAux_Ptr; + char *cbSs_Ptr; + char *cbSsExt_Ptr; + char *cbFd_Ptr; + char *cbRfd_Ptr; + char *cbExt_Ptr; +} elf_mips_symbolic_data; +typedef struct _elf_section +{ + Elf32_Shdr shr; + uint8_t *data; + const char *name; + unsigned int number; + struct _elf_section *link; + struct _elf_section *info; + void *optdata; +} elf_section; +typedef struct _syment +{ + Elf32_Sym sym; + const char *name; + unsigned int number; + int bind; + unsigned int type; + elf_section *shptr; + int refcount; +} elf_syment; +typedef struct _rel +{ + Elf32_Rel rel; + elf_syment *symptr; + unsigned int type; +} elf_rel; +typedef struct _elf_proghead +{ + Elf32_Phdr phdr; + elf_section **scp; + void *optdata; // Not used +} elf_proghead; +typedef struct _elffile +{ + Elf32_Ehdr *ehp; + elf_section *shstrptr; + elf_proghead *php; + elf_section **scp; + void *optdata; +} elf_file; + +// elflib.c, elfdump.c, srxgen.c + +typedef struct _elf_file_slot +{ + unsigned int offset; + unsigned int size; + unsigned int align; + int type; + union _elf_file_slot_d + { + elf_proghead *php; + elf_section *scp; + } d; +} Elf_file_slot; + +// readconf.c, srxfixup.c, srxgen.c + +typedef struct _segconf +{ + const char *name; + int bitid; + const char **sect_name_patterns; + elf_section *empty_section; + int nsect; + elf_section **scp; + unsigned int addr; + unsigned int size; +} SegConf; +typedef struct _pheader_info +{ + int sw; + union _pheader_info_d + { + const char *section_name; + SegConf **segment_list; + } d; +} PheaderInfo; +typedef struct _sectconf +{ + const char *sect_name_pattern; + unsigned int flag; + int secttype; + int sectflag; +} SectConf; +typedef struct _crtsymconf +{ + const char *name; + int bind; + int type; + SegConf *segment; + const char *sectname; + int shindex; + int seflag; +} CreateSymbolConf; +typedef struct _srx_gen_table +{ + int target; + SegConf *segment_list; + CreateSymbolConf *create_symbols; + PheaderInfo *program_header_order; + SectConf *section_list; + const char **removesection_list; + const char **section_table_order; + const char **file_layout_order; +} Srx_gen_table; + +// anaarg.c, srxfixup.c + +typedef struct _opt_strings +{ + struct _opt_strings *next; + const char *string; +} Opt_strings; +typedef struct _opttable +{ + const char *option; + int havearg; + char vartype; + void *var; +} Opttable; + +// ring.c, anaarg.c, srxfixup.c + +typedef struct _slink +{ + struct _slink *next; +} SLink; + +// mipsdis.c, elfdump.c + +typedef enum OperandTag +{ + OprTag_none = 0, + OprTag_reg = 1, + OprTag_c0reg_iop = 2, + OprTag_c0reg_ee = 3, + OprTag_czreg = 4, + OprTag_c1reg = 5, + OprTag_imm = 6, + OprTag_shamt = 7, + OprTag_jtarget = 8, + OprTag_regoffset = 9, + OprTag_code20 = 10, + OprTag_code25 = 11 +} OperandTag; +typedef struct operand +{ + enum OperandTag tag; + unsigned char reg; + unsigned int data; +} Operand; +typedef struct disasm_result +{ + unsigned int addr; + unsigned int data; + char mnemonic[16]; + Operand operands[4]; +} Disasm_result; + +// Function definitions + +// anaarg.c +extern int analize_arguments(const Opttable *dopttable, int argc, char **argv); + +// elfdump.c +extern void print_elf(const elf_file *elf, unsigned int flag); +extern void print_elf_ehdr(const elf_file *elf, unsigned int flag); +extern void print_elf_phdr(const elf_file *elf, unsigned int flag); +extern void print_elf_sections(const elf_file *elf, unsigned int flag); +extern void print_elf_reloc(const elf_section *scp, unsigned int flag); +extern void print_elf_disasm(const elf_file *elf, const elf_section *scp, unsigned int flag); +extern void print_elf_datadump(const elf_file *elf, const elf_section *scp, unsigned int flag); +extern void print_elf_symtbl(const elf_section *scp, unsigned int flag); +extern void print_elf_mips_symbols(const elf_mips_symbolic_data *symbol, unsigned int flag); + +// elflib.c +extern elf_file *read_elf(const char *filename); +extern int layout_elf_file(elf_file *elf); +extern int write_elf(elf_file *elf, const char *filename); +extern void add_section(elf_file *elf, elf_section *scp); +extern elf_section *remove_section(elf_file *elf, Elf32_Word shtype); +extern elf_section *remove_section_by_name(elf_file *elf, const char *secname); +extern elf_section *search_section(elf_file *elf, Elf32_Word stype); +extern elf_section *search_section_by_name(elf_file *elf, const char *secname); +extern unsigned int *get_section_data(elf_file *elf, unsigned int addr); +extern elf_syment *search_global_symbol(const char *name, elf_file *elf); +extern int is_defined_symbol(const elf_syment *sym); +extern elf_syment * +add_symbol(elf_file *elf, const char *name, int bind, int type, int value, elf_section *scp, int st_shndx); +extern unsigned int get_symbol_value(const elf_syment *sym, const elf_file *elf); +extern void reorder_symtab(elf_file *elf); +extern unsigned int adjust_align(unsigned int value, unsigned int align); +extern void rebuild_section_name_strings(elf_file *elf); +extern void rebuild_symbol_name_strings(elf_file *elf); +extern Elf_file_slot *build_file_order_list(const elf_file *elf); +extern void shrink_file_order_list(Elf_file_slot *efs); +extern void writeback_file_order_list(elf_file *elf, Elf_file_slot *efs); +extern void dump_file_order_list(const elf_file *elf, const Elf_file_slot *efs); + +// mipsdis.c +extern void gen_asmmacro(Disasm_result *result); +extern void initdisasm(int arch, int regform0, int regform1, int regform2, int regform3); +extern Disasm_result *disassemble(unsigned int addr, unsigned int data); +extern void shex(char *buf, unsigned int data); +extern void format_operand(const Operand *opr, char *buf); +extern void format_disasm(Disasm_result *dis, char *buf); + +// readconf.c +extern Srx_gen_table *read_conf(const char *indata, const char *infile, int dumpopt); + +// ring.c +extern SLink *add_ring_top(SLink *tailp, SLink *elementp); +extern SLink *add_ring_tail(SLink *tailp, SLink *elementp); +extern SLink *joint_ring(SLink *tailp, SLink *otherring); +extern SLink *ring_to_liner(SLink *tailp); + +// srxfixup.c +extern void usage(const char *myname); +extern void stripusage(const char *myname); + +// srxgen.c +extern int convert_rel2srx(elf_file *elf, const char *entrysym, int needoutput, int cause_irx1); +extern int layout_srx_file(elf_file *elf); +extern void strip_elf(elf_file *elf); +extern SegConf *lookup_segment(Srx_gen_table *conf, const char *segname, int msgsw); +extern void fixlocation_elf(elf_file *elf, unsigned int startaddr); +extern int relocation_is_version2(elf_section *relsect); +extern void dump_srx_gen_table(Srx_gen_table *tp); + +// swapmem.c +extern void swapmemory(void *aaddr, const char *format, unsigned int times); + +// eefixconf.c +extern const char *ee_defaultconf; + +// iopfixconf.c +extern const char *iop_defaultconf; + +enum Ei_class_name_enum +{ + ELFCLASSNONE = 0, + ELFCLASS32 = 1, + ELFCLASS64 = 2, +}; + +#define XEACH_Ei_class_name_enum() \ + X(ELFCLASSNONE) \ + X(ELFCLASS32) \ + X(ELFCLASS64) + +enum E_type_name_enum +{ + ET_NONE = 0, + ET_REL = 1, + ET_EXEC = 2, + ET_DYN = 3, + ET_CORE = 4, + ET_SCE_IOPRELEXEC = 0xFF80, + ET_SCE_IOPRELEXEC2 = 0xFF81, + ET_SCE_EERELEXEC = 0xFF90, + ET_SCE_EERELEXEC2 = 0xFF91, +}; + +#define XEACH_E_type_name_enum() \ + X(ET_NONE) \ + X(ET_REL) \ + X(ET_EXEC) \ + X(ET_DYN) \ + X(ET_CORE) \ + X(ET_SCE_IOPRELEXEC) \ + X(ET_SCE_IOPRELEXEC2) \ + X(ET_SCE_EERELEXEC) \ + X(ET_SCE_EERELEXEC2) + +enum Ei_data_name_enum +{ + ELFDATANONE = 0, + ELFDATA2LSB = 1, + ELFDATA2MSB = 2, +}; + +#define XEACH_Ei_data_name_enum() \ + X(ELFDATANONE) \ + X(ELFDATA2LSB) \ + X(ELFDATA2MSB) + +enum E_version_name_enum +{ + EV_NONE = 0, + EV_CURRENT = 1, +}; + +#define XEACH_E_version_name_enum() \ + X(EV_NONE) \ + X(EV_CURRENT) + +enum E_machine_name_enum +{ + EM_NONE = 0, + EM_M32 = 1, + EM_SPARC = 2, + EM_386 = 3, + EM_68K = 4, + EM_88K = 5, + EM_860 = 7, + EM_MIPS = 8, + EM_MIPS_RS4_BE = 10, + EM_SPARC64 = 11, + EM_PARISC = 15, + EM_SPARC32PLUS = 18, + EM_PPC = 20, + EM_SH = 42, +}; + +#define XEACH_E_machine_name_enum() \ + X(EM_NONE) \ + X(EM_M32) \ + X(EM_SPARC) \ + X(EM_386) \ + X(EM_68K) \ + X(EM_88K) \ + X(EM_860) \ + X(EM_MIPS) \ + X(EM_MIPS_RS4_BE) \ + X(EM_SPARC64) \ + X(EM_PARISC) \ + X(EM_SPARC32PLUS) \ + X(EM_PPC) \ + X(EM_SH) + +enum P_type_name_enum +{ + PT_NULL = 0, + PT_LOAD = 1, + PT_DYNAMIC = 2, + PT_INTERP = 3, + PT_NOTE = 4, + PT_SHLIB = 5, + PT_PHDR = 6, + PT_MIPS_REGINFO = 0x70000000, + PT_MIPS_RTPROC = 0x70000001, + PT_SCE_IOPMOD = 0x70000080, + PT_SCE_EEMOD = 0x70000090, +}; + +#define XEACH_P_type_name_enum() \ + X(PT_NULL) \ + X(PT_LOAD) \ + X(PT_DYNAMIC) \ + X(PT_INTERP) \ + X(PT_NOTE) \ + X(PT_SHLIB) \ + X(PT_PHDR) \ + X(PT_MIPS_REGINFO) \ + X(PT_MIPS_RTPROC) \ + X(PT_SCE_IOPMOD) \ + X(PT_SCE_EEMOD) + +enum S_type_name_enum +{ + SHT_NULL = 0, + SHT_PROGBITS = 1, + SHT_SYMTAB = 2, + SHT_STRTAB = 3, + SHT_RELA = 4, + SHT_HASH = 5, + SHT_DYNAMIC = 6, + SHT_NOTE = 7, + SHT_NOBITS = 8, + SHT_REL = 9, + SHT_SHLIB = 10, + SHT_DYNSYM = 11, + SHT_MIPS_LIBLIST = 0x70000000, + SHT_MIPS_CONFLICT = 0x70000002, + SHT_MIPS_GPTAB = 0x70000003, + SHT_MIPS_UCODE = 0x70000004, + SHT_MIPS_DEBUG = 0x70000005, + SHT_MIPS_REGINFO = 0x70000006, + SHT_SCE_IOPMOD = 0x70000080, + SHT_SCE_EEMOD = 0x70000090, +}; + +#define XEACH_S_type_name_enum() \ + X(SHT_NULL) \ + X(SHT_PROGBITS) \ + X(SHT_SYMTAB) \ + X(SHT_STRTAB) \ + X(SHT_RELA) \ + X(SHT_HASH) \ + X(SHT_DYNAMIC) \ + X(SHT_NOTE) \ + X(SHT_NOBITS) \ + X(SHT_REL) \ + X(SHT_SHLIB) \ + X(SHT_DYNSYM) \ + X(SHT_MIPS_LIBLIST) \ + X(SHT_MIPS_CONFLICT) \ + X(SHT_MIPS_GPTAB) \ + X(SHT_MIPS_UCODE) \ + X(SHT_MIPS_DEBUG) \ + X(SHT_MIPS_REGINFO) \ + X(SHT_SCE_IOPMOD) \ + X(SHT_SCE_EEMOD) + +enum R_MIPS_Type_enum +{ + R_MIPS_NONE = 0, + R_MIPS_16 = 1, + R_MIPS_32 = 2, + R_MIPS_REL32 = 3, + R_MIPS_26 = 4, + R_MIPS_HI16 = 5, + R_MIPS_LO16 = 6, + R_MIPS_GPREL16 = 7, + R_MIPS_LITERAL = 8, + R_MIPS_GOT16 = 9, + R_MIPS_PC16 = 10, + R_MIPS_CALL16 = 11, + R_MIPS_GPREL32 = 12, + R_MIPS_GOTHI16 = 21, + R_MIPS_GOTLO16 = 22, + R_MIPS_CALLHI16 = 30, + R_MIPS_CALLLO16 = 31, + R_MIPS_DVP_11_PCREL = 120, + R_MIPS_DVP_27_S4 = 121, + R_MIPS_DVP_11_S4 = 122, + R_MIPS_DVP_U15_S3 = 123, + R_MIPSSCE_MHI16 = 250, + R_MIPSSCE_ADDEND = 251, +}; + +#define XEACH_R_MIPS_Type_enum() \ + X(R_MIPS_NONE) \ + X(R_MIPS_16) \ + X(R_MIPS_32) \ + X(R_MIPS_REL32) \ + X(R_MIPS_26) \ + X(R_MIPS_HI16) \ + X(R_MIPS_LO16) \ + X(R_MIPS_GPREL16) \ + X(R_MIPS_LITERAL) \ + X(R_MIPS_GOT16) \ + X(R_MIPS_PC16) \ + X(R_MIPS_CALL16) \ + X(R_MIPS_GPREL32) \ + X(R_MIPS_GOTHI16) \ + X(R_MIPS_GOTLO16) \ + X(R_MIPS_CALLHI16) \ + X(R_MIPS_CALLLO16) \ + X(R_MIPS_DVP_11_PCREL) \ + X(R_MIPS_DVP_27_S4) \ + X(R_MIPS_DVP_11_S4) \ + X(R_MIPS_DVP_U15_S3) \ + X(R_MIPSSCE_MHI16) \ + X(R_MIPSSCE_ADDEND) + +enum SymbolBinding_enum +{ + STB_LOCAL = 0, + STB_GLOBAL = 1, + STB_WEAK = 2, +}; + +#define XEACH_SymbolBinding_enum() \ + X(STB_LOCAL) \ + X(STB_GLOBAL) \ + X(STB_WEAK) + +enum SymbolType_enum +{ + STT_NOTYPE = 0, + STT_OBJECT = 1, + STT_FUNC = 2, + STT_SECTION = 3, + STT_FILE = 4, +}; + +#define XEACH_SymbolType_enum() \ + X(STT_NOTYPE) \ + X(STT_OBJECT) \ + X(STT_FUNC) \ + X(STT_SECTION) \ + X(STT_FILE) + +enum SymbolSpSection_enum +{ + SHN_UNDEF = 0, + SHN_MIPS_ACOMMON = 0xFF00, + SHN_MIPS_TEXT = 0xFF01, + SHN_MIPS_DATA = 0xFF02, + SHN_MIPS_SCOMMON = 0xFF03, + SHN_MIPS_SUNDEFINED = 0xFF04, + SHN_RADDR = 0xFF1F, + SHN_ABS = 0xFFF1, + SHN_COMMON = 0xFFF2, +}; + +#define XEACH_SymbolSpSection_enum() \ + X(SHN_UNDEF) \ + X(SHN_MIPS_ACOMMON) \ + X(SHN_MIPS_TEXT) \ + X(SHN_MIPS_DATA) \ + X(SHN_MIPS_SCOMMON) \ + X(SHN_MIPS_SUNDEFINED) \ + X(SHN_RADDR) \ + X(SHN_ABS) \ + X(SHN_COMMON) + +enum SymbolTypes_enum +{ + stNil = 0, + stGlobal = 1, + stStatic = 2, + stParam = 3, + stLocal = 4, + stLabel = 5, + stProc = 6, + stBlock = 7, + stEnd = 8, + stMember = 9, + stTypedef = 10, + stFile = 11, + stRegReloc = 12, + stForward = 13, + stStaticProc = 14, + stConstant = 15, + stStaParam = 16, + stStruct = 26, + stUnion = 27, + stEnum = 28, + stIndirect = 34, + stStr = 60, + stNumber = 61, + stExpr = 62, + stType = 63, + stMax = 64, +}; + +#define XEACH_SymbolTypes_enum() \ + X(stNil) \ + X(stGlobal) \ + X(stStatic) \ + X(stParam) \ + X(stLocal) \ + X(stLabel) \ + X(stProc) \ + X(stBlock) \ + X(stEnd) \ + X(stMember) \ + X(stTypedef) \ + X(stFile) \ + X(stRegReloc) \ + X(stForward) \ + X(stStaticProc) \ + X(stConstant) \ + X(stStaParam) \ + X(stStruct) \ + X(stUnion) \ + X(stEnum) \ + X(stIndirect) \ + X(stStr) \ + X(stNumber) \ + X(stExpr) \ + X(stType) \ + X(stMax) + +enum StorageClasse_enum +{ + scNil = 0, + scText = 1, + scData = 2, + scBss = 3, + scRegister = 4, + scAbs = 5, + scUndef = 6, + scUndefined = 6, + scCdbLocal = 7, + scBits = 8, + scCdbSystem = 9, + scDbx = 9, + scRegImage = 10, + scInfo = 11, + scUserStruct = 12, + scSData = 13, + scSBss = 14, + scRData = 15, + scVar = 16, + scCommon = 17, + scSCommon = 18, + scVarRegister = 19, + scVariant = 20, + scSUndefined = 21, + scInit = 22, + scBasedVar = 23, + scXData = 24, + scPData = 25, + scFini = 26, + scRConst = 27, + scMax = 32, +}; + +#define XEACH_StorageClasse_enum() \ + X(scNil) \ + X(scText) \ + X(scData) \ + X(scBss) \ + X(scRegister) \ + X(scAbs) \ + X(scUndef) \ + X(scUndefined) \ + X(scCdbLocal) \ + X(scBits) \ + X(scCdbSystem) \ + X(scDbx) \ + X(scRegImage) \ + X(scInfo) \ + X(scUserStruct) \ + X(scSData) \ + X(scSBss) \ + X(scRData) \ + X(scVar) \ + X(scCommon) \ + X(scSCommon) \ + X(scVarRegister) \ + X(scVariant) \ + X(scSUndefined) \ + X(scInit) \ + X(scBasedVar) \ + X(scXData) \ + X(scPData) \ + X(scFini) \ + X(scRConst) \ + X(scMax) + +enum elf_header_flags +{ + EF_MIPS_NOREORDER = 1, + EF_MIPS_PIC = 2, + EF_MIPS_CPIC = 4, + EF_MIPS_MACH = 0x00FF0000, + EF_MIPS_MACH_5900 = 0x00920000, + EF_MIPS_ARCH_3 = 0x20000000, + EF_MIPS_ARCH = 0xF0000000, +}; + +enum elf_program_header_flags +{ + PF_X = 1, + PF_W = 2, + PF_R = 4, +}; + +enum elf_section_header_flags +{ + SHF_WRITE = 1, + SHF_ALLOC = 2, + SHF_EXECINSTR = 4, + SHF_MIPS_GPREL = 0x10000000, +}; + +enum anaarg_havearg_param +{ + ARG_HAVEARG_NONE = 0, + ARG_HAVEARG_UNK1 = 1, + ARG_HAVEARG_REQUIRED = 2, + ARG_HAVEARG_UNK3 = 3, + ARG_HAVEARG_UNK4 = 4, +}; + +enum elf_file_slot_type +{ + EFS_TYPE_NONE = 0, + EFS_TYPE_ELF_HEADER = 1, + EFS_TYPE_PROGRAM_HEADER_TABLE = 2, + EFS_TYPE_PROGRAM_HEADER_ENTRY = 3, + EFS_TYPE_SECTION_HEADER_TABLE = 4, + EFS_TYPE_SECTION_DATA = 5, + EFS_TYPE_END = 100, +}; + +enum srx_target_enum +{ + SRX_TARGET_IOP = 1, + SRX_TARGET_EE = 2, +}; + +enum srx_program_header_type +{ + SRX_PH_TYPE_MOD = 1, + SRX_PH_TYPE_TEXT = 2, +}; + +#endif diff --git a/tools/srxfixup/src/srxgen.c b/tools/srxfixup/src/srxgen.c new file mode 100644 index 00000000000..3890f66e4b4 --- /dev/null +++ b/tools/srxfixup/src/srxgen.c @@ -0,0 +1,2146 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "srxfixup_internal.h" +#include +#include +#include +#include + +typedef struct sect_org_data_ +{ + unsigned int org_addr; + unsigned int org_gp_value; +} Sect_org_data; + +static int setup_start_entry(elf_file *elf, const char *entrysym, elf_section *modinfo, int needoutput); +static Elf_file_slot *search_order_slots(const char *ordstr, const elf_file *elf, Elf_file_slot *order); +static void fixlocation_an_rel(elf_section *relsect, unsigned int startaddr); +static void save_org_addrs(elf_file *elf); +static elf_section *add_iopmod(elf_file *elf); +static elf_section *add_eemod(elf_file *elf); +static void modify_eemod(elf_file *elf, elf_section *eemod); +static void add_reserved_symbol_table( + Srx_gen_table *tp, + const char *name, + int bind, + int type, + SegConf *segment, + const char *sectname, + int shindex, + int base); +static void define_special_section_symbols(elf_file *elf); +static void create_need_section(elf_file *elf); +static int sect_name_match(const char *pattern, const char *name); +static int reorder_section_table(elf_file *elf); +static void create_phdr(elf_file *elf); +static void check_change_bit(unsigned int oldbit, unsigned int newbit, unsigned int *up, unsigned int *down); +static void segment_start_setup(SegConf *seglist, unsigned int bitid, const unsigned int *moffset); +static void add_section_to_segment(SegConf *seglist, elf_section *scp, unsigned int bitid); +static void segment_end_setup(SegConf *seglist, unsigned int bitid, unsigned int *moffset, int ee); +static void update_modinfo(elf_file *elf); +static void update_mdebug(elf_file *elf); +static void update_programheader(elf_file *elf); +static void remove_unuse_section(elf_file *elf); +static int layout_srx_memory(elf_file *elf); +static CreateSymbolConf *is_reserve_symbol(Srx_gen_table *tp, const char *name); +static int check_undef_symboles_an_reloc(elf_section *relsect); +static int check_undef_symboles(elf_file *elf); +static int create_reserved_symbols(elf_file *elf); +static void symbol_value_update(elf_file *elf); +static void rebuild_relocation(elf_file *elf, unsigned int gpvalue); +static int check_irx12(elf_file *elf, int cause_irx1); +static void setup_module_info(elf_file *elf, elf_section *modsect, const char *modulesymbol); +static void rebuild_an_relocation(elf_section *relsect, unsigned int gpvalue, int target); +static size_t iopmod_size(const Elf32_IopMod *modinfo); +static size_t eemod_size(const Elf32_EeMod *modinfo); + +int convert_rel2srx(elf_file *elf, const char *entrysym, int needoutput, int cause_irx1) +{ + Srx_gen_table *tp; + elf_section *modinfo; + + tp = (Srx_gen_table *)elf->optdata; + save_org_addrs(elf); + switch ( tp->target ) + { + case SRX_TARGET_IOP: + modinfo = add_iopmod(elf); + break; + case SRX_TARGET_EE: + modinfo = add_eemod(elf); + break; + default: + fprintf(stderr, "Internal error: target unknown\n"); + exit(1); + } + remove_unuse_section(elf); + define_special_section_symbols(elf); + create_need_section(elf); + reorder_section_table(elf); + create_phdr(elf); + if ( layout_srx_memory(elf) ) + { + return 1; + } + modify_eemod(elf, modinfo); + if ( create_reserved_symbols(elf) ) + { + return 1; + } + if ( check_undef_symboles(elf) ) + { + return 1; + } + symbol_value_update(elf); + rebuild_relocation(elf, lookup_segment(tp, "GLOBALDATA", 1)->addr + 0x7FF0); + if ( check_irx12(elf, cause_irx1) ) + { + return 1; + } + if ( setup_start_entry(elf, entrysym, modinfo, needoutput) ) + { + return 1; + } + { + const char *module_info_symbol; + const elf_syment *syp; + + module_info_symbol = "Module"; + syp = search_global_symbol("_irx_id", elf); + if ( is_defined_symbol(syp) != 0 ) + { + module_info_symbol = "_irx_id"; + } + setup_module_info(elf, modinfo, module_info_symbol); + } + return layout_srx_file(elf); +} + +static int setup_start_entry(elf_file *elf, const char *entrysym, elf_section *modinfo, int needoutput) +{ + const elf_syment *syp; + + if ( entrysym ) + { + syp = search_global_symbol(entrysym, elf); + if ( !is_defined_symbol(syp) ) + { + fprintf(stderr, "Error: Cannot find entry symbol %s\n", entrysym); + return 1; + } + elf->ehp->e_entry = get_symbol_value(syp, elf); + } + else + { + syp = search_global_symbol("start", elf); + if ( !syp ) + { + syp = search_global_symbol("_start", elf); + } + if ( !is_defined_symbol(syp) ) + { + if ( modinfo->shr.sh_type == SHT_SCE_EEMOD ) + { + elf->ehp->e_entry = -1; + } + else if ( needoutput ) + { + fprintf(stderr, "warning: Cannot find entry symbol `start' and `_start'\n"); + } + } + else + { + elf->ehp->e_entry = get_symbol_value(syp, elf); + } + } + switch ( modinfo->shr.sh_type ) + { + case SHT_SCE_IOPMOD: + case SHT_SCE_EEMOD: + *((uint32_t *)modinfo->data + 1) = elf->ehp->e_entry; + break; + default: + break; + } + return 0; +} + +static Elf_file_slot *search_order_slots(const char *ordstr, const elf_file *elf, Elf_file_slot *order) +{ + elf_section **scp; + + if ( !strcmp(ordstr, "@Section_header_table") ) + { + for ( ; order->type != EFS_TYPE_END; order += 1 ) + { + if ( order->type == EFS_TYPE_SECTION_HEADER_TABLE ) + { + return order; + } + } + return 0; + } + if ( !strncmp(ordstr, "@Program_header_data ", 0x15) ) + { + long n; + + n = strtol(ordstr + 21, NULL, 10); + for ( ; order->type != EFS_TYPE_END; order += 1 ) + { + if ( order->type == EFS_TYPE_PROGRAM_HEADER_ENTRY && order->d.php == &elf->php[n] ) + { + return order; + } + } + return 0; + } + for ( ; order->type != EFS_TYPE_END; order += 1 ) + { + switch ( order->type ) + { + case EFS_TYPE_PROGRAM_HEADER_ENTRY: + for ( scp = order->d.php->scp; *scp; scp += 1 ) + { + if ( !sect_name_match(ordstr, (*scp)->name) ) + { + return order; + } + } + break; + case EFS_TYPE_SECTION_DATA: + if ( !sect_name_match(ordstr, order->d.scp->name) ) + { + return order; + } + break; + default: + break; + } + } + return 0; +} + +int layout_srx_file(elf_file *elf) +{ + elf_section **scp; + const Srx_gen_table *tp; + Elf_file_slot *slotp_1; + Elf_file_slot *slotp_2; + Elf_file_slot *nslotp; + Elf_file_slot *neworder; + Elf_file_slot *order; + const char **ordstr; + unsigned int max_seg_align; + int error; + int maxslot; + + tp = (Srx_gen_table *)elf->optdata; + error = 0; + switch ( tp->target ) + { + case SRX_TARGET_IOP: + max_seg_align = 16; + break; + case SRX_TARGET_EE: + max_seg_align = 0x10000; + break; + default: + fprintf(stderr, "Internal error: target unknown\n"); + return 1; + } + reorder_symtab(elf); + rebuild_section_name_strings(elf); + rebuild_symbol_name_strings(elf); + order = build_file_order_list(elf); + for ( maxslot = 0; order[maxslot].type != EFS_TYPE_END; maxslot += 1 ) + { + ; + } + neworder = (Elf_file_slot *)calloc(maxslot + 1, sizeof(Elf_file_slot)); + memcpy(neworder, order, sizeof(Elf_file_slot)); + nslotp = neworder + 1; + order->type = EFS_TYPE_NONE; + if ( elf->ehp->e_phnum ) + { + memcpy(nslotp, &order[1], sizeof(Elf_file_slot)); + nslotp = neworder + 2; + order[1].type = EFS_TYPE_NONE; + } + for ( ordstr = tp->file_layout_order; *ordstr; ordstr += 1 ) + { + for ( ;; ) + { + slotp_1 = search_order_slots(*ordstr, elf, order); + if ( !slotp_1 ) + { + break; + } + memcpy(nslotp, slotp_1, sizeof(Elf_file_slot)); + nslotp += 1; + slotp_1->type = EFS_TYPE_NONE; + } + } + nslotp->type = EFS_TYPE_END; + shrink_file_order_list(neworder); + writeback_file_order_list(elf, neworder); + for ( slotp_2 = neworder; slotp_2->type != EFS_TYPE_END; slotp_2 += 1 ) + { + if ( + slotp_2->type == EFS_TYPE_PROGRAM_HEADER_ENTRY && slotp_2->d.php->phdr.p_type == PT_LOAD + && max_seg_align < slotp_2->align ) + { + fprintf(stderr, "Program Header Entry: unsupported align %u\n", slotp_2->align); + error += 1; + for ( scp = slotp_2->d.php->scp; *scp; scp += 1 ) + { + if ( max_seg_align < (*scp)->shr.sh_addralign ) + { + fprintf( + stderr, "Section '%s' : unsupported section align %d\n", (*scp)->name, (int)((*scp)->shr.sh_addralign)); + error += 1; + } + } + } + } + free(order); + free(neworder); + return error; +} + +void strip_elf(elf_file *elf) +{ + elf_syment **syp; + elf_section *scp; + unsigned int entrise; + unsigned int d; + unsigned int s; + + remove_section(elf, SHT_MIPS_DEBUG); + scp = search_section(elf, SHT_SYMTAB); + if ( scp == NULL ) + { + return; + } + entrise = scp->shr.sh_size / scp->shr.sh_entsize; + syp = (elf_syment **)scp->data; + d = 1; + for ( s = 1; s < entrise; s += 1 ) + { + if ( syp[s]->refcount <= 0 ) + { + syp[s]->number = -1; + } + else + { + syp[d] = syp[s]; + d += 1; + } + } + scp->shr.sh_size = d * scp->shr.sh_entsize; +} + +SegConf *lookup_segment(Srx_gen_table *conf, const char *segname, int msgsw) +{ + SegConf *i; + + for ( i = conf->segment_list; i->name; i += 1 ) + { + if ( !strcmp(segname, i->name) ) + { + return i; + } + } + if ( msgsw ) + { + fprintf(stderr, "segment '%s' not found \n", segname); + } + return 0; +} + +static void fixlocation_an_rel(elf_section *relsect, unsigned int startaddr) +{ + int daddr1; + unsigned int data_1; + uint32_t data_2; + int data_3; + unsigned int data_4; + uint16_t data_5; + elf_syment **symp; + elf_rel *rp; + unsigned int entrise; + unsigned int i; + + entrise = relsect->shr.sh_size / relsect->shr.sh_entsize; + rp = (elf_rel *)relsect->data; + symp = (elf_syment **)relsect->link->data; + for ( i = 0; i < entrise; i += 1 ) + { + uint8_t *datal; + + if ( rp->symptr && *symp != rp->symptr ) + { + fprintf(stderr, "Internal error: Illegal relocation entry\n"); + exit(1); + } + if ( + relsect->info->shr.sh_addr > rp->rel.r_offset + || rp->rel.r_offset >= relsect->info->shr.sh_size + relsect->info->shr.sh_addr ) + { + fprintf( + stderr, + "Panic !! relocation #%u offset=0x%x range out (section limit addr=0x%x-0x%x)\n", + i, + rp->rel.r_offset, + relsect->info->shr.sh_addr, + relsect->info->shr.sh_size + relsect->info->shr.sh_addr); + exit(1); + } + datal = &relsect->info->data[rp->rel.r_offset - relsect->info->shr.sh_addr]; + switch ( rp->type ) + { + case R_MIPS_16: + data_1 = startaddr + (int16_t)*(uint32_t *)datal; + if ( (uint16_t)(data_1 >> 16) ) + { + if ( (uint16_t)(data_1 >> 16) != 0xFFFF ) + { + fprintf(stderr, "REFHALF data overflow\n"); + exit(1); + } + } + *(uint32_t *)datal &= 0xFFFF0000; + *(uint32_t *)datal |= (uint16_t)data_1; + break; + case R_MIPS_32: + *(uint32_t *)datal += startaddr; + break; + case R_MIPS_26: + if ( rp->symptr && rp->symptr->bind != STB_LOCAL ) + { + fprintf(stderr, "R_MIPS_26 Unexcepted bind\n"); + exit(1); + } + data_2 = startaddr + ((rp->rel.r_offset & 0xF0000000) | (4 * (*(uint32_t *)datal & 0x3FFFFFF))); + *(uint32_t *)datal &= 0xFC000000; + *(uint32_t *)datal |= (16 * data_2) >> 6; + break; + case R_MIPS_HI16: + if ( i == entrise + 1 || rp[1].type != R_MIPS_LO16 || (rp->symptr && rp[1].symptr != rp->symptr) ) + { + fprintf(stderr, "R_MIPS_HI16 without R_MIPS_LO16\n"); + exit(1); + } + data_4 = startaddr + (int16_t)*(uint32_t *)&relsect->info->data[rp[1].rel.r_offset - relsect->info->shr.sh_addr] + + (*(uint32_t *)datal << 16); + *(uint32_t *)datal &= 0xFFFF0000; + *(uint32_t *)datal |= (uint16_t)(((data_4 >> 15) + 1) >> 1); + break; + case R_MIPS_LO16: + data_5 = startaddr + *(uint32_t *)datal; + *(uint32_t *)datal &= 0xFFFF0000; + *(uint32_t *)datal |= data_5; + break; + case R_MIPS_GPREL16: + fprintf(stderr, "Unexcepted R_MIPS_GPREL16\n"); + exit(1); + return; + case R_MIPS_LITERAL: + fprintf(stderr, "Unexcepted R_MIPS_LITERAL\n"); + exit(1); + return; + case R_MIPSSCE_MHI16: + if ( i == entrise + 1 || rp[1].type != R_MIPSSCE_ADDEND ) + { + fprintf(stderr, "R_MIPSSCE_MHI16 without R_MIPSSCE_ADDEND\n"); + exit(1); + } + data_3 = (uint16_t)((((startaddr + rp[1].rel.r_offset) >> 15) + 1) >> 1); + for ( daddr1 = 1; daddr1; datal += daddr1 ) + { + daddr1 = *(uint16_t *)datal << 16 >> 14; + *(uint32_t *)datal &= 0xFFFF0000; + *(uint32_t *)datal |= data_3; + } + rp += 1; + i += 1; + break; + case R_MIPS_REL32: + case R_MIPS_GOT16: + case R_MIPS_PC16: + case R_MIPS_CALL16: + case R_MIPS_GPREL32: + case R_MIPS_GOTHI16: + case R_MIPS_GOTLO16: + case R_MIPS_CALLHI16: + case R_MIPS_CALLLO16: + fprintf(stderr, "unacceptable relocation type: 0x%x\n", rp->type); + exit(1); + return; + default: + fprintf(stderr, "unknown relocation type: 0x%x\n", rp->type); + exit(1); + return; + } + rp += 1; + } +} + +void fixlocation_elf(elf_file *elf, unsigned int startaddr) +{ + unsigned int entrise; + int i; + unsigned int k; + int d; + int s; + int j; + elf_syment **syp; + elf_section *scp; + elf_section *modsect_1; + elf_section *modsect_2; + + if ( elf->scp == NULL ) + { + return; + } + d = 1; + for ( s = 1; s < elf->ehp->e_shnum; s += 1 ) + { + if ( elf->scp[s]->shr.sh_type == SHT_REL ) + { + fixlocation_an_rel(elf->scp[s], startaddr); + } + else + { + elf->scp[d] = elf->scp[s]; + d += 1; + } + } + elf->ehp->e_shnum = d; + elf->ehp->e_entry += startaddr; + modsect_1 = search_section(elf, SHT_SCE_IOPMOD); + if ( modsect_1 ) + { + Elf32_IopMod *iopmodinfo; + + iopmodinfo = (Elf32_IopMod *)modsect_1->data; + if ( iopmodinfo->moduleinfo != (Elf32_Word)(-1) ) + { + iopmodinfo->moduleinfo += startaddr; + } + iopmodinfo->entry += startaddr; + iopmodinfo->gp_value += startaddr; + } + modsect_2 = search_section(elf, SHT_SCE_EEMOD); + if ( modsect_2 ) + { + Elf32_EeMod *eemodinfo; + + eemodinfo = (Elf32_EeMod *)modsect_2->data; + if ( eemodinfo->moduleinfo != (Elf32_Word)(-1) ) + { + eemodinfo->moduleinfo += startaddr; + } + eemodinfo->entry += startaddr; + eemodinfo->gp_value += startaddr; + } + for ( i = 0; i < elf->ehp->e_phnum; i += 1 ) + { + if ( elf->php[i].phdr.p_type == PT_LOAD ) + { + elf->php[i].phdr.p_vaddr = startaddr; + elf->php[i].phdr.p_paddr = startaddr; + break; + } + } + for ( j = 1; j < elf->ehp->e_shnum; j += 1 ) + { + switch ( elf->scp[j]->shr.sh_type ) + { + case SHT_PROGBITS: + case SHT_NOBITS: + elf->scp[j]->shr.sh_addr += startaddr; + break; + default: + break; + } + } + scp = search_section(elf, SHT_SYMTAB); + if ( scp == NULL ) + { + return; + } + entrise = scp->shr.sh_size / scp->shr.sh_entsize; + syp = (elf_syment **)scp->data; + for ( k = 1; k < entrise; k += 1 ) + { + if ( syp[k]->sym.st_shndx == SHN_RADDR || (syp[k]->sym.st_shndx && syp[k]->sym.st_shndx <= 0xFEFF) ) + { + syp[k]->sym.st_value += startaddr; + } + if ( syp[k]->sym.st_shndx == SHN_RADDR ) + { + syp[k]->sym.st_shndx = -15; + } + } +} + +static void save_org_addrs(elf_file *elf) +{ + Elf32_RegInfo *data; + const Elf32_RegInfo *reginfop; + elf_section *reginfosec; + int i; + + reginfosec = search_section(elf, SHT_MIPS_REGINFO); + if ( reginfosec ) + { + data = (Elf32_RegInfo *)reginfosec->data; + } + else + { + data = 0; + } + reginfop = data; + for ( i = 1; i < elf->ehp->e_shnum; i += 1 ) + { + Sect_org_data *org; + + org = (Sect_org_data *)calloc(1, sizeof(Sect_org_data)); + org->org_addr = elf->scp[i]->shr.sh_addr; + if ( reginfop ) + { + org->org_gp_value = reginfop->ri_gp_value; + } + elf->scp[i]->optdata = (void *)org; + } +} + +static elf_section *add_iopmod(elf_file *elf) +{ + Elf32_IopMod *iopmodp; + elf_section *modsect; + + modsect = (elf_section *)malloc(sizeof(elf_section)); + memset(modsect, 0, sizeof(elf_section)); + iopmodp = (Elf32_IopMod *)malloc(sizeof(Elf32_IopMod)); + memset(iopmodp, 0, sizeof(Elf32_IopMod)); + iopmodp->moduleinfo = -1; + modsect->name = strdup(".iopmod"); + modsect->data = (uint8_t *)iopmodp; + modsect->shr.sh_type = SHT_SCE_IOPMOD; + modsect->shr.sh_size = iopmod_size(iopmodp); + modsect->shr.sh_addralign = 4; + modsect->shr.sh_entsize = 0; + add_section(elf, modsect); + return modsect; +} + +static elf_section *add_eemod(elf_file *elf) +{ + Elf32_EeMod *eemodp; + elf_section *modsect; + + modsect = (elf_section *)malloc(sizeof(elf_section)); + memset(modsect, 0, sizeof(elf_section)); + eemodp = (Elf32_EeMod *)malloc(sizeof(Elf32_EeMod)); + memset(eemodp, 0, sizeof(Elf32_EeMod)); + eemodp->moduleinfo = -1; + modsect->name = strdup(".eemod"); + modsect->data = (uint8_t *)eemodp; + modsect->shr.sh_type = SHT_SCE_EEMOD; + modsect->shr.sh_size = eemod_size(eemodp); + modsect->shr.sh_addralign = 4; + modsect->shr.sh_entsize = 0; + add_section(elf, modsect); + return modsect; +} + +static void modify_eemod(elf_file *elf, elf_section *eemod) +{ + elf_section *scp_1; + elf_section *scp_2; + Elf32_EeMod *moddata; + + if ( eemod->shr.sh_type != SHT_SCE_EEMOD ) + { + return; + } + moddata = (Elf32_EeMod *)eemod->data; + scp_1 = search_section_by_name(elf, ".erx.lib"); + if ( scp_1 ) + { + moddata->erx_lib_addr = scp_1->shr.sh_addr; + moddata->erx_lib_size = scp_1->shr.sh_size; + } + else + { + moddata->erx_lib_addr = -1; + moddata->erx_lib_size = 0; + } + scp_2 = search_section_by_name(elf, ".erx.stub"); + if ( scp_2 ) + { + moddata->erx_stub_addr = scp_2->shr.sh_addr; + moddata->erx_stub_size = scp_2->shr.sh_size; + } + else + { + moddata->erx_stub_addr = -1; + moddata->erx_stub_size = 0; + } +} + +static void add_reserved_symbol_table( + Srx_gen_table *tp, + const char *name, + int bind, + int type, + SegConf *segment, + const char *sectname, + int shindex, + int base) +{ + CreateSymbolConf *newent_1; + CreateSymbolConf *newent_2; + int entries; + + entries = 1; + for ( newent_1 = tp->create_symbols; newent_1->name; newent_1 += 1 ) + { + entries += 1; + } + tp->create_symbols = (CreateSymbolConf *)realloc(tp->create_symbols, (entries + 1) * sizeof(CreateSymbolConf)); + memset(&tp->create_symbols[entries], 0, sizeof(tp->create_symbols[entries])); + newent_2 = &tp->create_symbols[entries - 1]; + newent_2->name = strdup(name); + newent_2->bind = bind; + newent_2->type = type; + newent_2->segment = segment; + newent_2->sectname = strdup(sectname); + newent_2->shindex = shindex; + newent_2->seflag = base; +} + +const char *bos_str = "_begin_of_section_"; +const char *eos_str = "_end_of_section_"; +static void define_special_section_symbols(elf_file *elf) +{ + char *sectname; + const elf_syment *sym; + elf_syment **syp; + elf_section *scp; + unsigned int entrise; + unsigned int i; + Srx_gen_table *tp; + + tp = (Srx_gen_table *)(elf->optdata); + scp = search_section(elf, SHT_SYMTAB); + if ( scp == NULL ) + { + return; + } + sectname = (char *)__builtin_alloca(((elf->shstrptr->shr.sh_size + 22) >> 2) << 2); + entrise = scp->shr.sh_size / scp->shr.sh_entsize; + syp = (elf_syment **)(scp->data); + for ( i = 1; i < entrise; i += 1 ) + { + sym = syp[i]; + if ( sym->bind == STB_GLOBAL && !sym->sym.st_shndx ) + { + if ( !strncmp(bos_str, sym->name, strlen(bos_str)) ) + { + strcpy(sectname, "."); + strcat(sectname, &sym->name[strlen(bos_str)]); + add_reserved_symbol_table(tp, sym->name, 2, 1, 0, sectname, 0, 0); + } + if ( !strncmp(eos_str, sym->name, strlen(eos_str)) ) + { + strcpy(sectname, "."); + strcat(sectname, &sym->name[strlen(eos_str)]); + add_reserved_symbol_table(tp, sym->name, 2, 1, 0, sectname, 65311, 1); + } + } + } +} + +static void create_need_section(elf_file *elf) +{ + elf_section *scp; + unsigned int i; + CreateSymbolConf *csym; + Srx_gen_table *tp; + + tp = (Srx_gen_table *)elf->optdata; + scp = search_section(elf, SHT_SYMTAB); + if ( scp == NULL ) + { + return; + } + for ( i = 1; i < (scp->shr.sh_size / scp->shr.sh_entsize); i += 1 ) + { + const elf_syment *syment; + + syment = *(elf_syment **)&scp->data[i * sizeof(void *)]; + if ( !syment->sym.st_shndx ) + { + csym = is_reserve_symbol(tp, syment->name); + if ( csym ) + { + if ( csym->segment ) + { + elf_section *addscp_1; + + addscp_1 = csym->segment->empty_section; + if ( addscp_1 ) + { + if ( !search_section_by_name(elf, addscp_1->name) ) + { + add_section(elf, addscp_1); + } + } + } + else if ( csym->sectname && !search_section_by_name(elf, csym->sectname) ) + { + SectConf *odr; + + for ( odr = tp->section_list; odr->sect_name_pattern; odr += 1 ) + { + if ( !sect_name_match(odr->sect_name_pattern, csym->sectname) && odr->secttype && odr->sectflag ) + { + elf_section *addscp_2; + + addscp_2 = (elf_section *)calloc(1, sizeof(elf_section)); + addscp_2->name = strdup(csym->sectname); + addscp_2->shr.sh_type = odr->secttype; + addscp_2->shr.sh_flags = odr->sectflag; + addscp_2->shr.sh_size = 0; + addscp_2->shr.sh_addralign = 4; + addscp_2->shr.sh_entsize = 0; + add_section(elf, addscp_2); + break; + } + } + } + } + } + } +} + +static int sect_name_match(const char *pattern, const char *name) +{ + for ( ; *pattern && *name && *pattern != '*'; pattern += 1, name += 1 ) + { + if ( *name > *pattern ) + { + return -1; + } + if ( *name < *pattern ) + { + return 1; + } + } + if ( !*pattern && !*name ) + { + return 0; + } + if ( *pattern == '*' && !pattern[1] ) + { + return 0; + } + if ( *pattern != '*' ) + { + return strcmp(pattern, name); + } + pattern += 1; + if ( strlen(name) < strlen(pattern) ) + { + return strcmp(pattern, name); + } + return strcmp(pattern, &name[strlen(name) - strlen(pattern)]); +} + +static int reorder_section_table(elf_file *elf) +{ + const char **secorder; + int sections; + elf_section **scp; + int d; + int s; + + sections = elf->ehp->e_shnum; + secorder = ((Srx_gen_table *)elf->optdata)->section_table_order; + scp = (elf_section **)calloc(sections + 1, sizeof(elf_section *)); + memcpy(scp, elf->scp, sections * sizeof(elf_section *)); + *elf->scp = *scp; + d = 1; + for ( ; *secorder; secorder += 1 ) + { + for ( s = 1; s < sections; s += 1 ) + { + if ( scp[s] ) + { + if ( !sect_name_match(*secorder, scp[s]->name) ) + { + elf->scp[d] = scp[s]; + scp[s] = 0; + d += 1; + } + } + } + } + free(scp); + reorder_symtab(elf); + return 0; +} + +static void create_phdr(elf_file *elf) +{ + const PheaderInfo *phip; + int i; + + phip = ((Srx_gen_table *)(elf->optdata))->program_header_order; + for ( i = 0; phip[i].sw; i += 1 ) + { + ; + } + elf->php = (i != 0) ? (elf_proghead *)malloc(i * sizeof(elf_proghead)) : NULL; + if ( elf->php != NULL ) + { + memset(elf->php, 0, i * sizeof(elf_proghead)); + } + elf->ehp->e_phentsize = sizeof(Elf32_Phdr); + elf->ehp->e_phnum = i; + if ( elf->php != NULL ) + { + int j; + + for ( j = 0; phip[j].sw; j += 1 ) + { + switch ( phip[j].sw ) + { + case SRX_PH_TYPE_MOD: + elf->php[j].phdr.p_flags = PF_R; + elf->php[j].phdr.p_align = 4; + if ( !strcmp(".iopmod", phip[j].d.section_name) ) + { + elf->php[j].phdr.p_type = PT_SCE_IOPMOD; + elf->php[j].phdr.p_filesz = sizeof(Elf32_IopMod); + elf->php[j].scp = (elf_section **)calloc(2, sizeof(elf_section *)); + *elf->php[j].scp = search_section(elf, SHT_SCE_IOPMOD); + } + else if ( !strcmp(".eemod", phip[j].d.section_name) ) + { + elf->php[j].phdr.p_type = PT_SCE_EEMOD; + elf->php[j].phdr.p_filesz = sizeof(Elf32_EeMod); + elf->php[j].scp = (elf_section **)calloc(2, sizeof(elf_section *)); + *elf->php[j].scp = search_section(elf, SHT_SCE_EEMOD); + } + else + { + fprintf(stderr, "Unsuport section '%s' for program header\n", phip[j].d.section_name); + } + break; + case SRX_PH_TYPE_TEXT: + elf->php[j].phdr.p_type = PT_LOAD; + elf->php[j].phdr.p_flags = PF_X | PF_W | PF_R; + elf->php[j].phdr.p_align = 16; + break; + default: + break; + } + } + } +} + +static void check_change_bit(unsigned int oldbit, unsigned int newbit, unsigned int *up, unsigned int *down) +{ + *up = ~oldbit & newbit & (newbit ^ oldbit); + *down = ~newbit & oldbit & (newbit ^ oldbit); +} + +static void segment_start_setup(SegConf *seglist, unsigned int bitid, const unsigned int *moffset) +{ + for ( ; seglist->name; seglist += 1 ) + { + if ( (seglist->bitid & bitid) != 0 ) + { + seglist->addr = *moffset; + seglist->size = 0; + } + } +} + +static void add_section_to_segment(SegConf *seglist, elf_section *scp, unsigned int bitid) +{ + for ( ; seglist->name; seglist += 1 ) + { + if ( (seglist->bitid & bitid) != 0 ) + { + if ( !seglist->nsect ) + { + seglist->addr = scp->shr.sh_addr; + } + seglist->nsect += 1; + seglist->scp = (elf_section **)realloc(seglist->scp, (seglist->nsect + 1) * sizeof(elf_section *)); + seglist->scp[seglist->nsect - 1] = scp; + seglist->scp[seglist->nsect] = 0; + } + } +} + +static void segment_end_setup(SegConf *seglist, unsigned int bitid, unsigned int *moffset, int ee) +{ + for ( ; seglist->name; seglist += 1 ) + { + if ( (seglist->bitid & bitid) != 0 ) + { + if ( ee ) + { + if ( !strcmp(seglist->name, "TEXT") ) + { + *moffset += 32; + } + } + seglist->size = *moffset - seglist->addr; + } + } +} + +static void update_modinfo(elf_file *elf) +{ + Srx_gen_table *tp; + const SegConf *seginfo; + const SegConf *seginfo_4; + const SegConf *seginfo_8; + const SegConf *seginfo_12; + elf_section *scp_1; + elf_section *scp_2; + + tp = (Srx_gen_table *)elf->optdata; + seginfo = lookup_segment(tp, "TEXT", 1); + seginfo_4 = lookup_segment(tp, "DATA", 1); + seginfo_8 = lookup_segment(tp, "BSS", 1); + seginfo_12 = lookup_segment(tp, "GLOBALDATA", 1); + if ( !seginfo || !seginfo_4 || !seginfo_8 || !seginfo_12 ) + { + fprintf(stderr, "TEXT,DATA,BSS,GLOBALDATA segment missing abort"); + exit(1); + } + scp_1 = search_section(elf, SHT_SCE_IOPMOD); + if ( scp_1 ) + { + Elf32_IopMod *imp; + + scp_1->shr.sh_addr = 0; + imp = (Elf32_IopMod *)scp_1->data; + imp->text_size = seginfo_4->addr - seginfo->addr; + imp->data_size = seginfo_8->addr - seginfo_4->addr; + imp->bss_size = seginfo_8->size; + imp->gp_value = seginfo_12->addr + 0x7FF0; + } + scp_2 = search_section(elf, SHT_SCE_EEMOD); + if ( scp_2 ) + { + Elf32_EeMod *emp; + + scp_2->shr.sh_addr = 0; + emp = (Elf32_EeMod *)scp_2->data; + emp->text_size = seginfo_4->addr - seginfo->addr; + emp->data_size = seginfo_8->addr - seginfo_4->addr; + emp->bss_size = seginfo_8->size; + emp->gp_value = seginfo_12->addr + 0x7FF0; + } +} + +static void update_mdebug(elf_file *elf) +{ + elf_section *scp; + + scp = search_section(elf, SHT_MIPS_DEBUG); + if ( scp ) + { + scp->shr.sh_addr = 0; + } +} + +static void update_programheader(elf_file *elf) +{ + Srx_gen_table *tp; + SegConf **segp; + elf_section **scp; + PheaderInfo *phip; + unsigned int minsegalign; + unsigned int align; + int nsect_1; + int nsect_2; + int nseg_1; + int nseg_2; + int s; + int n; + + tp = (Srx_gen_table *)elf->optdata; + phip = tp->program_header_order; + switch ( tp->target ) + { + case SRX_TARGET_IOP: + minsegalign = 16; + break; + case SRX_TARGET_EE: + minsegalign = 128; + break; + default: + fprintf(stderr, "Internal error: target unknown\n"); + exit(1); + return; + } + for ( n = 0; phip[n].sw; n += 1 ) + { + if ( phip[n].sw == SRX_PH_TYPE_TEXT ) + { + segp = phip[n].d.segment_list; + if ( segp ) + { + elf->php[n].phdr.p_vaddr = (*segp)->addr; + align = minsegalign; + for ( nsect_1 = 0, nseg_1 = 0; segp[nseg_1]; nsect_1 += segp[nseg_1]->nsect, nseg_1 += 1 ) + { + ; + } + scp = (elf_section **)calloc(nsect_1 + 1, sizeof(elf_section *)); + elf->php[n].scp = scp; + for ( nsect_2 = 0, nseg_2 = 0; segp[nseg_2]; nsect_2 += segp[nseg_2]->nsect, nseg_2 += 1 ) + { + memcpy(&scp[nsect_2], segp[nseg_2]->scp, segp[nseg_2]->nsect * sizeof(elf_section *)); + } + for ( s = 0; s < nsect_2 && scp[s]->shr.sh_type == SHT_PROGBITS; s += 1 ) + { + if ( scp[s]->shr.sh_addralign > align ) + { + align = scp[s]->shr.sh_addralign; + } + } + elf->php[n].phdr.p_filesz = scp[s - 1]->shr.sh_size + scp[s - 1]->shr.sh_addr - (*scp)->shr.sh_addr; + elf->php[n].phdr.p_memsz = scp[nsect_2 - 1]->shr.sh_size + scp[nsect_2 - 1]->shr.sh_addr - (*scp)->shr.sh_addr; + for ( ; s < nsect_2; s += 1 ) + { + if ( scp[s]->shr.sh_addralign > align ) + { + align = scp[s]->shr.sh_addralign; + } + } + elf->php[n].phdr.p_align = align; + } + } + } +} + +static void remove_unuse_section(elf_file *elf) +{ + const char **sectnames; + int sections; + elf_section **dscp; + int d; + int i; + int j; + + sections = elf->ehp->e_shnum; + sectnames = ((Srx_gen_table *)(elf->optdata))->removesection_list; + dscp = (elf_section **)calloc(sections + 1, sizeof(elf_section *)); + memset(dscp, 0, sections * sizeof(elf_section *)); + d = 0; + for ( ; *sectnames; sectnames += 1 ) + { + for ( i = 1; i < sections; i += 1 ) + { + if ( elf->scp[i] ) + { + if ( !sect_name_match(*sectnames, elf->scp[i]->name) ) + { + dscp[d] = elf->scp[i]; + d += 1; + } + } + } + } + for ( j = 0; j < sections; j += 1 ) + { + if ( dscp[j] ) + { + remove_section_by_name(elf, dscp[j]->name); + } + } + free(dscp); +} + +static int layout_srx_memory(elf_file *elf) +{ + int s_3; + elf_section **scp; + SectConf *odr; + Srx_gen_table *tp; + int error; + int is_ee; + int sections; + int s_1; + int s_2; + unsigned int downdelta; + unsigned int updelta; + unsigned int oldbitid; + unsigned int moffset; + + tp = (Srx_gen_table *)elf->optdata; + moffset = 0; + oldbitid = 0; + error = 0; + is_ee = tp->target == SRX_TARGET_EE; + if ( !elf->scp ) + { + return 1; + } + sections = elf->ehp->e_shnum; + scp = (elf_section **)calloc(sections + 1, sizeof(elf_section *)); + memcpy(scp, elf->scp, sections * sizeof(elf_section *)); + for ( odr = tp->section_list; odr->sect_name_pattern; odr += 1 ) + { + check_change_bit(oldbitid, odr->flag, &updelta, &downdelta); + if ( updelta ) + { + segment_start_setup(tp->segment_list, updelta, &moffset); + } + for ( s_1 = 1; s_1 < sections; s_1 += 1 ) + { + if ( + scp[s_1] && !sect_name_match(odr->sect_name_pattern, scp[s_1]->name) + && (scp[s_1]->shr.sh_flags & SHF_ALLOC) != 0 ) + { + moffset = adjust_align(moffset, scp[s_1]->shr.sh_addralign); + scp[s_1]->shr.sh_addr = moffset; + moffset += scp[s_1]->shr.sh_size; + add_section_to_segment(tp->segment_list, scp[s_1], odr->flag); + scp[s_1] = 0; + } + } + oldbitid = odr->flag; + check_change_bit(oldbitid, odr[1].flag, &updelta, &downdelta); + if ( downdelta ) + { + segment_end_setup(tp->segment_list, downdelta, &moffset, is_ee); + } + } + for ( s_2 = 1; s_2 < sections; s_2 += 1 ) + { + if ( scp[s_2] && (scp[s_2]->shr.sh_flags & SHF_ALLOC) != 0 ) + { + for ( + s_3 = 1; + s_3 < sections + && (!scp[s_3] || (scp[s_3]->shr.sh_type != SHT_RELA && scp[s_3]->shr.sh_type != SHT_REL) || scp[s_2] != scp[s_3]->info); + s_3 += 1 ) + { + ; + } + if ( sections > s_3 ) + { + fprintf( + stderr, + "Error: section '%s' needs allocation and has relocation data but not in program segment\n", + scp[s_2]->name); + scp[s_3] = 0; + error += 1; + } + else + { + fprintf(stderr, "Warning: section '%s' needs allocation but not in program segment\n", scp[s_2]->name); + scp[s_2] = 0; + } + } + } + free(scp); + if ( !error ) + { + update_modinfo(elf); + update_mdebug(elf); + update_programheader(elf); + } + return error; +} + +static CreateSymbolConf *is_reserve_symbol(Srx_gen_table *tp, const char *name) +{ + CreateSymbolConf *csyms; + + if ( !name ) + { + return 0; + } + for ( csyms = tp->create_symbols; csyms->name; csyms += 1 ) + { + if ( !strcmp(csyms->name, name) ) + { + return csyms; + } + } + return 0; +} + +static int check_undef_symboles_an_reloc(elf_section *relsect) +{ + elf_syment **symp; + elf_rel *rp; + int undefcount; + unsigned int entrise; + unsigned int i; + + entrise = relsect->shr.sh_size / relsect->shr.sh_entsize; + rp = (elf_rel *)relsect->data; + symp = (elf_syment **)relsect->link->data; + undefcount = 0; + for ( i = 0; i < entrise; i += 1 ) + { + if ( rp->symptr && *symp != rp->symptr ) + { + if ( rp->symptr->sym.st_shndx ) + { + if ( + rp->symptr->sym.st_shndx > 0xFEFF && rp->symptr->sym.st_shndx != SHN_ABS + && rp->symptr->sym.st_shndx != SHN_RADDR ) + { + if ( rp->symptr->sym.st_shndx == SHN_COMMON ) + { + fprintf(stderr, " unallocated variable `%s'\n", rp->symptr->name); + } + else + { + fprintf(stderr, " `%s' unknown symbol type %x\n", rp->symptr->name, rp->symptr->sym.st_shndx); + } + undefcount += 1; + } + } + else if ( rp->symptr->bind != STB_WEAK ) + { + fprintf(stderr, " undefined reference to `%s'\n", rp->symptr->name); + undefcount += 1; + } + } + rp += 1; + } + return undefcount; +} + +static int check_undef_symboles(elf_file *elf) +{ + int err; + int s; + + if ( !elf->scp ) + { + return 0; + } + err = 0; + for ( s = 1; s < elf->ehp->e_shnum; s += 1 ) + { + if ( elf->scp[s]->shr.sh_type == SHT_REL ) + { + err += check_undef_symboles_an_reloc(elf->scp[s]); + } + } + return err; +} + +#if 0 +// clang-format off +static const char * const SymbolType[] = +{ +#define X(d) #d, + XEACH_SymbolType_enum() +#undef X +}; +// clang-format on +#endif +static int create_reserved_symbols(elf_file *elf) +{ + int csyms_; + unsigned int sh_size; + unsigned int sh_addr; + elf_section *scp; + CreateSymbolConf *csyms; + Srx_gen_table *tp; + + tp = (Srx_gen_table *)elf->optdata; + csyms_ = 0; + if ( !search_section(elf, SHT_SYMTAB) ) + { + return 1; + } + for ( csyms = tp->create_symbols; csyms->name; csyms += 1 ) + { + elf_syment *sym; + + sym = search_global_symbol(csyms->name, elf); + if ( !sym + && (csyms->shindex > 0xFEFF + || (csyms->segment && csyms->segment->scp) + || (!csyms->segment && csyms->sectname && search_section_by_name(elf, csyms->sectname))) ) + { + sym = add_symbol(elf, csyms->name, csyms->bind, 0, 0, 0, 0); + } + if ( sym ) + { + sh_size = 0; + sh_addr = 0; + scp = 0; + if ( csyms->segment ) + { + sh_addr = csyms->segment->addr; + sh_size = csyms->segment->size; + if ( csyms->shindex <= 0xFEFF ) + { + scp = *csyms->segment->scp; + } + } + else if ( csyms->sectname != NULL ) + { + scp = search_section_by_name(elf, csyms->sectname); + if ( scp ) + { + sh_addr = scp->shr.sh_addr; + sh_size = scp->shr.sh_size; + } + } + if ( csyms->segment || scp ) + { + // FIXME: disable this check because it trips on _gp, _end symbols +#if 0 + if ( sym->sym.st_shndx ) + { + fprintf(stderr, "Unexcepted Symbol \"%s\":%s \n", sym->name, SymbolType[sym->type]); + csyms_ += 1; + } + else +#endif + { + sym->bind = csyms->bind; + if ( !sym->type ) + { + sym->type = csyms->type; + } + sym->sym.st_info = ((csyms->bind & 0xFF) << 4) + (csyms->type & 0xF); + if ( csyms->shindex > 0xFEFF ) + { + sym->sym.st_shndx = csyms->shindex; + sym->shptr = 0; + switch ( csyms->seflag ) + { + case 0: + sym->sym.st_value = sh_addr; + break; + case 1: + sym->sym.st_value = sh_size + sh_addr; + break; + case 2: + sym->sym.st_value = sh_addr + 0x7FF0; + break; + default: + break; + } + } + else + { + sym->sym.st_shndx = 1; + sym->shptr = scp; + switch ( csyms->seflag ) + { + case 0: + sym->sym.st_value = 0; + break; + case 1: + sym->sym.st_value = sh_size; + break; + default: + break; + } + } + } + continue; + } + if ( csyms->bind == STB_WEAK && (sym->bind == STB_GLOBAL || sym->bind == STB_WEAK) && !sym->sym.st_shndx ) + { + if ( !sym->type ) + { + sym->type = csyms->type; + } + sym->bind = csyms->bind; + sym->sym.st_info = ((csyms->bind & 0xFF) << 4) + (csyms->type & 0xF); + } + } + } + return csyms_; +} + +static void symbol_value_update(elf_file *elf) +{ + unsigned int entrise; + unsigned int i; + elf_syment **syp; + elf_section *scp; + int target; + + target = ((Srx_gen_table *)(elf->optdata))->target; + if ( elf->ehp->e_type != ET_REL ) + { + return; + } + switch ( target ) + { + case SRX_TARGET_IOP: + elf->ehp->e_type = ET_SCE_IOPRELEXEC; + break; + case SRX_TARGET_EE: + elf->ehp->e_type = ET_SCE_EERELEXEC2; + break; + default: + break; + } + scp = search_section(elf, SHT_SYMTAB); + if ( scp == NULL ) + { + return; + } + entrise = scp->shr.sh_size / scp->shr.sh_entsize; + syp = (elf_syment **)scp->data; + for ( i = 1; i < entrise; i += 1 ) + { + if ( syp[i]->sym.st_shndx ) + { + if ( syp[i]->sym.st_shndx <= 0xFEFF ) + { + syp[i]->sym.st_value += syp[i]->shptr->shr.sh_addr; + } + } + } +} + +static void rebuild_relocation(elf_file *elf, unsigned int gpvalue) +{ + int s; + + if ( elf->scp == NULL ) + { + return; + } + for ( s = 1; s < elf->ehp->e_shnum; s += 1 ) + { + if ( elf->scp[s]->shr.sh_type == SHT_REL ) + { + rebuild_an_relocation(elf->scp[s], gpvalue, ((Srx_gen_table *)(elf->optdata))->target); + } + } +} + +static int check_irx12(elf_file *elf, int cause_irx1) +{ + int s; + + if ( elf->ehp->e_type != ET_SCE_IOPRELEXEC ) + { + return 0; + } + for ( s = 1; s < elf->ehp->e_shnum; s += 1 ) + { + if ( elf->scp[s]->shr.sh_type == SHT_REL && relocation_is_version2(elf->scp[s]) ) + { + if ( cause_irx1 ) + { + fprintf(stderr, "R_MIPS_LO16 without R_MIPS_HI16\n"); + return 1; + } + elf->ehp->e_type = ET_SCE_IOPRELEXEC2; + } + } + return 0; +} + +static void setup_module_info(elf_file *elf, elf_section *modsect, const char *modulesymbol) +{ + unsigned int *section_data; + int i; + char *buf; + const char *name; + unsigned int woff; + size_t buflen; + const unsigned int *modnamep; + unsigned int *modidatap; + unsigned int modiaddr; + const elf_syment *syp; + + syp = search_global_symbol(modulesymbol, elf); + if ( is_defined_symbol(syp) == 0 ) + { + return; + } + modiaddr = get_symbol_value(syp, elf); + modidatap = get_section_data(elf, modiaddr); + section_data = get_section_data(elf, *modidatap); + woff = (uintptr_t)section_data & 3; + modnamep = (unsigned int *)((char *)section_data - woff); + buflen = (strlen((const char *)section_data - woff + 4) + 15) & 0xFFFFFFFC; + buf = (char *)malloc(buflen); + memcpy(buf, modnamep, buflen); + swapmemory(buf, "l", buflen >> 2); + name = &buf[woff]; + switch ( modsect->shr.sh_type ) + { + case SHT_SCE_IOPMOD: + { + Elf32_IopMod *iopmodp_1; + Elf32_IopMod *iopmodp_2; + + iopmodp_1 = (Elf32_IopMod *)modsect->data; + iopmodp_1->moduleinfo = modiaddr; + iopmodp_1->moduleversion = *((uint16_t *)modidatap + 2); + // HACK FIXME: Don't place the name in the header + name = ""; + iopmodp_2 = (Elf32_IopMod *)realloc(iopmodp_1, strlen(name) + sizeof(Elf32_IopMod)); + strcpy(iopmodp_2->modulename, name); + modsect->data = (uint8_t *)iopmodp_2; + modsect->shr.sh_size = iopmod_size(iopmodp_2); + break; + } + case SHT_SCE_EEMOD: + { + Elf32_EeMod *eemodp_1; + Elf32_EeMod *eemodp_2; + eemodp_1 = (Elf32_EeMod *)modsect->data; + eemodp_1->moduleinfo = modiaddr; + eemodp_1->moduleversion = *((uint16_t *)modidatap + 2); + eemodp_2 = (Elf32_EeMod *)realloc(eemodp_1, strlen(name) + sizeof(Elf32_EeMod)); + strcpy(eemodp_2->modulename, name); + modsect->data = (uint8_t *)eemodp_2; + modsect->shr.sh_size = eemod_size(eemodp_2); + break; + } + default: + break; + } + free(buf); + if ( elf->php == NULL ) + { + return; + } + for ( i = 0; i < elf->ehp->e_phnum; i += 1 ) + { + if ( elf->php[i].scp && (modsect == *elf->php[i].scp) ) + { + elf->php[i].phdr.p_filesz = modsect->shr.sh_size; + } + } +} + +static void rebuild_an_relocation(elf_section *relsect, unsigned int gpvalue, int target) +{ + elf_rel *newtab; + void *daddr_2; + void *daddr_3; + uint32_t data32_1; + int data32_2; + uint32_t datah; + uint32_t data_1; + uint32_t data_2; + uint32_t data_33; + uint16_t data_4; + unsigned int data_5; + unsigned int data_6; + uint32_t data_7; + uint32_t step; + elf_syment **symp; + elf_rel *rp; + int rmflag; + unsigned int entrise; + unsigned int j_1; + unsigned int j_2; + unsigned int j_3; + unsigned int i_1; + + entrise = relsect->shr.sh_size / relsect->shr.sh_entsize; + rp = (elf_rel *)relsect->data; + symp = (elf_syment **)relsect->link->data; + rmflag = 0; + for ( i_1 = 0; i_1 < entrise; ) + { + int v4; + uint32_t symvalue; + void *daddr_1; + unsigned int next; + + if ( relsect->info->shr.sh_size <= rp->rel.r_offset ) + { + fprintf( + stderr, + "Panic !! relocation #%u offset=0x%x overflow (section size=0x%x)\n", + i_1, + rp->rel.r_offset, + relsect->info->shr.sh_size); + exit(1); + } + next = 1; + daddr_1 = (void *)&relsect->info->data[rp->rel.r_offset]; + symvalue = 0; + if ( rp->symptr ) + { + if ( rp->symptr->sym.st_shndx ) + { + symvalue = rp->symptr->sym.st_value; + } + } + v4 = 0; + if ( + !rp->symptr || (rp->symptr->sym.st_shndx && rp->symptr->sym.st_shndx <= 0xFEFF) + || rp->symptr->sym.st_shndx == SHN_RADDR ) + { + v4 = 1; + } + switch ( rp->type ) + { + case R_MIPS_NONE: + rmflag = 1; + break; + case R_MIPS_16: + data_1 = symvalue + (int16_t)*(uint32_t *)daddr_1; + if ( (uint16_t)(data_1 >> 16) && (uint16_t)(data_1 >> 16) != 0xFFFF ) + { + fprintf(stderr, "REFHALF data overflow\n"); + exit(1); + } + *(uint32_t *)daddr_1 &= 0xFFFF0000; + *(uint32_t *)daddr_1 |= (uint16_t)data_1; + if ( !v4 ) + { + rp->type = R_MIPS_NONE; + rmflag = 1; + } + break; + case R_MIPS_32: + *(uint32_t *)daddr_1 += symvalue; + if ( !v4 ) + { + rp->type = R_MIPS_NONE; + rmflag = 1; + } + break; + case R_MIPS_26: + data_2 = *(uint32_t *)daddr_1; + if ( rp->symptr && rp->symptr->bind != STB_LOCAL ) + { + data_33 = data_2 << 6 >> 4; + } + else + { + data_33 = ((relsect->info->shr.sh_addr + rp->rel.r_offset) & 0xF0000000) | (4 * (data_2 & 0x3FFFFFF)); + } + *(uint32_t *)daddr_1 &= 0xFC000000; + *(uint32_t *)daddr_1 |= (16 * (symvalue + data_33)) >> 6; + if ( !v4 ) + { + rp->type = R_MIPS_NONE; + rmflag = 1; + } + break; + case R_MIPS_HI16: + datah = *(uint32_t *)daddr_1 << 16; + for ( j_1 = i_1 + 1; j_1 < entrise && rp[next].type == R_MIPS_HI16; j_1 += 1 ) + { + if ( rp->symptr && rp[next].symptr != rp->symptr ) + { + fprintf(stderr, "R_MIPS_HI16 without R_MIPS_LO16\n"); + exit(1); + } + if ( relsect->info->shr.sh_size <= rp[next].rel.r_offset ) + { + fprintf( + stderr, + "Panic !! relocation #%u offset=0x%x overflow (section size=0x%x)\n", + i_1 + next, + rp[next].rel.r_offset, + relsect->info->shr.sh_size); + exit(1); + } + daddr_1 = (void *)&relsect->info->data[rp[next].rel.r_offset]; + if ( datah != *(uint32_t *)daddr_1 << 16 ) + { + fprintf(stderr, "R_MIPS_HI16s not same offsets\n"); + exit(1); + } + next += 1; + } + if ( j_1 == entrise + 1 || rp[next].type != R_MIPS_LO16 || (rp->symptr && rp[next].symptr != rp->symptr) ) + { + fprintf(stderr, "R_MIPS_HI16 without R_MIPS_LO16\n"); + exit(1); + } + data32_1 = symvalue + (int16_t)*(uint32_t *)&relsect->info->data[rp[next].rel.r_offset] + datah; + if ( next == 1 ) + { + *(uint32_t *)daddr_1 &= 0xFFFF0000; + *(uint32_t *)daddr_1 |= (uint16_t)(((data32_1 >> 15) + 1) >> 1); + if ( !v4 ) + { + rp->type = R_MIPS_NONE; + rmflag = 1; + } + } + else if ( v4 ) + { + for ( j_2 = 0; j_2 < next; j_2 += 1 ) + { + daddr_2 = (void *)&relsect->info->data[rp[j_2].rel.r_offset]; + *(uint32_t *)daddr_2 &= 0xFFFF0000; + if ( j_2 < next - 1 ) + { + step = rp[j_2 + 1].rel.r_offset - rp[j_2].rel.r_offset; + if ( step >> 18 && step >> 18 != 0x3FFF ) + { + fprintf(stderr, "R_MIPS_HI16s too long distance\n"); + exit(1); + } + *(uint32_t *)daddr_2 |= (uint16_t)(step >> 2); + } + rp[j_2].type = R_MIPS_NONE; + if ( rp[j_2].symptr ) + { + rp[j_2].symptr->refcount -= 1; + rp[j_2].symptr = *symp; + } + } + rp->type = R_MIPSSCE_MHI16; + rp->rel.r_offset += relsect->info->shr.sh_addr; + rp[1].type = R_MIPSSCE_ADDEND; + rp[1].rel.r_offset = data32_1; + rmflag = 1; + rp += next; + i_1 += next; + next = 0; + } + else + { + data32_2 = (uint16_t)(((data32_1 >> 15) + 1) >> 1); + for ( j_3 = 0; j_3 < next; j_3 += 1 ) + { + daddr_3 = (void *)&relsect->info->data[rp[j_3].rel.r_offset]; + *(uint32_t *)daddr_3 &= 0xFFFF0000; + *(uint32_t *)daddr_3 |= data32_2; + rp[j_3].type = R_MIPS_NONE; + } + rmflag = 1; + } + break; + case R_MIPS_LO16: + data_4 = symvalue + *(uint32_t *)daddr_1; + *(uint32_t *)daddr_1 &= 0xFFFF0000; + *(uint32_t *)daddr_1 |= data_4; + if ( !v4 ) + { + rp->type = R_MIPS_NONE; + rmflag = 1; + } + break; + case R_MIPS_GPREL16: + data_5 = (int16_t)*(uint32_t *)daddr_1; + if ( rp->symptr ) + { + if ( rp->symptr->type == STT_SECTION ) + { + data_5 += ((Sect_org_data *)(rp->symptr->shptr->optdata))->org_gp_value + symvalue + - ((Sect_org_data *)(rp->symptr->shptr->optdata))->org_addr - gpvalue; + } + else if ( rp->symptr->bind == STB_GLOBAL || (rp->symptr->bind == STB_WEAK && rp->symptr->sym.st_shndx) ) + { + data_5 += symvalue - gpvalue; + } + else if ( rp->symptr->bind != STB_WEAK || rp->symptr->sym.st_shndx ) + { + fprintf(stderr, "R_MIPS_GPREL16 unknown case abort\n"); + exit(1); + } + } + else + { + fprintf(stderr, "R_MIPS_GPREL16 no symtab\n"); + exit(1); + } + if ( (uint16_t)(data_5 >> 16) && (uint16_t)(data_5 >> 16) != 0xFFFF ) + { + fprintf(stderr, "R_MIPS_GPREL16 data overflow\n"); + exit(1); + } + *(uint32_t *)daddr_1 &= 0xFFFF0000; + *(uint32_t *)daddr_1 |= (uint16_t)data_5; + rp->type = R_MIPS_NONE; + rmflag = 1; + break; + case R_MIPS_LITERAL: + if ( !rp->symptr || rp->symptr->type != STT_SECTION ) + { + fprintf(stderr, "R_MIPS_LITERAL unknown case abort\n"); + exit(1); + } + data_6 = ((Sect_org_data *)(rp->symptr->shptr->optdata))->org_gp_value + symvalue + - ((Sect_org_data *)(rp->symptr->shptr->optdata))->org_addr - gpvalue + (int16_t)*(uint32_t *)daddr_1; + if ( (uint16_t)(data_6 >> 16) && (uint16_t)(data_6 >> 16) != 0xFFFF ) + { + fprintf(stderr, "R_MIPS_LITERAL data overflow\n"); + exit(1); + } + *(uint32_t *)daddr_1 &= 0xFFFF0000; + *(uint32_t *)daddr_1 |= (uint16_t)data_6; + rp->type = R_MIPS_NONE; + rmflag = 1; + break; + case R_MIPS_DVP_27_S4: + if ( target != SRX_TARGET_EE ) + { + fprintf(stderr, "R_MIPS_DVP_27_S4 can use only for EE.\n"); + exit(1); + } + data_7 = symvalue + (*(uint32_t *)daddr_1 & 0x7FFFFFF0); + *(uint32_t *)daddr_1 &= 0x8000000F; + *(uint32_t *)daddr_1 |= data_7 & 0x7FFFFFF0; + if ( !v4 ) + { + rp->type = R_MIPS_NONE; + rmflag = 1; + } + break; + case R_MIPS_REL32: + case R_MIPS_GOT16: + case R_MIPS_PC16: + case R_MIPS_CALL16: + case R_MIPS_GPREL32: + case R_MIPS_GOTHI16: + case R_MIPS_GOTLO16: + case R_MIPS_CALLHI16: + case R_MIPS_CALLLO16: + fprintf(stderr, "unacceptable relocation type: 0x%x\n", rp->type); + exit(1); + return; + default: + fprintf(stderr, "unknown relocation type: 0x%x\n", rp->type); + exit(1); + return; + } + for ( ; next > 0; next -= 1 ) + { + rp->rel.r_offset += relsect->info->shr.sh_addr; + if ( rp->symptr ) + { + rp->symptr->refcount -= 1; + rp->symptr = *symp; + } + i_1 += 1; + rp += 1; + } + } + if ( rmflag > 0 ) + { + elf_rel *s; + elf_rel *d; + unsigned int newentrise; + unsigned int i_2; + + newtab = (elf_rel *)calloc(entrise, sizeof(elf_rel)); + d = newtab; + s = (elf_rel *)relsect->data; + newentrise = 0; + for ( i_2 = 0; i_2 < entrise; i_2 += 1 ) + { + if ( s->type ) + { + memcpy(d, s, sizeof(elf_rel)); + d += 1; + newentrise += 1; + } + s += 1; + } + free(relsect->data); + relsect->data = (uint8_t *)newtab; + relsect->shr.sh_size = relsect->shr.sh_entsize * newentrise; + } +} + +static size_t iopmod_size(const Elf32_IopMod *modinfo) +{ + return strlen(modinfo->modulename) + (sizeof(Elf32_IopMod) - 1); +} + +static size_t eemod_size(const Elf32_EeMod *modinfo) +{ + return strlen(modinfo->modulename) + (sizeof(Elf32_EeMod) - 1); +} + +int relocation_is_version2(elf_section *relsect) +{ + elf_rel *rp; + unsigned int entrise; + unsigned int i; + + entrise = relsect->shr.sh_size / relsect->shr.sh_entsize; + rp = (elf_rel *)relsect->data; + for ( i = 0; i < entrise; i += 1 ) + { + switch ( rp->type ) + { + case R_MIPS_LO16: + case R_MIPSSCE_MHI16: + case R_MIPSSCE_ADDEND: + return 1; + case R_MIPS_HI16: + if ( i == entrise + 1 || rp[1].type != R_MIPS_LO16 || (rp->symptr && rp[1].symptr != rp->symptr) ) + { + return 1; + } + rp += 1; + i += 1; + break; + default: + break; + } + rp += 1; + } + return 0; +} + +void dump_srx_gen_table(Srx_gen_table *tp) +{ + const char *v1; + int scnfp_; + int v8; + int scp_; + int scp_a; + int nsegment; + int b; + int i; + CreateSymbolConf *csyms; + PheaderInfo *phip; + SectConf *sctp; + const char ***scnfpp; + SegConf *scnfp; + elf_section **scp; + char segsig[32]; + const char **strp; + + if ( tp == NULL ) + { + return; + } + switch ( tp->target ) + { + case SRX_TARGET_IOP: + v1 = "IOP"; + break; + case SRX_TARGET_EE: + v1 = "EE"; + break; + default: + v1 = "??"; + break; + } + printf("===============\nTarget is %s(%d)\n", v1, tp->target); + printf("Segment list\n"); + for ( v8 = 0, scnfp = tp->segment_list; scnfp->name; v8 += 1, scnfp += 1 ) + { + printf(" %2d:segment %s\n", v8, scnfp->name); + printf( + " addr,size=0x%x,0x%x bitid,nsect= 0x%x,%d\n ", scnfp->addr, scnfp->size, scnfp->bitid, scnfp->nsect); + if ( scnfp->sect_name_patterns ) + { + for ( strp = scnfp->sect_name_patterns; *strp; strp += 1 ) + { + printf("%s ", *strp); + } + printf("\n"); + } + if ( scnfp->empty_section ) + { + printf(" Auto add section: %s\n", scnfp->empty_section->name); + } + if ( scnfp->scp ) + { + for ( scp = scnfp->scp; *scp; scp += 1 ) + { + printf(" %p: %s\n", *scp, (*scp)->name); + } + } + segsig[v8] = *scnfp->name; + } + printf("\nProgram header order\n"); + for ( scp_ = 0, phip = tp->program_header_order; phip->sw; scp_ += 1, phip += 1 ) + { + switch ( phip->sw ) + { + case SRX_PH_TYPE_MOD: + printf(" %2d: section %s\n", scp_, phip->d.section_name); + break; + case SRX_PH_TYPE_TEXT: + printf(" %2d: Segments ", scp_); + for ( scnfpp = (const char ***)phip->d.section_name; *scnfpp; scnfpp += 1 ) + { + printf("%s ", **scnfpp); + } + printf("\n"); + break; + default: + break; + } + } + printf("\nRemove section list\n"); + for ( scp_a = 0, strp = tp->removesection_list; *strp; scp_a += 1, strp += 1 ) + { + printf(" %2d: %s\n", scp_a, *strp); + } + printf("\nSection table order\n"); + for ( nsegment = 0, strp = tp->section_table_order; *strp; nsegment += 1, strp += 1 ) + { + printf(" %2d: %s\n", nsegment, *strp); + } + printf("\nFile layout order\n"); + for ( b = 0, strp = tp->file_layout_order; *strp; b += 1, strp += 1 ) + { + printf(" %2d: %s\n", b, *strp); + } + printf("\nmemory layout order\n"); + for ( i = 0, sctp = tp->section_list; sctp->sect_name_pattern; i += 1, sctp += 1 ) + { + printf(" %2d: [", i); + for ( scnfp_ = 0; scnfp_ < v8; scnfp_ += 1 ) + { + printf("%c", ((sctp->flag & (1 << scnfp_)) != 0) ? (unsigned char)(segsig[scnfp_]) : 46); + } + printf("] %s", sctp->sect_name_pattern); + if ( sctp->secttype ) + { + printf("\t: Auto create type=%x flag=%x", sctp->secttype, sctp->sectflag); + } + printf("\n"); + } + printf("\nReserved symbols\n"); + for ( csyms = tp->create_symbols; csyms->name; csyms += 1 ) + { + printf( + " %-8s: bind=%d, type=%d, shindex=0x%04x, seflag=%d, seg=%s, sect=%s\n", + csyms->name, + csyms->bind, + csyms->type, + csyms->shindex, + csyms->seflag, + csyms->segment ? csyms->segment->name : "-", + csyms->sectname ?: "-"); + } + printf("\n\n"); +} diff --git a/tools/srxfixup/src/swapmem.c b/tools/srxfixup/src/swapmem.c new file mode 100644 index 00000000000..ebab3db7308 --- /dev/null +++ b/tools/srxfixup/src/swapmem.c @@ -0,0 +1,66 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "srxfixup_internal.h" + +#if defined(__has_include) +#if __has_include() +// NOLINTNEXTLINE(misc-include-cleaner) +#include +#if _BYTE_ORDER != _LITTLE_ENDIAN +#define SWAPMEM_IS_NOT_BIG_ENDIAN +#endif +#endif +#endif + +#ifdef SWAPMEM_IS_NOT_BIG_ENDIAN +#include +#include +#endif + +void swapmemory(void *aaddr, const char *format, unsigned int times) +{ +#ifdef SWAPMEM_IS_NOT_BIG_ENDIAN + unsigned int i; + size_t j; + void *aaddr_cur; + size_t format_len; + + format_len = strlen(format); + + aaddr_cur = aaddr; + for ( i = 0; i < times; i += 1 ) + { + for ( j = 0; j < format_len; j += 1 ) + { + switch ( format[j] ) + { + case 'c': + aaddr_cur = (void *)(((uint8_t *)aaddr_cur) + 1); + break; + case 's': + *(uint16_t *)aaddr_cur = bswap16(*(uint16_t *)aaddr_cur); + aaddr_cur = (void *)(((uint8_t *)aaddr_cur) + 2); + break; + case 'l': + *(uint32_t *)aaddr_cur = bswap32(*(uint32_t *)aaddr_cur); + aaddr_cur = (void *)(((uint8_t *)aaddr_cur) + 4); + break; + default: + break; + } + } + } +#else + (void)aaddr; + (void)format; + (void)times; +#endif +}