This is ild.c in view mode; [Download] [Up]
/* ild: incremental linker/loader on System V (C) Masami Hagiya, 1986 UTS version (C) Akiumi Hasegawa, 1987 Usage: % ild loading_object start_address \ loaded_object output_file The start address is in decimal. How to Create: To compile this file (ild.c) and make ild, do the following. % cc -o ild ild.c -lld Problem: This program only supports the simplest linear search for symbols. This program is modified for UTS system. */ #include <stdio.h> #include <filehdr.h> #include <aouthdr.h> #include <scnhdr.h> #include <reloc.h> #include <syms.h> #include <storclass.h> #include <ldfcn.h> struct filehdr my_header; struct syment *my_symbol_table; char *my_string_table; struct filehdr header; struct aouthdr opt_header; struct scnhdr section[9]; char *text; struct syment *symbol_table; char *string_table; char *start_address; struct reloc relocation_info; main(argc, argv) int argc; char *argv[]; { if (argc < 5) { fprintf(stderr, "Arg count.\n"); exit(1); } #ifdef DEBUG printf("ild %s %s %s %s\n", argv[1], argv[2], argv[3], argv[4]); fflush(stdout); #endif get_myself(argv[1]); start_address = (char *)atoi(argv[2]); #ifdef DEBUG printf("start address= %x\n",(int)start_address);fflush(stdout); #endif fasload(argv[3], argv[4]); exit(0); } get_myself(filename) char *filename; { int i; LDFILE *ldptr; extern char *malloc(); ldptr = ldopen(filename, NULL); if (ldptr == NULL) { fprintf(stderr, "Can't open %s\n", filename); exit(1); } ldfhread(ldptr, &my_header); ldtbseek(ldptr); my_symbol_table = (struct syment *)malloc(sizeof(struct syment) * my_header.f_nsyms); /* sizeof(struct syment) and SYMESZ are not always the same. */ if(my_symbol_table == NULL){ fprintf(stderr,"Can't allocate memory for my_symbol_table\n"); exit(1); } for (i = 0; i < my_header.f_nsyms; i++) FREAD(&my_symbol_table[i], SYMESZ, 1, ldptr); /* If the string table is not empty, its length is stored after the symbol table, This is described in the manual. (see UTS Support Tools Guide V10L20) */ if (FREAD(&i, 4, 1, ldptr) > 0) { my_string_table = malloc(i); FSEEK(ldptr, -4, 1); FREAD(my_string_table, 1, i, ldptr); } ldclose(ldptr); } fasload(filename, outputfilename) char *filename, *outputfilename; { register struct syment *sym, *end; int i, n; LDFILE *ldptr; FILE *fp; extern char *malloc(); ldptr = ldopen(filename, "r"); if (ldptr == NULL) { fprintf(stderr, "Can't open %s\n", filename); exit(1); } ldfhread(ldptr, &header); FREAD(&opt_header,sizeof(struct aouthdr),1,ldptr); if (header.f_nscns < 3 || header.f_nscns > 8) { fprintf(stderr, "Illegal number of sections.\n"); exit(1); } for (i = 1; i <= header.f_nscns; i++) ldshread(ldptr, i, §ion[i]); if (strcmp(section[1].s_name, ".text") != 0) { fprintf(stderr, ".text not found.\n"); exit(1); } if (strcmp(section[2].s_name, ".data") != 0) { fprintf(stderr, ".data not found.\n"); exit(1); } /* The bss segment need not exist. */ /* if (strcmp(section[3].s_name, ".bss") != 0) { fprintf(stderr, ".bss not found.\n"); exit(1); } */ if (section[1].s_size > 0 && section[1].s_scnptr != sizeof(struct filehdr) + sizeof(struct aouthdr) + header.f_nscns*sizeof(struct scnhdr)) { fprintf(stderr, "Contradictory text start.\n"); exit(1); } if (section[1].s_size > 0 && section[2].s_size > 0 && section[1].s_scnptr + section[1].s_size != section[2].s_scnptr) { fprintf(stderr, "Contradictory data start.\n"); exit(1); } text = malloc(section[1].s_size + section[2].s_size); FSEEK(ldptr, section[1].s_scnptr, 0); FREAD(text, 1, section[1].s_size + section[2].s_size, ldptr); ldtbseek(ldptr); symbol_table = (struct syment *)malloc(sizeof(struct syment) * header.f_nsyms); /* sizeof(struct syment) and SYMESZ are not always the same. */ for (i = 0; i < header.f_nsyms; i++) FREAD(&symbol_table[i], SYMESZ, 1, ldptr); /* If the string table is not empty, its length is stored after the symbol table, This is described in the manual. (see UTS Support Tools Guide V10L20) */ if (FREAD(&i, 4, 1, ldptr) > 0) { string_table = malloc(i); FSEEK(ldptr, -4, 1); FREAD(string_table, 1, i, ldptr); } end = symbol_table + header.f_nsyms; for (sym = symbol_table; sym < end; sym++) { switch (sym->n_scnum) { /* in UTS, relocatable address is the offset in the section, in which it defined. Thus "sym->n_value" for each section should be the the top address of the section. in case of ".data" section, s_vaddr is equal to s_size. However, ".bss" section, s_vaddr <> textsize+datasize. I cannot understand why. But this code works well. */ case 1: /* .text */ sym->n_value = (int)start_address; break; case 2: /* .data */ sym->n_value = (int)start_address + section[1].s_size; break; case 3: /* .bss */ sym->n_value = (int)start_address + section[1].s_size + section[2].s_size; break; case N_UNDEF: search_symbol(sym); break; default: /* Does nothing. Is it OK? */ break; } sym += sym->n_numaux; } if(ldrseek(ldptr, 1) ==FAILURE){ fprintf(stderr,"Can't locate relocation table\n"); exit(1); } for (i=0; i< section[1].s_nreloc; i++){ FREAD(&relocation_info,10,1,ldptr); relocate(); } ldrseek(ldptr, 2); for (i = 0; i < section[2].s_nreloc; i++) { FREAD(&relocation_info, 10, 1, ldptr); relocate(); } fp = fopen(outputfilename, "w"); if (fp == NULL) { fprintf(stderr, "Can't creat %s.\n", outputfilename); exit(1); } fwrite(&header, sizeof(struct filehdr), 1, fp); fwrite(&opt_header,sizeof(struct aouthdr),1,fp); for (i = 1; i<= header.f_nscns; i++) fwrite(§ion[i], sizeof(struct scnhdr), 1, fp); fwrite(text, 1, section[1].s_size + section[2].s_size, fp); fclose(fp); ldclose(ldptr); } search_symbol(sym) register struct syment *sym; { register struct syment *p, *end; end = my_symbol_table + my_header.f_nsyms; for (p = my_symbol_table; p < end; p++) { /* Is the following check enough? */ if (1 <= p->n_scnum && p->n_scnum <= 3 && p->n_sclass == C_EXT && (sym->n_zeroes == 0 ? (p->n_zeroes == 0 && strcmp(&my_string_table[p->n_offset], &string_table[sym->n_offset]) == 0) : (p->n_zeroes != 0 && strncmp(p->n_name, sym->n_name, SYMNMLEN) == 0))) goto FOUND; p += p->n_numaux; } sym->n_name[SYMNMLEN] = '\0'; fprintf(stderr, "%s: undefined symbol.\n", (sym->n_zeroes ? sym->n_name : &string_table[sym->n_offset])); exit(1); FOUND: sym->n_value = p->n_value; } relocate() { char *where, *p; int value; where = text + relocation_info.r_vaddr; if (relocation_info.r_type == R_ABS) return; /* The following code depends on CPU. in case of UTS, R_RELLONG is assumed. */ if (relocation_info.r_type != R_RELLONG) { fprintf(stderr, "%d: unsupported relocation type.", relocation_info.r_type); exit(1); } /* Assuming R_RELLONG. */ p = (char *)(&value); p[0] = where[0]; p[1] = where[1]; p[2] = where[2]; p[3] = where[3]; #ifdef DEBUG printf("%s\n", (symbol_table[relocation_info.r_symndx].n_zeroes ? symbol_table[relocation_info.r_symndx].n_name : &string_table [symbol_table[relocation_info.r_symndx].n_offset])); printf("value = %x\n",value);fflush(stdout); #endif value += symbol_table[relocation_info.r_symndx].n_value; #ifdef DEBUG printf("value = %x\n",value);fflush(stdout); #endif where[0] = p[0]; where[1] = p[1]; where[2] = p[2]; where[3] = p[3]; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.