vita-toolchain

git clone https://git.neptards.moe/neptards/vita-toolchain.git
Log | Files | Refs | README | LICENSE

vita-elf-create.c (7067B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <stdint.h>
      4 #include <string.h>
      5 
      6 #include <limits.h>
      7 
      8 #include <libelf.h>
      9 #include <gelf.h>
     10 
     11 #include "vita-elf.h"
     12 #include "vita-import.h"
     13 #include "vita-export.h"
     14 #include "elf-defs.h"
     15 #include "sce-elf.h"
     16 #include "elf-utils.h"
     17 #include "fail-utils.h"
     18 #include "elf-create-argp.h"
     19 
     20 // logging level
     21 int g_log = 0;
     22 
     23 #define NONE 0
     24 #define VERBOSE 1
     25 #define DEBUG 2
     26 
     27 #define TRACEF(lvl, ...) \
     28 	do { if (g_log >= lvl) printf(__VA_ARGS__); } while (0)
     29 
     30 void print_stubs(vita_elf_stub_t *stubs, int num_stubs)
     31 {
     32 	int i;
     33 
     34 	for (i = 0; i < num_stubs; i++) {
     35 		TRACEF(VERBOSE, "  0x%06x (%s):\n", stubs[i].addr, stubs[i].symbol ? stubs[i].symbol->name : "unreferenced stub");
     36 		TRACEF(VERBOSE, "    Flags  : %u\n", stubs[i].module ? stubs[i].module->flags : 0);
     37 		TRACEF(VERBOSE, "    Library: %u (%s)\n", stubs[i].module_nid, stubs[i].module ? stubs[i].module->name : "not found");
     38 		TRACEF(VERBOSE, "    NID    : %u (%s)\n", stubs[i].target_nid, stubs[i].target ? stubs[i].target->name : "not found");
     39 	}
     40 }
     41 
     42 const char *get_scn_name(vita_elf_t *ve, Elf_Scn *scn)
     43 {
     44 	size_t shstrndx;
     45 	GElf_Shdr shdr;
     46 
     47 	elf_getshdrstrndx(ve->elf, &shstrndx);
     48 	gelf_getshdr(scn, &shdr);
     49 	return elf_strptr(ve->elf, shstrndx, shdr.sh_name);
     50 }
     51 
     52 const char *get_scndx_name(vita_elf_t *ve, int scndx)
     53 {
     54 	return get_scn_name(ve, elf_getscn(ve->elf, scndx));
     55 }
     56 
     57 void print_rtable(vita_elf_rela_table_t *rtable)
     58 {
     59 	vita_elf_rela_t *rela;
     60 	int num_relas;
     61 
     62 	for (num_relas = rtable->num_relas, rela = rtable->relas; num_relas; num_relas--, rela++) {
     63 		if (rela->symbol) {
     64 			TRACEF(VERBOSE, "    offset %06x: type %s, %s%+d\n",
     65 					rela->offset,
     66 					elf_decode_r_type(rela->type),
     67 					rela->symbol->name, rela->addend);
     68 		} else if (rela->offset) {
     69 			TRACEF(VERBOSE, "    offset %06x: type %s, absolute %06x\n",
     70 					rela->offset,
     71 					elf_decode_r_type(rela->type),
     72 					(uint32_t)rela->addend);
     73 		}
     74 	}
     75 }
     76 
     77 void list_rels(vita_elf_t *ve)
     78 {
     79 	vita_elf_rela_table_t *rtable;
     80 
     81 	for (rtable = ve->rela_tables; rtable; rtable = rtable->next) {
     82 		TRACEF(VERBOSE, "  Relocations for section %d: %s\n",
     83 				rtable->target_ndx, get_scndx_name(ve, rtable->target_ndx));
     84 		print_rtable(rtable);
     85 
     86 	}
     87 }
     88 
     89 void list_segments(vita_elf_t *ve)
     90 {
     91 	int i;
     92 
     93 	for (i = 0; i < ve->num_segments; i++) {
     94 		TRACEF(VERBOSE, "  Segment %d: vaddr %06x, size 0x%x\n",
     95 				i, ve->segments[i].vaddr, ve->segments[i].memsz);
     96 		if (ve->segments[i].memsz) {
     97 			TRACEF(VERBOSE, "    Host address region: %p - %p\n",
     98 					ve->segments[i].vaddr_top, ve->segments[i].vaddr_bottom);
     99 			TRACEF(VERBOSE, "    4 bytes into segment (%p): %x\n",
    100 					ve->segments[i].vaddr_top + 4, vita_elf_host_to_vaddr(ve, ve->segments[i].vaddr_top + 4));
    101 			TRACEF(VERBOSE, "    addr of 8 bytes into segment (%x): %p\n",
    102 					ve->segments[i].vaddr + 8, vita_elf_vaddr_to_host(ve, ve->segments[i].vaddr + 8));
    103 			TRACEF(VERBOSE, "    12 bytes into segment offset (%p): %d\n",
    104 					ve->segments[i].vaddr_top + 12, vita_elf_host_to_segoffset(ve, ve->segments[i].vaddr_top + 12, i));
    105 			TRACEF(VERBOSE, "    addr of 16 bytes into segment (%d): %p\n",
    106 					16, vita_elf_segoffset_to_host(ve, i, 16));
    107 		}
    108 	}
    109 }
    110 
    111 #if defined(_WIN32) && !defined(__CYGWIN__)
    112 #define WIN32_LEAN_AND_MEAN
    113 #include <windows.h>
    114 #define strtok_r strtok_s
    115 #elif defined(__linux__) || defined(__CYGWIN__)
    116 #include <unistd.h>
    117 #elif defined(__APPLE__)
    118 #include <mach-o/dyld.h>
    119 #elif defined(__FreeBSD__)
    120 #include <sys/types.h>
    121 #include <sys/sysctl.h>
    122 #endif
    123 
    124 static int usage(int argc, char *argv[])
    125 {
    126 	fprintf(stderr, "usage: %s [-v|vv|vvv] [-n] [-e config.yml] input.elf output.velf\n"
    127 					"\t-v,-vv,-vvv:    logging verbosity (more v is more verbose)\n"
    128 					"\t-n         :    allow empty imports\n"
    129 					"\t-e yml     :    optional config options\n"
    130 					"\tinput.elf  :    input ARM ET_EXEC type ELF\n"
    131 					"\toutput.velf:    output ET_SCE_RELEXEC type ELF\n", argc > 0 ? argv[0] : "vita-elf-create");
    132 	return 0;
    133 }
    134 
    135 int main(int argc, char *argv[])
    136 {
    137 	vita_elf_t *ve;
    138 	sce_module_info_t *module_info;
    139 	sce_section_sizes_t section_sizes;
    140 	void *encoded_modinfo;
    141 	vita_elf_rela_table_t rtable = {};
    142 	vita_export_t *exports = NULL;
    143 	
    144 	int status = EXIT_SUCCESS;
    145 
    146 	elf_create_args args = {};
    147 	if (parse_arguments(argc, argv, &args) < 0) {
    148 		usage(argc, argv);
    149 		return EXIT_FAILURE;
    150 	}
    151 
    152 	g_log = args.log_level;
    153 
    154 	if ((ve = vita_elf_load(args.input, args.check_stub_count)) == NULL)
    155 		return EXIT_FAILURE;
    156 
    157 	/* FIXME: save original segment sizes */
    158 	Elf32_Word *segment_sizes = malloc(ve->num_segments * sizeof(Elf32_Word));
    159 	int idx;
    160 	for(idx = 0; idx < ve->num_segments; idx++)
    161 		segment_sizes[idx] = ve->segments[idx].memsz;
    162 
    163 	if (args.exports) {
    164 		exports = vita_exports_load(args.exports, args.input, 0);
    165 		
    166 		if (!exports)
    167 			return EXIT_FAILURE;
    168 	}
    169 	else {
    170 		// generate a default export list
    171 		exports = vita_export_generate_default(args.input);
    172 	}
    173 
    174 	if (!vita_elf_lookup_imports(ve))
    175 		status = EXIT_FAILURE;
    176 
    177 	if (ve->fstubs_va.count) {
    178 		TRACEF(VERBOSE, "Function stubs in sections \n");
    179 		print_stubs(ve->fstubs, ve->num_fstubs);
    180 	}
    181 	if (ve->vstubs_va.count) {
    182 		TRACEF(VERBOSE, "Variable stubs in sections \n");
    183 		print_stubs(ve->vstubs, ve->num_vstubs);
    184 	}
    185 
    186 	TRACEF(VERBOSE, "Relocations:\n");
    187 	list_rels(ve);
    188 
    189 	TRACEF(VERBOSE, "Segments:\n");
    190 	list_segments(ve);
    191 
    192 	module_info = sce_elf_module_info_create(ve, exports);
    193 
    194 	if (!module_info)
    195 		return EXIT_FAILURE;
    196 	
    197 	int total_size = sce_elf_module_info_get_size(module_info, &section_sizes);
    198 	int curpos = 0;
    199 	TRACEF(VERBOSE, "Total SCE data size: %d / %x\n", total_size, total_size);
    200 #define PRINTSEC(name) TRACEF(VERBOSE, "  .%.*s.%s: %d (%x @ %x)\n", (int)strcspn(#name,"_"), #name, strchr(#name,'_')+1, section_sizes.name, section_sizes.name, curpos+ve->segments[0].vaddr+ve->segments[0].memsz); curpos += section_sizes.name
    201 	PRINTSEC(sceModuleInfo_rodata);
    202 	PRINTSEC(sceLib_ent);
    203 	PRINTSEC(sceExport_rodata);
    204 	PRINTSEC(sceLib_stubs);
    205 	PRINTSEC(sceImport_rodata);
    206 	PRINTSEC(sceFNID_rodata);
    207 	PRINTSEC(sceFStub_rodata);
    208 	PRINTSEC(sceVNID_rodata);
    209 	PRINTSEC(sceVStub_rodata);
    210 
    211 	encoded_modinfo = sce_elf_module_info_encode(
    212 			module_info, ve, &section_sizes, &rtable);
    213 
    214 	TRACEF(VERBOSE, "Relocations from encoded modinfo:\n");
    215 	print_rtable(&rtable);
    216 
    217 	FILE *outfile;
    218 	Elf *dest;
    219 	ASSERT(dest = elf_utils_copy_to_file(args.output, ve->elf, &outfile));
    220 	ASSERT(elf_utils_duplicate_shstrtab(dest));
    221 	ASSERT(sce_elf_discard_invalid_relocs(ve, ve->rela_tables));
    222 	ASSERT(sce_elf_write_module_info(dest, ve, &section_sizes, encoded_modinfo));
    223 	rtable.next = ve->rela_tables;
    224 	ASSERT(sce_elf_write_rela_sections(dest, ve, &rtable));
    225 	ASSERT(sce_elf_rewrite_stubs(dest, ve));
    226 	ELF_ASSERT(elf_update(dest, ELF_C_WRITE) >= 0);
    227 	elf_end(dest);
    228 	ASSERT(sce_elf_set_headers(outfile, ve));
    229 	fclose(outfile);
    230 
    231 	/* FIXME: restore original segment sizes */
    232 	for(idx = 0; idx < ve->num_segments; idx++)
    233 		ve->segments[idx].memsz = segment_sizes[idx];
    234 	free(segment_sizes);
    235 
    236 	sce_elf_module_info_free(module_info);
    237 	vita_elf_free(ve);
    238 
    239 	return status;
    240 failure:
    241 	return EXIT_FAILURE;
    242 }