From 141468f0cc8733eb40077a22cfcf548c4d368d0c Mon Sep 17 00:00:00 2001 From: uyjulian Date: Mon, 15 Aug 2022 00:50:50 -0500 Subject: [PATCH 1/2] Add ps2-irxgen tool --- tools/Makefile | 8 +- tools/ps2-irxgen/Makefile | 14 + tools/ps2-irxgen/src/elftypes.h | 245 ++++++++ tools/ps2-irxgen/src/irxtypes.h | 18 + tools/ps2-irxgen/src/ps2-irxgen.c | 931 ++++++++++++++++++++++++++++++ tools/ps2-irxgen/src/types.h | 117 ++++ 6 files changed, 1332 insertions(+), 1 deletion(-) create mode 100644 tools/ps2-irxgen/Makefile create mode 100644 tools/ps2-irxgen/src/elftypes.h create mode 100644 tools/ps2-irxgen/src/irxtypes.h create mode 100644 tools/ps2-irxgen/src/ps2-irxgen.c create mode 100644 tools/ps2-irxgen/src/types.h diff --git a/tools/Makefile b/tools/Makefile index 8a2884247a5..7a3c6f338d4 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -6,7 +6,13 @@ # Licenced under Academic Free License version 2.0 # Review ps2sdk README & LICENSE files for further details. -SUBDIRS = bin2s bin2c bin2o adpenc ps2adpcm \ +SUBDIRS = \ + adpenc \ + bin2c \ + bin2o \ + bin2s \ + ps2-irxgen \ + ps2adpcm \ # gensymtab include $(PS2SDKSRC)/Defs.make diff --git a/tools/ps2-irxgen/Makefile b/tools/ps2-irxgen/Makefile new file mode 100644 index 00000000000..3b8212add47 --- /dev/null +++ b/tools/ps2-irxgen/Makefile @@ -0,0 +1,14 @@ +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ 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_OBJS = ps2-irxgen.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/ps2-irxgen/src/elftypes.h b/tools/ps2-irxgen/src/elftypes.h new file mode 100644 index 00000000000..1da8be79211 --- /dev/null +++ b/tools/ps2-irxgen/src/elftypes.h @@ -0,0 +1,245 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ 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. +*/ + +#ifndef __ELF_TYPES_H__ +#define __ELF_TYPES_H__ + +#include "types.h" + +#define ELF_MACHINE_MIPS 0x0008 +#define ELF_SH_STRTAB ".shstrtab" + +#define ELF_SECT_MAX_NAME 128 + +/* Structure defining a single elf section */ +struct ElfSection +{ + /* Name index */ + uint32_t iName; + /* Type of section */ + uint32_t iType; + /* Section flags */ + uint32_t iFlags; + /* Addr of section when loaded */ + uint32_t iAddr; + /* Offset of the section in the elf */ + uint32_t iOffset; + /* Size of the sections data */ + uint32_t iSize; + /* Link info */ + uint32_t iLink; + /* Info */ + uint32_t iInfo; + /* Address alignment */ + uint32_t iAddralign; + /* Entry size */ + uint32_t iEntsize; + + /* Aliased pointer to the data (in the original Elf) */ + uint8_t *pData; + /* Name of the section */ + char szName[ELF_SECT_MAX_NAME]; + /* Index */ + int iIndex; + /* Section Ref. Used for relocations */ + struct ElfSection *pRef; + /* Indicates if this section is to be outputted */ + int blOutput; +}; + +struct ElfProgram +{ + uint32_t iType; + uint32_t iOffset; + uint32_t iVaddr; + uint32_t iPaddr; + uint32_t iFilesz; + uint32_t iMemsz; + uint32_t iFlags; + uint32_t iAlign; + + /* Aliased pointer to the data (in the original Elf)*/ + uint8_t *pData; +}; + +/* Structure to hold elf header data, in native format */ +struct ElfHeader +{ + uint32_t iMagic; + uint32_t iClass; + uint32_t iData; + uint32_t iIdver; + uint32_t iType; + uint32_t iMachine; + uint32_t iVersion; + uint32_t iEntry; + uint32_t iPhoff; + uint32_t iShoff; + uint32_t iFlags; + uint32_t iEhsize; + uint32_t iPhentsize; + uint32_t iPhnum; + uint32_t iShentsize; + uint32_t iShnum; + uint32_t iShstrndx; +}; + +struct ElfReloc +{ + /* Pointer to the section name */ + const char* secname; + /* Base address */ + uint32_t base; + /* Type */ + uint32_t type; + /* Symbol (if known) */ + uint32_t symbol; + /* Offset into the file */ + uint32_t offset; + /* New Address for the relocation (to do with what you will) */ + uint32_t addr; +}; + +/* Define ELF types */ +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +#define ELF_MAGIC 0x464C457F + +#define ELF_EXEC_TYPE 0x0002 +#define ELF_IRX_TYPE 0xFF80 + +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +#define SHT_LOPROC_EE_IMPORT_TAB 0x90 +#define SHT_LOPROC_IOPMOD 0x80 + +// MIPS Reloc Entry Types +#define R_MIPS_NONE 0 +#define R_MIPS_16 1 +#define R_MIPS_32 2 +#define R_MIPS_REL32 3 +#define R_MIPS_26 4 +#define R_MIPS_HI16 5 +#define R_MIPS_LO16 6 +#define R_MIPS_GPREL16 7 +#define R_MIPS_LITERAL 8 +#define R_MIPS_GOT16 9 +#define R_MIPS_PC16 10 +#define R_MIPS_CALL16 11 +#define R_MIPS_GPREL32 12 + +#define SHF_WRITE 1 +#define SHF_ALLOC 2 +#define SHF_EXECINSTR 4 + +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +/* ELF file header */ +typedef struct { + Elf32_Word e_magic; + uint8_t e_class; + uint8_t e_data; + uint8_t e_idver; + uint8_t e_pad[9]; + 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; +} __attribute__((packed)) Elf32_Ehdr; + +/* ELF section header */ +typedef struct { + 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; +} __attribute__((packed)) Elf32_Shdr; + +typedef struct { + 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; + +#define ELF32_R_SYM(i) ((i)>>8) +#define ELF32_R_TYPE(i) ((uint8_t)(i&0xFF)) + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} __attribute__((packed)) Elf32_Sym; + +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +#define ELF32_ST_BIND(i) ((i)>>4) +#define ELF32_ST_TYPE(i) ((i)&0xf) +#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) + +#endif diff --git a/tools/ps2-irxgen/src/irxtypes.h b/tools/ps2-irxgen/src/irxtypes.h new file mode 100644 index 00000000000..437b86f2b01 --- /dev/null +++ b/tools/ps2-irxgen/src/irxtypes.h @@ -0,0 +1,18 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ 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. +*/ + +#ifndef __PRXTYPES_H__ +#define __PRXTYPES_H__ + +#include "types.h" + +#define PS2_MODULE_INFO_NAME ".iopmod" + +#endif diff --git a/tools/ps2-irxgen/src/ps2-irxgen.c b/tools/ps2-irxgen/src/ps2-irxgen.c new file mode 100644 index 00000000000..7365f2726d7 --- /dev/null +++ b/tools/ps2-irxgen/src/ps2-irxgen.c @@ -0,0 +1,931 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ 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. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "elftypes.h" +#include "irxtypes.h" + +/* Arrangement of ELF file after stripping + * + * ELF Header - 52 bytes + * Program Headers + * .text data + * .data data + * Section Headers + * Relocation data + * Section Header String Table + * + * When stripping the sections remove anything which isn't an allocated section or a relocation section. + * The section string section we will rebuild. + */ + +static const char *g_outfile; +static const char *g_infile; +static unsigned char *g_elfdata = NULL; +static struct ElfHeader g_elfhead = {0}; +static struct ElfSection *g_elfsections = NULL; +static struct ElfSection *g_iopmod = NULL; +static int g_out_sects = 2; +static int g_alloc_size = 0; +static int g_mem_size = 0; +static int g_reloc_size = 0; +static int g_str_size = 1; + +/* Base addresses in the Elf */ +static int g_phbase = 0; +static int g_iopmodbase = 0; +static int g_allocbase = 0; +static int g_shbase = 0; +static int g_relocbase = 0; +static int g_shstrbase = 0; + +/* Specifies that the current usage is to print additional debugging information */ +static int g_verbose = 0; + +static struct option arg_opts[] = +{ + {"verbose", no_argument, NULL, 'v'}, + { NULL, 0, NULL, 0 } +}; + +/* Process the arguments */ +int process_args(int argc, char **argv) +{ + int ch; + + g_outfile = NULL; + g_infile = NULL; + + ch = getopt_long(argc, argv, "v", arg_opts, NULL); + while(ch != -1) + { + switch(ch) + { + case 'v' : g_verbose = 1; + break; + default : break; + }; + + ch = getopt_long(argc, argv, "v", arg_opts, NULL); + } + + argc -= optind; + argv += optind; + + if(argc < 2) + { + return 0; + } + + g_infile = argv[0]; + g_outfile = argv[1]; + + if(g_verbose) + { + fprintf(stderr, "Loading %s, outputting to %s\n", g_infile, g_outfile); + } + + return 1; +} + +void print_help(void) +{ + fprintf(stderr, "Usage: ps2-irxgen [-v] infile.elf outfile.irx\n"); + fprintf(stderr, "Options:\n"); + fprintf(stderr, "-v, --verbose : Verbose output\n"); +} + +unsigned char *load_file(const char *file) +{ + unsigned char *data = NULL; + + do + { + FILE *fp; + + fp = fopen(file, "rb"); + if(fp != NULL) + { + unsigned int size; + + (void) fseek(fp, 0, SEEK_END); + size = ftell(fp); + rewind(fp); + + if(size < sizeof(Elf32_Ehdr)) + { + fprintf(stderr, "Error, invalid file size\n"); + fclose(fp); + break; + } + + data = (unsigned char *) malloc(size); + if(data == NULL) + { + fprintf(stderr, "Error, could not allocate memory for ELF\n"); + fclose(fp); + break; + } + + (void) fread(data, 1, size, fp); + fclose(fp); + } + else + { + fprintf(stderr, "Error, could not find file %s\n", file); + } + } + while(0); + + return data; +} + +/* Validate the ELF header */ +int validate_header(unsigned char *data) +{ + Elf32_Ehdr *head; + int ret = 0; + + head = (Elf32_Ehdr*) data; + + do + { + /* Read in the header structure */ + g_elfhead.iMagic = LW(head->e_magic); + g_elfhead.iClass = head->e_class; + g_elfhead.iData = head->e_data; + g_elfhead.iIdver = head->e_idver; + g_elfhead.iType = LH(head->e_type); + g_elfhead.iMachine = LH(head->e_machine); + g_elfhead.iVersion = LW(head->e_version); + g_elfhead.iEntry = LW(head->e_entry); + g_elfhead.iPhoff = LW(head->e_phoff); + g_elfhead.iShoff = LW(head->e_shoff); + g_elfhead.iFlags = LW(head->e_flags); + g_elfhead.iEhsize = LH(head->e_ehsize); + g_elfhead.iPhentsize = LH(head->e_phentsize); + g_elfhead.iPhnum = LH(head->e_phnum); + g_elfhead.iShentsize = LH(head->e_shentsize); + g_elfhead.iShnum = LH(head->e_shnum); + g_elfhead.iShstrndx = LH(head->e_shstrndx); + + if(g_verbose) + { + fprintf(stderr, "Magic %08X, Class %02X, Data %02X, Idver %02X\n", g_elfhead.iMagic, + g_elfhead.iClass, g_elfhead.iData, g_elfhead.iIdver); + fprintf(stderr, "Type %04X, Machine %04X, Version %08X, Entry %08X\n", g_elfhead.iType, + g_elfhead.iMachine, g_elfhead.iVersion, g_elfhead.iEntry); + fprintf(stderr, "Phoff %08X, Shoff %08X, Flags %08X, Ehsize %08X\n", g_elfhead.iPhoff, + g_elfhead.iShoff, g_elfhead.iFlags, g_elfhead.iEhsize); + fprintf(stderr, "Phentsize %04X, Phnum %04X\n", g_elfhead.iPhentsize, g_elfhead.iPhnum); + fprintf(stderr, "Shentsize %04X, Shnum %08X, Shstrndx %04X\n", g_elfhead.iShentsize, + g_elfhead.iShnum, g_elfhead.iShstrndx); + } + + if(g_elfhead.iMagic != ELF_MAGIC) + { + fprintf(stderr, "Error, invalid magic in the header\n"); + break; + } + + if((g_elfhead.iType != ELF_EXEC_TYPE) && (g_elfhead.iType != ELF_IRX_TYPE)) + { + fprintf(stderr, "Error, not EXEC type elf\n"); + break; + } + + if(g_elfhead.iMachine != ELF_MACHINE_MIPS) + { + fprintf(stderr, "Error, not MIPS type ELF\n"); + break; + } + + if(g_elfhead.iShnum < g_elfhead.iShstrndx) + { + fprintf(stderr, "Error, number of headers is less than section string index\n"); + break; + } + + ret = 1; + } + while(0); + + return ret; +} + +/* Load sections into ram */ +int load_sections(unsigned char *data) +{ + int ret = 0; + + if(g_elfhead.iShnum > 0) + { + do + { + int i; + unsigned int load_addr = 0xFFFFFFFF; + int found_rel = 0; + + g_elfsections = (struct ElfSection *) malloc(sizeof(struct ElfSection) * g_elfhead.iShnum); + if(g_elfsections == NULL) + { + fprintf(stderr, "Error, could not allocate memory for sections\n"); + break; + } + + memset(g_elfsections, 0, sizeof(struct ElfSection) * g_elfhead.iShnum); + + for(i = 0; i < g_elfhead.iShnum; i++) + { + Elf32_Shdr *sect; + + sect = (Elf32_Shdr *) (g_elfdata + g_elfhead.iShoff + (i * g_elfhead.iShentsize)); + + g_elfsections[i].iName = LW(sect->sh_name); + g_elfsections[i].iType = LW(sect->sh_type); + g_elfsections[i].iAddr = LW(sect->sh_addr); + g_elfsections[i].iFlags = LW(sect->sh_flags); + g_elfsections[i].iOffset = LW(sect->sh_offset); + g_elfsections[i].iSize = LW(sect->sh_size); + g_elfsections[i].iLink = LW(sect->sh_link); + g_elfsections[i].iInfo = LW(sect->sh_info); + g_elfsections[i].iAddralign = LW(sect->sh_addralign); + g_elfsections[i].iEntsize = LW(sect->sh_entsize); + g_elfsections[i].iIndex = i; + + if(g_elfsections[i].iOffset != 0) + { + g_elfsections[i].pData = g_elfdata + g_elfsections[i].iOffset; + } + + if(g_elfsections[i].iFlags & SHF_ALLOC) + { + g_elfsections[i].blOutput = 1; + if(g_elfsections[i].iAddr < load_addr) + { + load_addr = g_elfsections[i].iAddr; + } + } + } + + /* Okay so we have loaded all the sections, lets find relocations and fix up the names */ + for(i = 0; i < g_elfhead.iShnum; i++) + { + if(((g_elfsections[i].iType == SHT_REL)) + && (g_elfsections[g_elfsections[i].iInfo].iFlags & SHF_ALLOC)) + { + g_elfsections[i].pRef = &g_elfsections[g_elfsections[i].iInfo]; + found_rel = 1; + g_elfsections[i].blOutput = 1; + } + + strcpy(g_elfsections[i].szName, (char *) (g_elfsections[g_elfhead.iShstrndx].pData + g_elfsections[i].iName)); + if(strcmp(g_elfsections[i].szName, PS2_MODULE_INFO_NAME) == 0) + { + g_elfsections[i].blOutput = 1; + g_iopmod = &g_elfsections[i]; + g_iopmod->iType = SHT_LOPROC | SHT_LOPROC_IOPMOD; + } + } + + if(g_verbose) + { + for(i = 0; i < g_elfhead.iShnum; i++) + { + fprintf(stderr, "\nSection %d: %s\n", i, g_elfsections[i].szName); + fprintf(stderr, "Name %08X, Type %08X, Flags %08X, Addr %08X\n", + g_elfsections[i].iName, g_elfsections[i].iType, + g_elfsections[i].iFlags, g_elfsections[i].iAddr); + fprintf(stderr, "Offset %08X, Size %08X, Link %08X, Info %08X\n", + g_elfsections[i].iOffset, g_elfsections[i].iSize, + g_elfsections[i].iLink, g_elfsections[i].iInfo); + fprintf(stderr, "Addralign %08X, Entsize %08X pData %p\n", + g_elfsections[i].iAddralign, g_elfsections[i].iEntsize, + g_elfsections[i].pData); + } + + fprintf(stderr, "ELF Load Base address %08X\n", load_addr); + } + + if(!found_rel) + { + fprintf(stderr, "Error, found no relocation sections\n"); + break; + } + + if(g_iopmod == NULL) + { + fprintf(stderr, "Error, found no iopmod sections\n"); + break; + } + + if(load_addr != 0) + { + fprintf(stderr, "Error, ELF not loaded to address 0 (%08X)\n", load_addr); + break; + } + + ret = 1; + } + while(0); + } + else + { + fprintf(stderr, "Error, no sections in the ELF\n"); + } + + return ret; +} + +int remove_weak_relocs(struct ElfSection *pReloc, struct ElfSection *pSymbol, struct ElfSection *pString) +{ + unsigned int iCount; + unsigned int iMaxSymbol; + void *pNewRel = NULL; + Elf32_Rel *pInRel; + Elf32_Rel *pOutRel; + Elf32_Sym *pSymData = (Elf32_Sym *) pSymbol->pData; + char *pStrData = NULL; + unsigned int iOutput; + unsigned int i; + + if(pString != NULL) + { + pStrData = (char *) pString->pData; + } + + iMaxSymbol = pSymbol->iSize / sizeof(Elf32_Sym); + iCount = pReloc->iSize / sizeof(Elf32_Rel); + + pNewRel = malloc(pReloc->iSize); + if(pNewRel == NULL) + { + return 0; + } + pOutRel = (Elf32_Rel *) pNewRel; + pInRel = (Elf32_Rel *) pReloc->pData; + iOutput = 0; + + if(g_verbose) + { + fprintf(stderr, "[%s] Processing %u relocations, %u symbols\n", pReloc->szName, iCount, iMaxSymbol); + } + + for(i = 0; i < iCount; i++) + { + unsigned int iSymbol; + + iSymbol = ELF32_R_SYM(LW(pInRel->r_info)); + if(g_verbose) + { + fprintf(stderr, "Relocation %u - Symbol %x\n", iOutput, iSymbol); + } + + if(iSymbol >= iMaxSymbol) + { + fprintf(stderr, "Warning: Ignoring relocation as cannot find matching symbol\n"); + } + else + { + if(g_verbose) + { + if(pStrData != NULL) + { + fprintf(stderr, "Symbol %u - Name %s info %x ndx %x\n", iSymbol, &pStrData[pSymData[iSymbol].st_name], + pSymData[iSymbol].st_info, pSymData[iSymbol].st_shndx); + } + else + { + fprintf(stderr, "Symbol %u - Name %u info %x ndx %x\n", iSymbol, pSymData[iSymbol].st_name, + pSymData[iSymbol].st_info, pSymData[iSymbol].st_shndx); + } + } + + /* We are keeping this relocation, copy it across */ + *pOutRel = *pInRel; + pOutRel++; + iOutput++; + } + + pInRel++; + } + + /* If we deleted some relocations */ + if(iOutput < iCount) + { + uint32_t iSize; + + iSize = iOutput * sizeof(Elf32_Rel); + if(g_verbose) + { + fprintf(stderr, "Old relocation size %u, new %u\n", pReloc->iSize, iSize); + } + pReloc->iSize = iSize; + /* If size is zero then delete this section */ + if(iSize == 0) + { + pReloc->blOutput = 0; + } + else + { + /* Copy across the new relocation data */ + memcpy(pReloc->pData, pNewRel, pReloc->iSize); + } + } + + free(pNewRel); + + return 1; +} + +/* Let's remove the weak relocations from the list */ +int process_relocs(void) +{ + int i; + + for(i = 0; i < g_elfhead.iShnum; i++) + { + if((g_elfsections[i].blOutput) && (g_elfsections[i].iType == SHT_REL)) + { + struct ElfSection *pReloc; + + pReloc = &g_elfsections[i]; + if((pReloc->iLink < g_elfhead.iShnum) && (g_elfsections[pReloc->iLink].iType == SHT_SYMTAB)) + { + struct ElfSection *pStrings = NULL; + struct ElfSection *pSymbols; + + pSymbols = &g_elfsections[pReloc->iLink]; + if((pSymbols->iLink < g_elfhead.iShnum) && (g_elfsections[pSymbols->iLink].iType == SHT_STRTAB)) + { + pStrings = &g_elfsections[pSymbols->iLink]; + } + + if(!remove_weak_relocs(pReloc, pSymbols, pStrings)) + { + return 0; + } + } + else + { + if(g_verbose) + { + fprintf(stderr, "Ignoring relocation section %d, invalid link number\n", i); + } + } + } + } + + return 1; +} + +/* Reindex the sections we are keeping */ +void reindex_sections(void) +{ + int i; + int sect = 1; + + for(i = 0; i < g_elfhead.iShnum; i++) + { + if(g_elfsections[i].blOutput) + { + g_elfsections[i].iIndex = sect++; + } + } +} + +/* Load an ELF file */ +int load_elf(const char *elf) +{ + int ret = 0; + + do + { + g_elfdata = load_file(elf); + if(g_elfdata == NULL) + { + break; + } + + if(!validate_header(g_elfdata)) + { + break; + } + + if(!load_sections(g_elfdata)) + { + break; + } + + if(!process_relocs()) + { + break; + } + + reindex_sections(); + + ret = 1; + } + while(0); + + return ret; +} + +int calculate_outsize(void) +{ + /* out_sects starts at two for the null section and the section string table */ + int out_sects = 2; + int alloc_size = 0; + int reloc_size = 0; + int mem_size = 0; + /* 1 for the NUL for the NULL section */ + int str_size = 1; + int i; + + /* Calculate how big our output file needs to be */ + /* We have elf header + 1 PH + allocated data + section headers + relocation data */ + + /* Note that the ELF should be based from 0, we use this to calculate the alloc and mem sizes */ + + /* Skip null section */ + for(i = 1; i < g_elfhead.iShnum; i++) + { + if(g_elfsections[i].blOutput) + { + if(g_elfsections[i].iType == SHT_PROGBITS) + { + unsigned int top_addr; + + top_addr = g_elfsections[i].iAddr + g_elfsections[i].iSize; + + if(top_addr > alloc_size) + { + alloc_size = top_addr; + } + + if(top_addr > mem_size) + { + mem_size = top_addr; + } + + str_size += strlen(g_elfsections[i].szName) + 1; + } + else if(g_elfsections[i].iType == SHT_REL) + { + reloc_size += g_elfsections[i].iSize; + str_size += strlen(g_elfsections[i].szName) + 1; + } + else + { + unsigned int top_addr; + + top_addr = g_elfsections[i].iAddr + g_elfsections[i].iSize; + + if(top_addr > mem_size) + { + mem_size = top_addr; + } + + str_size += strlen(g_elfsections[i].szName) + 1; + } + out_sects++; + } + } + + alloc_size = (alloc_size + 3) & ~3; + mem_size = (mem_size + 3) & ~3; + str_size = (str_size + 3) & ~3; + str_size += strlen(ELF_SH_STRTAB) + 1; + + if(g_verbose) + { + fprintf(stderr, "Out_sects %d, alloc_size %d, reloc_size %d, str_size %d, mem_size %d\n", + out_sects, alloc_size, reloc_size, str_size, mem_size); + } + + /* Save them for future use */ + g_out_sects = out_sects; + g_alloc_size = alloc_size; + g_reloc_size = reloc_size; + g_mem_size = mem_size; + g_str_size = str_size; + + /* Lets build the offsets */ + g_phbase = sizeof(Elf32_Ehdr); + /* The allocated data needs to be 4 byte aligned */ + g_iopmodbase = (g_phbase + (2 * sizeof(Elf32_Phdr)) + 0x3) & ~0x3; + /* The allocated data needs to be 16 byte aligned */ + g_allocbase = (g_iopmodbase + g_iopmod->iSize + 0xF) & ~0xF; + g_shbase = g_allocbase + g_alloc_size; + g_relocbase = g_shbase + (g_out_sects * sizeof(Elf32_Shdr)); + g_shstrbase = g_relocbase + g_reloc_size; + + if(g_verbose) + { + fprintf(stderr, "PHBase %08X, AllocBase %08X, SHBase %08X\n", g_phbase, g_allocbase, g_shbase); + fprintf(stderr, "Relocbase %08X, Shstrbase %08X\n", g_relocbase, g_shstrbase); + fprintf(stderr, "Total size %d\n", g_shstrbase + g_str_size); + } + + return (g_shstrbase + g_str_size); +} + +/* Output the ELF header */ +void output_header(unsigned char *data) +{ + Elf32_Ehdr *head; + + head = (Elf32_Ehdr*) data; + + SW(&head->e_magic, g_elfhead.iMagic); + head->e_class = g_elfhead.iClass; + head->e_data = g_elfhead.iData; + head->e_idver = g_elfhead.iIdver; + SH(&head->e_type, ELF_IRX_TYPE); + SH(&head->e_machine, g_elfhead.iMachine); + SW(&head->e_version, g_elfhead.iVersion); + SW(&head->e_entry, g_elfhead.iEntry); + SW(&head->e_phoff, g_phbase); + SW(&head->e_shoff, g_shbase); + SW(&head->e_flags, g_elfhead.iFlags); + SH(&head->e_ehsize, sizeof(Elf32_Ehdr)); + SH(&head->e_phentsize, sizeof(Elf32_Phdr)); + SH(&head->e_phnum, 2); + SH(&head->e_shentsize, sizeof(Elf32_Shdr)); + SH(&head->e_shnum, g_out_sects); + SH(&head->e_shstrndx, g_out_sects-1); +} + +/* Output the iopmod program header */ +void output_ph_iopmod(unsigned char *data) +{ + Elf32_Phdr *phdr; + + phdr = (Elf32_Phdr*) data; + + SW(&phdr->p_type, SHT_LOPROC | SHT_LOPROC_IOPMOD); + /* Starts after the program header */ + SW(&phdr->p_offset, g_iopmodbase); + SW(&phdr->p_vaddr, 0); + SW(&phdr->p_paddr, 0); + SW(&phdr->p_filesz, g_iopmod->iSize); + SW(&phdr->p_memsz, 0); + SW(&phdr->p_flags, 4); + SW(&phdr->p_align, 0x4); +} + +/* Output the program header */ +void output_ph(unsigned char *data) +{ + Elf32_Phdr *phdr; + + phdr = (Elf32_Phdr*) data; + + SW(&phdr->p_type, 1); + /* Starts after the program header */ + SW(&phdr->p_offset, g_allocbase); + SW(&phdr->p_vaddr, 0); + SW(&phdr->p_paddr, 0); + SW(&phdr->p_filesz, g_alloc_size); + SW(&phdr->p_memsz, g_mem_size); + SW(&phdr->p_flags, 7); + SW(&phdr->p_align, 0x10); +} + +/* Output the allocated sections */ +void output_alloc(unsigned char *data) +{ + int i; + + for(i = 0; i < g_elfhead.iShnum; i++) + { + if((g_elfsections[i].blOutput) && (g_elfsections[i].iType == SHT_PROGBITS)) + { + memcpy(&data[g_elfsections[i].iAddr], g_elfsections[i].pData, g_elfsections[i].iSize); + } + } +} + +/* Output the iopmod section */ +void output_iopmod(unsigned char *data) +{ + memcpy(data, g_iopmod->pData, g_iopmod->iSize); +} + +/* Output the section headers */ +void output_sh(unsigned char *data) +{ + unsigned int reloc_ofs; + unsigned int str_ofs; + Elf32_Shdr *shdr; + int i; + + shdr = (Elf32_Shdr*) data; + /* For the NULL section */ + shdr++; + memset(data, 0, g_out_sects * sizeof(Elf32_Shdr)); + + reloc_ofs = g_relocbase; + str_ofs = 1; + + for(i = 1; i < g_elfhead.iShnum; i++) + { + if(g_elfsections[i].blOutput) + { + SW(&shdr->sh_name, str_ofs); + str_ofs += strlen(g_elfsections[i].szName) + 1; + SW(&shdr->sh_flags, g_elfsections[i].iFlags); + SW(&shdr->sh_addr, g_elfsections[i].iAddr); + SW(&shdr->sh_size, g_elfsections[i].iSize); + /* Note: this is safe set to zero for REL sections, despite the readelf warnings */ + SW(&shdr->sh_link, 0); + SW(&shdr->sh_addralign, g_elfsections[i].iAddralign); + SW(&shdr->sh_entsize, g_elfsections[i].iEntsize); + + if(g_elfsections[i].iType == SHT_REL) + { + SW(&shdr->sh_type, SHT_REL); + if (g_elfsections[i].pRef) + SW(&shdr->sh_info, g_elfsections[i].pRef->iIndex); + else + SW(&shdr->sh_info, 0); + SW(&shdr->sh_offset, reloc_ofs); + reloc_ofs += g_elfsections[i].iSize; + } + else if(g_elfsections[i].iType == SHT_PROGBITS) + { + SW(&shdr->sh_type, g_elfsections[i].iType); + SW(&shdr->sh_info, 0); + SW(&shdr->sh_offset, g_allocbase + g_elfsections[i].iAddr); + } + else if(&g_elfsections[i] == g_iopmod) + { + SW(&shdr->sh_type, g_elfsections[i].iType); + SW(&shdr->sh_info, 0); + SW(&shdr->sh_offset, g_iopmodbase); + } + else + { + SW(&shdr->sh_type, g_elfsections[i].iType); + SW(&shdr->sh_info, 0); + /* Point it to the end of the allocated section */ + SW(&shdr->sh_offset, g_allocbase + g_alloc_size); + } + + shdr++; + } + } + + /* Fill in the shstrtab section */ + SW(&shdr->sh_name, str_ofs); + SW(&shdr->sh_flags, 0); + SW(&shdr->sh_addr, 0); + SW(&shdr->sh_size, g_str_size); + SW(&shdr->sh_link, 0); + SW(&shdr->sh_addralign, 1); + SW(&shdr->sh_entsize, 0); + SW(&shdr->sh_type, SHT_STRTAB); + SW(&shdr->sh_info, 0); + SW(&shdr->sh_offset, g_shstrbase); +} + +/* Output relocations */ +void output_relocs(unsigned char *data) +{ + int i; + unsigned char *pReloc; + + pReloc = data; + + for(i = 0; i < g_elfhead.iShnum; i++) + { + if((g_elfsections[i].blOutput) && + ((g_elfsections[i].iType == SHT_REL))) + { + memcpy(pReloc, g_elfsections[i].pData, g_elfsections[i].iSize); + pReloc += g_elfsections[i].iSize; + } + } +} + +/* Output the section header string table */ +void output_shstrtab(unsigned char *data) +{ + int i; + char *pData; + + /* For the NULL section, memory should be zeroed anyway */ + memset(data, 0, g_str_size); + pData = (char *) (data + 1); + + for(i = 1; i < g_elfhead.iShnum; i++) + { + if(g_elfsections[i].blOutput) + { + if(g_verbose) + { + fprintf(stderr, "String %d: %s\n", i, g_elfsections[i].szName); + } + + strcpy(pData, g_elfsections[i].szName); + pData += strlen(g_elfsections[i].szName) + 1; + } + } + + strcpy(pData, ELF_SH_STRTAB); +} + +/* Output a stripped irx file */ +int output_irx(const char *irxfile) +{ + do + { + int size; + unsigned char *data; + FILE *fp; + + size = calculate_outsize(); + data = (unsigned char *) malloc(size); + if(data == NULL) + { + fprintf(stderr, "Error, couldn't allocate output data\n"); + break; + } + + memset(data, 0, size); + + output_header(data); + output_ph_iopmod(data + g_phbase); + output_ph(data + g_phbase + sizeof(Elf32_Phdr)); + output_iopmod(data + g_iopmodbase); + output_alloc(data + g_allocbase); + output_sh(data + g_shbase); + output_relocs(data + g_relocbase); + output_shstrtab(data + g_shstrbase); + + fp = fopen(irxfile, "wb"); + if(fp != NULL) + { + fwrite(data, 1, size, fp); + fclose(fp); + } + else + { + fprintf(stderr, "Error, could not open output file %s\n", irxfile); + } + + free(data); + } + while(0); + + return 0; +} + +/* Free allocated memory */ +void free_data(void) +{ + if(g_elfdata != NULL) + { + free(g_elfdata); + g_elfdata = NULL; + } + + if(g_elfsections != NULL) + { + free(g_elfsections); + g_elfsections = NULL; + } +} + +int main(int argc, char **argv) +{ + if(process_args(argc, argv)) + { + if(load_elf(g_infile)) + { + (void) output_irx(g_outfile); + free_data(); + } + } + else + { + print_help(); + } + + return 0; +} diff --git a/tools/ps2-irxgen/src/types.h b/tools/ps2-irxgen/src/types.h new file mode 100644 index 00000000000..18557ad1aa4 --- /dev/null +++ b/tools/ps2-irxgen/src/types.h @@ -0,0 +1,117 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ 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. +*/ + +#ifndef __TYPES_H__ +#define __TYPES_H__ + +#include + +static inline uint32_t lw_le(uint32_t data) +{ + uint8_t *ptr; + uint32_t val; + + ptr = (uint8_t*) &data; + + val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); + + return val; +} + +static inline uint16_t lh_le(uint16_t data) +{ + uint8_t *ptr; + uint16_t val; + + ptr = (uint8_t*) &data; + + val = ptr[0] | (ptr[1] << 8); + + return val; +} + +static inline uint32_t lw_be(uint32_t data) +{ + uint8_t *ptr; + uint32_t val; + + ptr = (uint8_t*) &data; + + val = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3]; + + return val; +} + +static inline uint16_t lh_be(uint16_t data) +{ + uint8_t *ptr; + uint16_t val; + + ptr = (uint8_t*) &data; + + val = (ptr[0] << 16) | ptr[1]; + + return val; +} + +#define LW_LE(x) (lw_le((x))) +#define LW_BE(x) (lw_be((x))) +#define LH_LE(x) (lh_le((x))) +#define LH_BE(x) (lh_be((x))) + +#define LW(x) (LW_LE(x)) +#define LH(x) (LH_LE(x)) + + +static inline void sw_le(uint8_t *data, uint32_t val) +{ + uint8_t* ptr = (uint8_t*) data; + + ptr[0] = (uint8_t) (val & 0xFF); + ptr[1] = (uint8_t) ((val >> 8) & 0xFF); + ptr[2] = (uint8_t) ((val >> 16) & 0xFF); + ptr[3] = (uint8_t) ((val >> 24) & 0xFF); +} + +static inline void sh_le(uint8_t *data, uint16_t val) +{ + uint8_t *ptr = (uint8_t*) data; + + ptr[0] = (uint8_t) (val & 0xFF); + ptr[1] = (uint8_t) ((val >> 8) & 0xFF); +} + +static inline void sw_be(uint8_t *data, uint32_t val) +{ + uint8_t *ptr = (uint8_t*) data; + + ptr[0] = (uint8_t) ((val >> 24) & 0xFF); + ptr[1] = (uint8_t) ((val >> 16) & 0xFF); + ptr[2] = (uint8_t) ((val >> 8) & 0xFF); + ptr[3] = (uint8_t) (val & 0xFF); +} + +static inline void sh_be(uint8_t *data, uint16_t val) +{ + uint8_t* ptr = (uint8_t*) data; + + ptr[0] = (uint8_t) ((val >> 8) & 0xFF); + ptr[1] = (uint8_t) (val & 0xFF); +} + +#define SW_LE(x, v) (sw_le((uint8_t *)(x), (v))) +#define SW_BE(x, v) (sw_be((uint8_t *)(x), (v))) +#define SH_LE(x, v) (sh_le((uint8_t *)(x), (v))) +#define SH_BE(x, v) (sh_be((uint8_t *)(x), (v))) + +#define SW(x, v) (SW_LE(x, v)) +#define SH(x, v) (SH_LE(x, v)) + +#endif From ec1496d9079e7fae415fac850ee3c08e793bec63 Mon Sep 17 00:00:00 2001 From: uyjulian Date: Mon, 15 Aug 2022 00:51:07 -0500 Subject: [PATCH 2/2] Changes to use unpatched binutils for linking IRX --- Defs.make | 2 +- iop/Makefile | 18 ++++- iop/Rules.make | 21 ++++-- iop/Rules.release | 2 +- iop/kernel/include/irx.h | 16 +++-- iop/startup/Makefile | 20 ++++++ iop/startup/src/linkfile | 109 ++++++++++++++++++++++++++++++ samples/Makefile.iopglobal_sample | 19 ++++-- samples/Makefile.pref_sample | 2 +- 9 files changed, 190 insertions(+), 19 deletions(-) create mode 100644 iop/startup/Makefile create mode 100644 iop/startup/src/linkfile diff --git a/Defs.make b/Defs.make index 9a840b0204c..b7f005b9d55 100644 --- a/Defs.make +++ b/Defs.make @@ -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-ps2-elf- IOP_CC ?= $(IOP_TOOL_PREFIX)gcc IOP_AS ?= $(IOP_TOOL_PREFIX)as IOP_LD ?= $(IOP_TOOL_PREFIX)ld diff --git a/iop/Makefile b/iop/Makefile index 7cdefa51758..f69ede92d12 100644 --- a/iop/Makefile +++ b/iop/Makefile @@ -6,7 +6,23 @@ # Licenced under Academic Free License version 2.0 # Review ps2sdk README & LICENSE files for further details. -SUBDIRS = kernel dev9 fs hdd sound tcpip usb system debug memorycard network iLink cdvd sio dvrp +SUBDIRS = \ + cdvd \ + debug \ + dev9 \ + dvrp \ + fs \ + hdd \ + iLink \ + kernel \ + memorycard \ + network \ + sio \ + sound \ + startup \ + system \ + tcpip \ + usb include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/Rules.make diff --git a/iop/Rules.make b/iop/Rules.make index 971b4b8f822..c96b1668b42 100644 --- a/iop/Rules.make +++ b/iop/Rules.make @@ -37,7 +37,7 @@ ifeq ($(DEBUG),1) IOP_CFLAGS += -DDEBUG endif # Linker flags -IOP_LDFLAGS := -nostdlib -s $(IOP_LDFLAGS) +IOP_LDFLAGS := -Wl,--gpsize=0 -Wl,-G0 -Wl,--nmagic -Wl,--orphan-handling=error -Wl,--discard-all -Wl,--gc-sections -Wl,--emit-relocs -nostdlib -Wl,-z,max-page-size=128 -Wl,--no-relax $(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 @@ -66,8 +66,15 @@ 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) + # Externally defined variables: IOP_BIN, IOP_OBJS, IOP_LIB # These macros can be used to simplify certain build rules. @@ -90,6 +97,9 @@ $(IOP_OBJS_DIR)%.o: $(IOP_SRC_DIR)%.s .INTERMEDIATE: $(IOP_OBJS_DIR)build-imports.c $(IOP_OBJS_DIR)build-exports.c +$(PS2SDKSRC)/tools/ps2-irxgen/bin/ps2-irxgen: $(PS2SDKSRC)/tools/ps2-irxgen + $(MAKEREC) $< + # Rules to build imports.lst. $(IOP_OBJS_DIR)build-imports.c: $(IOP_SRC_DIR)imports.lst $(DIR_GUARD) @@ -110,10 +120,13 @@ $(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) $(IOP_OPTFLAGS) -o $(IOP_BIN) $(IOP_OBJS) $(IOP_LDFLAGS) $(IOP_LIBS) + $(IOP_C_COMPILE) -T$(IOP_LINKFILE) $(IOP_OPTFLAGS) -o $@ $(IOP_OBJS) $(IOP_LDFLAGS) $(IOP_LIBS) + +$(IOP_BIN): $(IOP_BIN_ELF) $(PS2SDKSRC)/tools/ps2-irxgen/bin/ps2-irxgen + $(PS2SDKSRC)/tools/ps2-irxgen/bin/ps2-irxgen $< $@ $(IOP_LIB): $(IOP_OBJS) $(DIR_GUARD) - $(IOP_AR) cru $(IOP_LIB) $(IOP_OBJS) + $(IOP_AR) cru $@ $(IOP_OBJS) diff --git a/iop/Rules.release b/iop/Rules.release index 268e42ca803..b38faab9a95 100644 --- a/iop/Rules.release +++ b/iop/Rules.release @@ -11,7 +11,7 @@ # Creates the base iop directory structure in target directory. # -RELEASE_IOP_DIRS = iop/ iop/include/sys/ iop/irx/ iop/lib +RELEASE_IOP_DIRS = iop/ iop/include/sys/ iop/irx/ iop/lib iop/startup RELEASE_IOP_DIRS := $(RELEASE_IOP_DIRS:%=$(PS2SDK)/%) diff --git a/iop/kernel/include/irx.h b/iop/kernel/include/irx.h index 2e605df2b4c..ec2aa53deac 100644 --- a/iop/kernel/include/irx.h +++ b/iop/kernel/include/irx.h @@ -28,7 +28,9 @@ struct irx_id { #define IRX_ID(name, major, minor) \ struct irx_id _irx_id = { \ name, IRX_VER(major, minor) \ -}; +}; \ +const u16 _irx_version __attribute__((section(".iopmod"))) = IRX_VER(major, minor); \ +const char _irx_name[] __attribute__((aligned(1),section(".iopmod"))) = name; /* * Module imports @@ -57,20 +59,20 @@ struct irx_import_stub */ #define DECLARE_IMPORT_TABLE(modname, major, minor) \ static struct irx_import_table _imp_##modname \ - __attribute__((section(".text\n\t#"), unused))= { \ + __attribute__((section(".module.imports\n\t#"), unused))= { \ magic: IMPORT_MAGIC, version: IRX_VER(major, minor), \ name: #modname, }; #define STR(val) #val // .word 0x03e00008 == jr $ra (return immediately), this value will be patched later #define DECLARE_IMPORT(ord, name) \ - __asm__ (".section\t.text\n\t" \ + __asm__ (".section\t.module.imports\n\t" \ ".globl\t"#name"\n\t"#name":\n\t" \ ".word 0x03e00008\n\t" \ ".word "STR(0x24000000|ord)); #define END_IMPORT_TABLE \ - __asm__ (".section\t.text\n\t.word\t0, 0"); + __asm__ (".section\t.module.imports\n\t.word\t0, 0"); /* * Module exports @@ -94,13 +96,13 @@ struct irx_export_table { #define DECLARE_EXPORT_TABLE(modname, major, minor) \ struct irx_export_table _exp_##modname \ - __attribute__((section(".text\n\t#"), unused)) = { \ + __attribute__((section(".module.exports\n\t#"), unused)) = { \ magic: EXPORT_MAGIC, version: IRX_VER(major, minor), \ name: #modname, }; #define DECLARE_EXPORT(fptr) \ - __asm__ (".section\t.text\n\t.word\t"STR(fptr)); + __asm__ (".section\t.module.exports\n\t.word\t"STR(fptr)); -#define END_EXPORT_TABLE __asm__ (".section\t.text\n\t.word\t0"); +#define END_EXPORT_TABLE __asm__ (".section\t.module.exports\n\t.word\t0"); #endif /* __IRX_H__ */ diff --git a/iop/startup/Makefile b/iop/startup/Makefile new file mode 100644 index 00000000000..feeef6fc473 --- /dev/null +++ b/iop/startup/Makefile @@ -0,0 +1,20 @@ +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. + +all: + +include $(PS2SDKSRC)/Defs.make +include $(PS2SDKSRC)/iop/Rules.make +include $(PS2SDKSRC)/iop/Rules.release + +clean: + +release: + $(ECHO) Installing $(IOP_SRC_DIR)linkfile into $(PS2SDK)/iop/startup + cp -f $(IOP_SRC_DIR)linkfile $(PS2SDK)/iop/startup + diff --git a/iop/startup/src/linkfile b/iop/startup/src/linkfile new file mode 100644 index 00000000000..9c27f218152 --- /dev/null +++ b/iop/startup/src/linkfile @@ -0,0 +1,109 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ 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. +# +# Linkfile script for iop-ld +*/ + +OUTPUT_FORMAT("elf32-littlemips") +SEARCH_DIR(""); +ENTRY(_start) +PHDRS +{ + irxhdr 0x70000080 FLAGS (PF_R); /* 0x70000080 -> PT_SCE_IOPMOD */ + defhdr PT_LOAD FLAGS (PF_X | PF_W | PF_R); +} +SECTIONS +{ + . = SIZEOF_HEADERS; + /* + * 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 )) ; + FILL(0x00000000); + } :irxhdr = 0 + + .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) ; + + /* + * 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 ) + /* + * 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 ) + } +} diff --git a/samples/Makefile.iopglobal_sample b/samples/Makefile.iopglobal_sample index ccf40b4d3ab..9fa500b002a 100644 --- a/samples/Makefile.iopglobal_sample +++ b/samples/Makefile.iopglobal_sample @@ -35,7 +35,7 @@ IOP_WARNFLAGS ?= -Wall # for finer-grained control over what goes into each IRX. IOP_CFLAGS := -D_IOP -fno-builtin -G0 $(IOP_OPTFLAGS) $(IOP_WARNFLAGS) $(IOP_INCS) $(IOP_CFLAGS) # linker flags -IOP_LDFLAGS := -nostdlib -s $(IOP_LDFLAGS) +IOP_LDFLAGS := -Wl,--gpsize=0 -Wl,-G0 -Wl,--nmagic -Wl,--orphan-handling=error -Wl,--discard-all -Wl,--gc-sections -Wl,--emit-relocs -nostdlib -Wl,-z,max-page-size=128 -Wl,--no-relax $(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 @@ -64,8 +64,15 @@ 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) + # Externally defined variables: IOP_BIN, IOP_OBJS, IOP_LIB # These macros can be used to simplify certain build rules. @@ -107,10 +114,14 @@ $(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): $(IOP_BIN_ELF) $(DIR_GUARD) - $(IOP_C_COMPILE) $(IOP_OPTFLAGS) -o $(IOP_BIN) $(IOP_OBJS) $(IOP_LDFLAGS) $(IOP_LIBS) + ps2-irxgen $< $@ $(IOP_LIB): $(IOP_OBJS) $(DIR_GUARD) - $(IOP_AR) cru $(IOP_LIB) $(IOP_OBJS) + $(IOP_AR) cru $@ $(IOP_OBJS) diff --git a/samples/Makefile.pref_sample b/samples/Makefile.pref_sample index b4648f71119..63d6a571122 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-ps2-elf- IOP_CC ?= $(IOP_TOOL_PREFIX)gcc IOP_AS ?= $(IOP_TOOL_PREFIX)as IOP_LD ?= $(IOP_TOOL_PREFIX)ld