PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
main.c
1/*
2 Generate a symbol table encapsulated in a .o file.
3 Supports reading global symbols from elfs (.o, .elf), ranlibs (.a) and text files (.l)
4 The text files should have one symbol per line, terminated with \n (not \r\n)
5
6 NOTES;
7 Doesn't support big-endian systems (sorry powerMac users)
8 Requires a system elf.h and ar.h (sorry windows users)
9 String handling is pretty evil, needs cleaning up
10 Actually, everything wants to be cleaned up a bit :)
11*/
12
13#include <stdio.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <unistd.h>
17#include <elf.h>
18#include <ar.h>
19#include <string.h>
20#include <stdlib.h>
21#include <byteswap.h>
22#include <stdarg.h>
23
24int harvest_text(const char *filename, int (*call_symbol)(void *user, int type, const char *name), void *user)
25{
26 FILE *f = fopen(filename, "r");
27 if (f==NULL)
28 {
29 printf("%s: Failed to open (%s)\n", filename, strerror(errno));
30 return(-1);
31 }
32
33 while(!feof(f))
34 {
35 char buf[512];
36 fgets(buf, sizeof(buf), f);
37 if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';
38 call_symbol(user, STT_OBJECT, buf);
39 }
40
41 fclose(f);
42 return(0);
43}
44
45int harvest_ar(const char *filename, int (*call_symbol)(void *user, int type, const char *name), void *user)
46{
47 int fdi = open(filename, O_RDONLY);
48 if (fdi<0)
49 {
50 printf("%s: Failed to open (%s)\n", filename, strerror(errno));
51 return(-1);
52 }
53
54 char armag[SARMAG];
55 read(fdi, armag, SARMAG);
56 if (memcmp(armag, ARMAG, SARMAG))
57 {
58 close(fdi);
59 printf("%s: not an AR file!\n", filename);
60 return(-1);
61 }
62
63 struct ar_hdr arhdr;
64 read(fdi, &arhdr, sizeof(struct ar_hdr));
65
66 if (arhdr.ar_name[0]!='/' && arhdr.ar_name[0]!='\0')
67 {
68 close(fdi);
69 printf("%s: AR file doesn't seem to have symbol table!\n", filename);
70 return(-1);
71 }
72
73 char buf[sizeof(arhdr.ar_size)+1];
74 memcpy(buf, arhdr.ar_size, sizeof(arhdr.ar_size));
75 buf[sizeof(arhdr.ar_size)] = '\0';
76
77 int size = atoi(buf);
78 if (size==0)
79 {
80 close(fdi);
81 printf("%s: AR file doesn't seem to have symbol table! (%s)\n", filename, buf);
82 return(-1);
83 }
84
85 char *data = malloc(size);
86 read(fdi, data, size);
87
88 int symbols = bswap_32(*(int*)data);
89
90 int *type = (int*)data+4;
91 char *names = data+4+(4*symbols);
92 for (int i=0;i<symbols;i++)
93 {
94 call_symbol(user, STT_OBJECT, names);
95 names+=strlen(names)+1;
96 type++;
97 }
98
99 free(data);
100
101
102 close(fdi);
103 return(0);
104}
105
106int harvest_elf(const char *filename, int (*call_symbol)(void *user, int type, const char *name), void *user)
107{
108 int symcnt=0;
109 char *shstrs=NULL, *strs=NULL;
110 int fdi = open(filename, O_RDONLY);
111 if (fdi<0)
112 {
113 printf("%s: Failed to open (%s)\n", filename, strerror(errno));
114 return(-1);
115 }
116
117 Elf32_Ehdr ehdr;
118 read(fdi, &ehdr, sizeof(Elf32_Ehdr));
119 if ((ehdr.e_ident[EI_MAG0] != ELFMAG0) ||
120 (ehdr.e_ident[EI_MAG1] != ELFMAG1) ||
121 (ehdr.e_ident[EI_MAG2] != ELFMAG2) ||
122 (ehdr.e_ident[EI_MAG3] != ELFMAG3))
123 {
124 printf("%s: Doesn't seem to be an ELF!\n", filename);
125 return(-1);
126 }
127
128 lseek(fdi, ehdr.e_shoff+(sizeof(Elf32_Shdr)*ehdr.e_shstrndx), SEEK_SET);
129 {
130 Elf32_Shdr shdr;
131 read(fdi, &shdr, sizeof(Elf32_Shdr));
132 shstrs = malloc(shdr.sh_size);
133 lseek(fdi, shdr.sh_offset, SEEK_SET);
134 read(fdi, shstrs, shdr.sh_size);
135 }
136
137 Elf32_Sym *syms = NULL;
138 for (int i=0;i<ehdr.e_shnum;i++)
139 {
140 Elf32_Shdr shdr;
141
142 lseek(fdi, ehdr.e_shoff+(sizeof(Elf32_Shdr)*i), SEEK_SET);
143
144 read(fdi, &shdr, sizeof(Elf32_Shdr));
145 if ((!strcmp(&shstrs[shdr.sh_name], ".strtab")) && shdr.sh_type == SHT_STRTAB)
146 {
147 strs = malloc(shdr.sh_size);
148 lseek(fdi, shdr.sh_offset, SEEK_SET);
149 read(fdi, strs, shdr.sh_size);
150 }
151
152 if ((!strcmp(&shstrs[shdr.sh_name], ".symtab")) && shdr.sh_type == SHT_SYMTAB)
153 {
154 if (syms!=NULL)
155 {
156 printf("%s: More than one .symtab sections? using latest.\n", filename);
157 free(syms);
158 }
159 syms = malloc(shdr.sh_size);
160 lseek(fdi, shdr.sh_offset, SEEK_SET);
161 read(fdi, syms, shdr.sh_size);
162 symcnt = shdr.sh_size/shdr.sh_entsize;
163 }
164 }
165
166 for (int i=0;i<symcnt;i++)
167 {
168 if (ELF32_ST_BIND(syms[i].st_info) == STB_GLOBAL)
169 {
170 if (syms[i].st_shndx==STN_UNDEF) // XXX: Maybe needed?
171 continue;
172 call_symbol(user, ELF32_ST_TYPE(syms[i].st_info), &strs[syms[i].st_name]);
173 }
174 }
175
176
177 if (shstrs!=NULL)
178 free(shstrs);
179 if (strs!=NULL)
180 free(strs);
181 if (syms!=NULL)
182 free(syms);
183
184
185 close(fdi);
186 return(0);
187}
188
189typedef struct
190{
191 int Size;
192 char *Buffer;
193 char *Cur;
194} elf_str;
195
196
197void elf_str_start(elf_str *s, int size)
198{
199 s->Size = size;
200 s->Buffer = malloc(size);
201 s->Buffer[0] = '\0';
202 s->Cur = s->Buffer+1;
203}
204
205int elf_str_add(elf_str *s, const char *format, ...)
206{
207 int idx = s->Cur-s->Buffer;
208 char buf[512];
209 va_list va;
210 va_start(va, format);
211 vsnprintf(buf, sizeof(buf), format, va);
212 va_end(va);
213
214 int len = strlen(buf);
215
216 if (len>(s->Size-(s->Cur-s->Buffer)))
217 {
218 printf("Failed to add '%s'\n", buf);
219 return(0);
220 }
221
222 strcpy(s->Cur, buf);
223 s->Cur[len] = '\0';
224 s->Cur += len+1;
225 return(idx);
226}
227
228int elf_str_size(elf_str *s)
229{
230 return(s->Cur-s->Buffer);
231}
232
233
234typedef struct symbol_ll
235{
236 const char *Name;
237 int Type;
238 struct symbol_ll *Next;
239} symbol_ll;
240
241typedef struct
242{
243 symbol_ll *First;
244 int Count;
245} symbol;
246
247int symtab_write(const char *filename, const char *name, symbol *s)
248{
249 int cur = 0;
250 FILE *file;
251 elf_str shstr;
252 elf_str str;
253 Elf32_Ehdr ehdr;
254 Elf32_Shdr shdr[16];
255 Elf32_Sym sym;
256 Elf32_Rel rel;
257
258 file = fopen(filename, "wb");
259 if (file==NULL)
260 return(-1);
261
262 elf_str_start(&shstr, 512);
263 elf_str_start(&str, 512*1024);
264
265 cur += sizeof(Elf32_Ehdr);
266 ehdr.e_ident[EI_MAG0] = ELFMAG0;
267 ehdr.e_ident[EI_MAG1] = ELFMAG1;
268 ehdr.e_ident[EI_MAG2] = ELFMAG2;
269 ehdr.e_ident[EI_MAG3] = ELFMAG3;
270 ehdr.e_ident[EI_CLASS] = ELFCLASS32;
271 ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
272 ehdr.e_ident[EI_VERSION] = EV_CURRENT;
273 ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV;
274 ehdr.e_ident[EI_ABIVERSION] = 0;
275 ehdr.e_ident[EI_PAD] = 0;
276 ehdr.e_type = ET_REL;
277 ehdr.e_machine = EM_MIPS;
278 ehdr.e_version = 0x1;
279 ehdr.e_entry = 0x0000;
280 ehdr.e_phoff = 0;
281 ehdr.e_shoff = cur;
282 ehdr.e_flags = 0x20924001; // HRM?
283 ehdr.e_ehsize = sizeof(Elf32_Ehdr);
284 ehdr.e_phentsize = sizeof(Elf32_Phdr);
285 ehdr.e_phnum = 0;
286 ehdr.e_shentsize = sizeof(Elf32_Shdr);
287 ehdr.e_shnum = 6;
288 ehdr.e_shstrndx = 1;
289
290 cur += ehdr.e_shentsize * ehdr.e_shnum;
291
292 /* Make section names first.... */
293 shdr[0].sh_name = 0;
294 shdr[1].sh_name = elf_str_add(&shstr, ".shstrtab");
295 shdr[2].sh_name = elf_str_add(&shstr, ".symtab");
296 shdr[3].sh_name = elf_str_add(&shstr, ".data");
297 shdr[4].sh_name = elf_str_add(&shstr, ".rel.data");
298 shdr[5].sh_name = elf_str_add(&shstr, ".strtab");
299
300 // NULL section
301 shdr[0].sh_type = SHT_NULL;
302 shdr[0].sh_flags = 0;
303 shdr[0].sh_addr = 0;
304 shdr[0].sh_offset = 0;
305 shdr[0].sh_size = 0;
306 shdr[0].sh_link = 0;
307 shdr[0].sh_info = 0;
308 shdr[0].sh_addralign = 0;
309 shdr[0].sh_entsize = 0;
310
311 /* Write out section header string table */
312 shdr[1].sh_type = SHT_STRTAB;
313 shdr[1].sh_flags = 0;
314 shdr[1].sh_addr = 0;
315 shdr[1].sh_offset = cur;
316 shdr[1].sh_size = elf_str_size(&shstr);
317 shdr[1].sh_link = 0;
318 shdr[1].sh_info = 0;
319 shdr[1].sh_addralign = 1;
320 shdr[1].sh_entsize = 0;
321 cur = shdr[1].sh_offset + shdr[1].sh_size;
322 fseek(file, shdr[1].sh_offset, SEEK_SET);
323 fwrite(shstr.Buffer, shdr[1].sh_size, 1, file);
324
325
326 /*
327 Write out symbol table
328 */
329 shdr[2].sh_type = SHT_SYMTAB;
330 shdr[2].sh_flags = 0;
331 shdr[2].sh_addr = 0;
332 shdr[2].sh_offset = cur;
333 shdr[2].sh_size = sizeof(Elf32_Sym)*(3+s->Count);
334 shdr[2].sh_link = 5; // .strtab
335 shdr[2].sh_info = 0;
336 shdr[2].sh_addralign = 4;
337 shdr[2].sh_entsize = sizeof(Elf32_Sym);
338 cur = shdr[2].sh_offset + shdr[2].sh_size;
339
340 fseek(file, shdr[2].sh_offset, SEEK_SET);
341 sym.st_name = 0;
342 sym.st_info = 0;
343 sym.st_other = 0;
344 sym.st_shndx = 0;
345 sym.st_value = 0;
346 sym.st_size = 0;
347 fwrite(&sym, shdr[2].sh_entsize, 1, file);
348
349 sym.st_name = 0;
350 sym.st_info = ELF32_ST_INFO(STB_LOCAL, STT_SECTION);
351 sym.st_other = 0;
352 sym.st_shndx = 3; // .data
353 sym.st_value = 0;
354 sym.st_size = 0;
355 fwrite(&sym, shdr[2].sh_entsize, 1, file);
356
357 sym.st_name = elf_str_add(&str, "_symtab_%s", name);
358 sym.st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT);
359 sym.st_other = 0;
360 sym.st_shndx = 3; // .data
361 sym.st_value = 0;
362 sym.st_size = 1;
363 fwrite(&sym, shdr[2].sh_entsize, 1, file);
364
365
366 for (symbol_ll *cur_sym=s->First;cur_sym!=NULL;cur_sym=cur_sym->Next)
367 {
368 sym.st_name = elf_str_add(&str, "%s", cur_sym->Name);
369 sym.st_info = ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE);
370 sym.st_other = 0;
371 sym.st_shndx = 0;
372 sym.st_value = 0;
373 sym.st_size = 0;
374 fwrite(&sym, shdr[2].sh_entsize, 1, file);
375 }
376
377 /*
378 Write out data area
379 */
380 shdr[3].sh_type = SHT_PROGBITS;
381 shdr[3].sh_flags = SHF_WRITE | SHF_ALLOC;
382 shdr[3].sh_addr = 0;
383 shdr[3].sh_offset = cur;
384 shdr[3].sh_link = 0;
385 shdr[3].sh_info = 0;
386 shdr[3].sh_addralign = 16;
387 shdr[3].sh_entsize = 0;
388
389 elf_str prgstr;
390 elf_str_start(&prgstr, 512*1024);
391
392 fseek(file, shdr[3].sh_offset, SEEK_SET);
393 unsigned int dat = 0;
394 for (symbol_ll *cur_sym=s->First;cur_sym!=NULL;cur_sym=cur_sym->Next)
395 {
396 dat = 0x00000000;
397 fwrite(&dat, 4, 1, file);
398
399 dat = (8*(s->Count+1))+elf_str_add(&prgstr, "%s", cur_sym->Name);
400 fwrite(&dat, 4, 1, file);
401 }
402 dat = 0;
403 fwrite(&dat, 4, 1, file);
404 fwrite(&dat, 4, 1, file);
405 fwrite(prgstr.Buffer, elf_str_size(&prgstr), 1, file);
406
407 shdr[3].sh_size = (8*(s->Count+1))+elf_str_size(&prgstr);
408 cur = shdr[3].sh_offset + shdr[3].sh_size;
409
410
411 /*
412 Write out relocation table
413 */
414 shdr[4].sh_type = SHT_REL;
415 shdr[4].sh_flags = 0;
416 shdr[4].sh_addr = 0;
417 shdr[4].sh_offset = cur;
418 shdr[4].sh_size = sizeof(Elf32_Rel)*(s->Count*2);
419 shdr[4].sh_link = 2; // .symtab
420 shdr[4].sh_info = 3; // .data
421 shdr[4].sh_addralign = 16;
422 shdr[4].sh_entsize = sizeof(Elf32_Rel);
423 cur = shdr[4].sh_offset + shdr[4].sh_size;
424
425 fseek(file, shdr[4].sh_offset, SEEK_SET);
426 for (int i=0;i<s->Count;i++)
427 {
428 // Symbol pointer
429 rel.r_offset = i*8;
430 rel.r_info = ELF32_R_INFO(3+i, R_MIPS_32);
431 fwrite(&rel, shdr[4].sh_entsize, 1, file);
432
433 // String offset
434 rel.r_offset = (i*8)+4;
435 rel.r_info = ELF32_R_INFO(1, R_MIPS_32);
436 fwrite(&rel, shdr[4].sh_entsize, 1, file);
437 }
438
439 /*
440 Write out string table
441 */
442 shdr[5].sh_type = SHT_STRTAB;
443 shdr[5].sh_flags = 0;
444 shdr[5].sh_addr = 0;
445 shdr[5].sh_offset = cur;
446 shdr[5].sh_size = elf_str_size(&str);
447 shdr[5].sh_link = 0;
448 shdr[5].sh_info = 0;
449 shdr[5].sh_addralign = 1;
450 shdr[5].sh_entsize = 0;
451
452 fseek(file, shdr[5].sh_offset, SEEK_SET);
453 fwrite(str.Buffer, shdr[5].sh_size, 1, file);
454
455 /* Write out section headers*/
456 fseek(file, ehdr.e_shoff, SEEK_SET);
457 fwrite(shdr, ehdr.e_shentsize, ehdr.e_shnum, file);
458
459 /* Write out ELF header */
460 fseek(file, 0, SEEK_SET);
461 fwrite(&ehdr, ehdr.e_ehsize, 1, file);
462
463
464 return(0);
465}
466
467int symtab_symbol(void *user, int type, const char *name)
468{
469 symbol *s = user;
470
471 if (type!=STT_OBJECT && type!=STT_FUNC)
472 return(0);
473
474 symbol_ll *sn = malloc(sizeof(symbol_ll));
475 sn->Name = strdup(name);
476 sn->Next = s->First;
477 sn->Type = type;
478 s->First = sn;
479 s->Count++;
480 return(1);
481}
482
483int main(int argc, char *argv[])
484{
485 if (argc<4)
486 {
487 printf("usage:\n%s <name> output_symtab.o [input elfs]\n", argv[0]);
488 return(1);
489 }
490 symbol syms;
491 syms.First = NULL;
492 syms.Count = 0;
493
494 for (int i=3;i<argc;i++)
495 {
496 int len = strlen(argv[i]);
497 if (argv[i][len-2] == '.')
498 {
499 if (argv[i][len-1] == 'o')
500 {
501 harvest_elf(argv[i], symtab_symbol, &syms);
502 continue;
503 }
504 else if (argv[i][len-1] == 'a')
505 {
506 harvest_ar(argv[i], symtab_symbol, &syms);
507 continue;
508 }
509 else if (argv[i][len-1] == 'l')
510 {
511 harvest_text(argv[i], symtab_symbol, &syms);
512 continue;
513 }
514 }
515 printf("%s: Unknown filetype!\n", argv[i]);
516 }
517
518 symtab_write(argv[2], argv[1], &syms);
519
520
521 return(0);
522}
Definition main.c:242