This is atom.c in view mode; [Download] [Up]
#include <stdio.h> #include <sys/file.h> #include <sys/types.h> #include <sys/stat.h> #include <varargs.h> #include <a.out.h> #include <sys/loader.h> #define OBJC_SYM "__OBJC_SYMBOLS" #define OBJC_MOD "__OBJC_MODULES" #define OBJC_SEL "__OBJC_STRINGS" #include <symseg.h> /* The structures for mach relocatables */ struct mach_header header; struct segment_command reloc_segment; struct section text_section; /* __TEXT, __text */ struct section data_section; /* __DATA, __data */ struct section bss_section; /* __DATA, __bss */ struct section sym_section; /* __OBJC, __symbol_table */ struct section mod_section; /* __OBJC, __module_info */ struct section sel_section; /* __OBJC, __selector_strs */ struct symtab_command symbol_table; struct symseg_command symbol_segment; /* * The data relocation entried which are looked through to divide up into the * objective-C section's relocation entries and the data section's. */ struct relocation_info *data_reloc; long data_reloff, data_nreloc; a_out_to_mach_O(a_out, size_a_out, file_name, gdbsize, gdbpointer) char *a_out; int size_a_out; char *file_name; int gdbsize; char *gdbpointer; { char *p, *ap; long header_size, fileoff, strsize; struct exec *exec; struct relocation_info *preloc; struct nlist *pnlist; struct symbol_root *psymbol_root; struct mach_root *pmach_root, mach_root; exec = (struct exec *)a_out; /* * For converted a.out files the resulting Mach-O object file will * look like: * * mach header * mach load commands * the text segment * the data segment * the objective-C segment * the relocation entries * the 4.3bsd symbol table * the 4.3bsd string table * the gdb symbol segments */ header.magic = MH_MAGIC; header.cputype = CPU_TYPE_MC680x0; header.cpusubtype = CPU_SUBTYPE_MC68040; header.filetype = MH_OBJECT; header.ncmds = 3; header.sizeofcmds = sizeof(struct segment_command) + 6 * sizeof(struct section) + sizeof(struct symtab_command) + sizeof(struct symseg_command); header.flags = 0; header_size = header.sizeofcmds + sizeof(struct mach_header); reloc_segment.cmd = LC_SEGMENT; reloc_segment.cmdsize = sizeof(struct segment_command) + 6 * sizeof(struct section); /* leave reloc_segment.segname full of zeros */ reloc_segment.vmaddr = 0; reloc_segment.vmsize = exec->a_text + exec->a_data + exec->a_bss; reloc_segment.fileoff = header_size; reloc_segment.filesize = exec->a_text + exec->a_data; reloc_segment.maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; reloc_segment.initprot= VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; reloc_segment.nsects = 6; reloc_segment.flags = 0; strcpy(text_section.sectname, SECT_TEXT); strcpy(text_section.segname, SEG_TEXT); text_section.addr = 0; text_section.size = exec->a_text; text_section.offset = header_size; text_section.align = 2; if(exec->a_trsize != 0) { text_section.reloff = header_size + exec->a_text + exec->a_data; text_section.nreloc = exec->a_trsize / sizeof (struct relocation_info); } else { text_section.reloff = 0; text_section.nreloc = 0; } text_section.flags = 0; text_section.reserved1 = 0; text_section.reserved2 = 0; strcpy(data_section.sectname, SECT_DATA); strcpy(data_section.segname, SEG_DATA); data_section.addr = exec->a_text; data_section.offset = header_size + exec->a_text; data_section.align = 2; data_section.flags = 0; data_section.reserved1 = 0; data_section.reserved2 = 0; strcpy(sym_section.sectname, SECT_OBJC_SYMBOLS); strcpy(sym_section.segname, SEG_OBJC); sym_section.align = 2; strcpy(mod_section.sectname, SECT_OBJC_MODULES); strcpy(mod_section.segname, SEG_OBJC); mod_section.align = 2; strcpy(sel_section.sectname, SECT_OBJC_STRINGS); strcpy(sel_section.segname, SEG_OBJC); sel_section.align = 2; /* * The symbols that start each of the objective-C sections have prevoiusly * been looked up in write.c and the addresses and sizes of these sections * has been set into the section structures. These addresses are used to * to divide up the data section. The assumptions are as follows: * the data for these are at the end of the data section * they are in the following order (if present) * symbol table section * module information section * selector strings section */ /* * Now knowing the sizes of all the objective-C sections the size * of the data section and the file offsets can be calculated. */ data_section.size = exec->a_data - (sel_section.size + sym_section.size + mod_section.size); sym_section.offset = data_section.offset + data_section.size; mod_section.offset = sym_section.offset + sym_section.size; sel_section.offset = mod_section.offset + mod_section.size; /* * Now the data relocation entries have to be divided up. This * is relying on the fact that the assembler produces relocation * entries in decreasing order based on the r_address field. Note * the r_address field is really an offset into the section. */ if(exec->a_drsize != 0) { data_reloc = (struct relocation_info *)xmalloc(exec->a_drsize); ap = a_out + N_TXTOFF(*exec) + exec->a_text + exec->a_data + exec->a_trsize; bcopy(ap, data_reloc, exec->a_drsize); data_reloff = header_size + exec->a_text + exec->a_data + exec->a_trsize; data_nreloc = exec->a_drsize / sizeof (struct relocation_info); data_section.reloff = data_reloff; data_section.nreloc = 0; sym_section.reloff = data_reloff; sym_section.nreloc = 0; mod_section.reloff = data_reloff; mod_section.nreloc = 0; sel_section.reloff = data_reloff; sel_section.nreloc = 0; for(preloc = (struct relocation_info *)data_reloc; preloc < data_reloc + data_nreloc; preloc++){ if(preloc->r_address >= (data_section.addr + data_section.size) - exec->a_text) data_section.reloff += sizeof(struct relocation_info); else if(preloc->r_address >= data_section.addr - exec->a_text) data_section.nreloc++; if(preloc->r_address >= (sym_section.addr + sym_section.size) - exec->a_text) sym_section.reloff += sizeof(struct relocation_info); else if(preloc->r_address >= sym_section.addr - exec->a_text) sym_section.nreloc++; if(preloc->r_address >= (mod_section.addr + mod_section.size) - exec->a_text) mod_section.reloff += sizeof(struct relocation_info); else if(preloc->r_address >= mod_section.addr - exec->a_text) mod_section.nreloc++; if(preloc->r_address >= (sel_section.addr + sel_section.size) - exec->a_text) sel_section.reloff += sizeof(struct relocation_info); else if(preloc->r_address >= sel_section.addr - exec->a_text) sel_section.nreloc++; } } else{ data_section.reloff = 0; data_section.nreloc = 0; sym_section.reloff = 0; sym_section.nreloc = 0; mod_section.reloff = 0; mod_section.nreloc = 0; sel_section.reloff = 0; sel_section.nreloc = 0; } sym_section.flags = 0; sym_section.reserved1 = 0; sym_section.reserved2 = 0; mod_section.flags = 0; mod_section.reserved1 = 0; mod_section.reserved2 = 0; sel_section.flags = S_CSTRING_LITERALS; sel_section.reserved1 = 0; sel_section.reserved2 = 0; strcpy(bss_section.sectname, SECT_BSS); strcpy(bss_section.segname, SEG_DATA); bss_section.addr = exec->a_text + exec->a_data; bss_section.size = exec->a_bss; bss_section.offset = 0; bss_section.align = 2; bss_section.reloff = 0; bss_section.nreloc = 0; bss_section.flags = S_ZEROFILL; bss_section.reserved1 = 0; bss_section.reserved2 = 0; symbol_table.cmd = LC_SYMTAB; symbol_table.cmdsize = sizeof(struct symtab_command); symbol_table.symoff = 0; symbol_table.nsyms = 0; symbol_table.stroff = 0; symbol_table.strsize = 0; symbol_segment.cmd = LC_SYMSEG; symbol_segment.cmdsize = sizeof(struct symseg_command); symbol_segment.offset = 0; symbol_segment.size = 0; if(exec->a_syms != 0){ fileoff = header_size + exec->a_text + exec->a_data + exec->a_trsize + exec->a_drsize; symbol_table.symoff = fileoff; symbol_table.nsyms = exec->a_syms / sizeof(struct nlist); fileoff += exec->a_syms; symbol_table.stroff = fileoff; p = a_out + N_STROFF(*exec); strsize = *(int *)p; symbol_table.strsize = strsize; fileoff += strsize; symbol_segment.cmd = LC_SYMSEG; symbol_segment.cmdsize = sizeof(struct symseg_command); symbol_segment.offset = fileoff; symbol_segment.size = gdbsize; } output_seek(0); output_write(&header, sizeof(struct mach_header)); output_write(&reloc_segment, sizeof(struct segment_command)); output_write(&text_section, sizeof(struct section)); output_write(&data_section, sizeof(struct section)); output_write(&bss_section, sizeof(struct section)); output_write(&sym_section, sizeof(struct section)); output_write(&mod_section, sizeof(struct section)); output_write(&sel_section, sizeof(struct section)); output_write(&symbol_table, sizeof(struct symtab_command)); output_write(&symbol_segment, sizeof(struct symseg_command)); /* leave the pad after the headers */ output_seek(header_size); ap = a_out + N_TXTOFF(*exec); output_write(ap, exec->a_text); ap += exec->a_text; output_write(ap, exec->a_data); ap += exec->a_data; /* * The conversion of r_symbolnum is now done in emit_relocation() in * write.c. This fixed a bug where the item to be relocated is symbol * plus offset and here we can't tell what the original symbol's address * is and we might use the wrong section number which will result an * incorrect relocation entry. */ /* read and write the text relocation entries */ if(exec->a_trsize != 0){ p = ap; ap += exec->a_trsize; output_seek(text_section.reloff); output_write(p, exec->a_trsize); } /* read and write the data relocation entries */ if(exec->a_drsize != 0){ if (data_reloc != NULL) { p = (char *)data_reloc; } else { p = ap; } ap += exec->a_drsize; /* convert local relocation entries to Mach-O style */ for(preloc = (struct relocation_info *)p; preloc < (struct relocation_info *)(p + exec->a_drsize); preloc++){ /* * Adjust the r_address field (which is an * offset) to be an offset into the section that * the address it is refering to is in. */ if(preloc->r_address >= sel_section.addr - exec->a_text) preloc->r_address -= (sel_section.addr - data_section.addr); else if(preloc->r_address >= mod_section.addr - exec->a_text) preloc->r_address -= (mod_section.addr - data_section.addr); else if(preloc->r_address >= sym_section.addr - exec->a_text) preloc->r_address -= (sym_section.addr - data_section.addr); /* else its in the data section an it's fine as is*/ } output_seek(data_reloff); output_write(p, exec->a_drsize); } /* read and write the symbol table */ if(exec->a_syms != 0){ p = ap; ap += exec->a_syms; /* convert symbol table entries to Mach-O style */ for(pnlist = (struct nlist *)p; pnlist < (struct nlist *)(p + exec->a_syms); pnlist++){ switch(pnlist->n_type & N_TYPE){ case N_TEXT: pnlist->n_sect = 1; if((pnlist->n_type & N_STAB) == 0) pnlist->n_type = N_SECT | (pnlist->n_type & N_EXT); break; case N_DATA: { if(pnlist->n_value >= sel_section.addr + sel_section.size) pnlist->n_sect = 2; else if(pnlist->n_value >= sel_section.addr) pnlist->n_sect = 6; else if(pnlist->n_value >= mod_section.addr) pnlist->n_sect = 5; else if(pnlist->n_value >= sym_section.addr) pnlist->n_sect = 4; else pnlist->n_sect = 2; } if((pnlist->n_type & N_STAB) == 0) pnlist->n_type = N_SECT | (pnlist->n_type & N_EXT); break; case N_BSS: pnlist->n_sect = 3; if((pnlist->n_type & N_STAB) == 0) pnlist->n_type = N_SECT | (pnlist->n_type & N_EXT); break; default: pnlist->n_sect = NO_SECT; } } output_seek(symbol_table.symoff); output_write(p, exec->a_syms); /* read and write the string table */ p = ap; ap += strsize; output_seek(symbol_table.stroff); output_write(p, strsize); } /* read and write the symbol segment */ if(symbol_segment.size != 0){ p = ap; ap += symbol_segment.size; /* * Convert only the symbol_root to a mach_symbol_root. * This conversion is quite ugly. It relies on the fact that * sizeof(struct symbol_root) - sizeof(struct mach_symbol_root) * >= sizeof(struct loadmap) * It replaces the symbol_root with a mach_symbol_root copying * the like fields. Then it sets the loadmap pointer (offset * since it's in a file) to the end of the mach_symbol_root. * The load map is really just a struct loadmap field struct * with the nmaps field zero for a relocatable object. It gets * the zero by bzero'ing the sizeof the symbol_root. This also * assumes that in an OMAGIC file there is just one symbol_root. * I did say this was ugly. */ p = gdbpointer; if(symbol_segment.size < sizeof(struct symbol_root)) as_fatal("Invalid size of gdb symbol segment (smaller than a " "symbol root)"); psymbol_root = (struct symbol_root *)p; mach_root.format = MACH_ROOT_FORMAT; mach_root.length = psymbol_root->length; mach_root.ldsymoff = psymbol_root->ldsymoff; mach_root.filename = psymbol_root->filename; mach_root.filedir = psymbol_root->filedir; mach_root.blockvector = psymbol_root->blockvector; mach_root.typevector = psymbol_root->typevector; mach_root.language = psymbol_root->language; mach_root.version = psymbol_root->version; mach_root.compilation = psymbol_root->compilation; mach_root.sourcevector = psymbol_root->sourcevector; mach_root.loadmap = (struct loadmap *)(sizeof(struct mach_root)); bzero(p, sizeof(struct symbol_root)); pmach_root = (struct mach_root *)p; *pmach_root = mach_root; output_seek(symbol_segment.offset); output_write(p, symbol_segment.size); } }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.