PS2SDK
PS2 Homebrew Libraries
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 
24 int 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 
45 int 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 
106 int 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 
189 typedef struct
190 {
191  int Size;
192  char *Buffer;
193  char *Cur;
194 } elf_str;
195 
196 
197 void 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 
205 int 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 
228 int elf_str_size(elf_str *s)
229 {
230  return(s->Cur-s->Buffer);
231 }
232 
233 
234 typedef struct symbol_ll
235 {
236  const char *Name;
237  int Type;
238  struct symbol_ll *Next;
239 } symbol_ll;
240 
241 typedef struct
242 {
243  symbol_ll *First;
244  int Count;
245 } symbol;
246 
247 int 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 
467 int 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 
483 int 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 }
_Elf32_ehdr
Definition: srxfixup_internal.h:25
_Elf32_Shdr
Definition: srxfixup_internal.h:53
symbol_ll
Definition: main.c:234
Elf32_Rel
Definition: elftypes.h:221
Elf32_Phdr
Definition: elftypes.h:207
elf_str
Definition: main.c:189
_Elf32_Sym
Definition: srxfixup_internal.h:66
stdio.h
symbol
Definition: main.c:241
stdlib.h
errno.h