1/* unexapollo.c -- COFF File UNEXEC for GNU Emacs on Apollo SR10.x 2 Copyright (C) 1988, 1994, 2001, 2002, 2003, 2004, 3 2005, 2006, 2007 Free Software Foundation, Inc. 4 5This file is part of GNU Emacs. 6 7GNU Emacs is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 2, or (at your option) 10any later version. 11 12GNU Emacs is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with GNU Emacs; see the file COPYING. If not, write to 19the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20Boston, MA 02110-1301, USA. */ 21 22/* Written by Leonard N. Zubkoff. */ 23 24#ifdef HAVE_CONFIG_H 25#include <config.h> 26#endif 27 28#include <fcntl.h> 29 30 31#include <a.out.h> 32#include <sys/file.h> 33#include <apollo/base.h> 34#include <apollo/ios.h> 35#include <apollo/type_uids.h> 36#include <apollo/dst.h> 37 38 39#define DST_RECORD_HDR_SIZE 2 40#define LONG_ALIGN(X) (((X)+3)&(~3)) 41 42 43void 44unexec (target_file_name, source_file_name) 45 char *target_file_name, *source_file_name; 46{ 47 struct filehdr file_header; 48 struct aouthdr domain_header; 49 struct scnhdr *section, *sections, *sections_limit; 50 struct scnhdr *first_data_section, *last_data_section; 51 struct scnhdr *rwdi_section, *blocks_section; 52 struct reloc reloc_entry; 53 unsigned long data_size, old_data_section_size, source_file_offset_past_rwdi; 54 unsigned char buffer[4096]; 55 long delta_before_rwdi, delta_after_rwdi, byte_count; 56 long first_changed_vaddr, old_rwdi_vaddr, i; 57 ios_$id_t target_file, source_file; 58 status_$t status; 59 /* Open the Source File. */ 60 if ((source_file = open (source_file_name, O_RDONLY)) < 0) 61 error ("cannot open source file for input"); 62 /* Read the File Header. */ 63 if (read (source_file, &file_header, sizeof (file_header)) != sizeof (file_header)) 64 error ("cannot read file header"); 65 66 /* Read the Domain Header. */ 67 if (read (source_file, &domain_header, sizeof (domain_header)) 68 != sizeof (domain_header)) 69 error ("cannot read domain header"); 70 /* Read the Section Headers. */ 71 sections = 72 (struct scnhdr *) malloc (file_header.f_nscns*sizeof (struct scnhdr)); 73 if (sections == (struct scnhdr *) 0) 74 error ("cannot allocate section header storage"); 75 sections_limit = sections + file_header.f_nscns; 76 if (read (source_file, sections, file_header.f_nscns*sizeof (struct scnhdr)) 77 != file_header.f_nscns*sizeof (struct scnhdr)) 78 error ("cannot read section headers"); 79 /* Compute the new Size of the Data Section. */ 80 data_size = sbrk (0) - domain_header.data_start; 81 delta_before_rwdi = delta_after_rwdi = data_size - domain_header.dsize; 82 old_rwdi_vaddr = 0; 83 /* Find and Deallocate the .rwdi Section Information. */ 84 for (rwdi_section = sections; rwdi_section != sections_limit; rwdi_section++) 85 if (strcmp (rwdi_section->s_name, ".rwdi") == 0) 86 { 87 /* If there are relocation entries, we cannot "unrelocate" them. */ 88 if (rwdi_section->s_nreloc > 0) 89 error (".rwdi section needs relocation - cannot dump Emacs"); 90 delta_after_rwdi = delta_before_rwdi - rwdi_section->s_size; 91 old_rwdi_vaddr = rwdi_section->s_vaddr; 92 rwdi_section->s_paddr = 0; 93 rwdi_section->s_vaddr = 0; 94 rwdi_section->s_scnptr = 0; 95 rwdi_section->s_size = 0; 96 source_file_offset_past_rwdi = (rwdi_section+1)->s_scnptr; 97 break; 98 } 99 /* Skip over the Text Section Headers. */ 100 for (section = sections; (section->s_flags & STYP_TEXT) != 0; section++) ; 101 /* 102 Find the First and Last Data Sections and Fixup 103 Section Header Relocation Pointers. 104 */ 105 first_data_section = last_data_section = (struct scnhdr *) 0; 106 for (; section != sections_limit; section++) 107 { 108 if ((section->s_flags & STYP_DATA) != 0) 109 { 110 if (first_data_section == (struct scnhdr *) 0) 111 first_data_section = section; 112 last_data_section = section; 113 } 114 if (section->s_relptr != 0) 115 section->s_relptr += delta_after_rwdi; 116 } 117 /* Increment the Size of the Last Data Section. */ 118 old_data_section_size = last_data_section->s_size; 119 last_data_section->s_size += delta_before_rwdi; 120 121 /* Update the File Header and Domain Header. */ 122 file_header.f_symptr += delta_after_rwdi; 123 domain_header.dsize = data_size; 124 domain_header.bsize = 0; 125 /* Skip over subsequent Bss Section Headers. */ 126 for (section = last_data_section+1; 127 (section->s_flags & STYP_BSS) != 0; section++) ; 128 /* Update the remaining Section Headers. */ 129 blocks_section = (struct scnhdr *) 0; 130 first_changed_vaddr = 0; 131 for (; section != sections_limit; section++) 132 { 133 long delta = (section < rwdi_section ? delta_before_rwdi : delta_after_rwdi); 134 if (section->s_paddr != 0) 135 section->s_paddr += delta; 136 if (section->s_vaddr != 0) 137 { 138 if (first_changed_vaddr == 0) 139 first_changed_vaddr = section->s_vaddr; 140 section->s_vaddr += delta; 141 } 142 if (section->s_scnptr != 0) 143 section->s_scnptr += delta; 144 if (strcmp (section->s_name, ".blocks") == 0) 145 blocks_section = section; 146 else if (strcmp (section->s_name, ".sri") == 0 && 147 domain_header.o_sri != 0) 148 domain_header.o_sri += delta; 149 else if (strcmp (section->s_name, ".inlib") == 0 && 150 domain_header.o_inlib != 0) 151 domain_header.o_inlib += delta; 152 } 153 /* Open the Target File. */ 154 ios_$create (target_file_name, strlen (target_file_name), coff_$uid, 155 ios_$recreate_mode, ios_$write_opt, &target_file, &status); 156 if (status.all != status_$ok) 157 error ("cannot open target file for output"); 158 /* Write the File Header. */ 159 if (write (target_file, &file_header, sizeof (file_header)) != sizeof (file_header)) 160 error ("cannot write file header"); 161 /* Write the Domain Header. */ 162 if (write (target_file, &domain_header, sizeof (domain_header)) 163 != sizeof (domain_header)) 164 error ("cannot write domain header"); 165 /* Write the Section Headers. */ 166 if (write (target_file, sections, file_header.f_nscns*sizeof (struct scnhdr)) 167 != file_header.f_nscns*sizeof (struct scnhdr)) 168 error ("cannot write section headers"); 169 /* Copy the Allocated Sections. */ 170 for (section = sections; section != first_data_section; section++) 171 if (section->s_scnptr != 0) 172 CopyData (target_file, source_file, LONG_ALIGN(section->s_size)); 173 /* Write the Expanded Data Segment. */ 174 if (write (target_file, first_data_section->s_vaddr, data_size) != data_size) 175 error ("cannot write new data section"); 176 177 /* Skip over the Last Data Section and Copy until the .rwdi Section. */ 178 if (lseek (source_file, last_data_section->s_scnptr 179 +old_data_section_size, L_SET) == -1) 180 error ("cannot seek past data section"); 181 for (section = last_data_section+1; section != rwdi_section; section++) 182 if (section->s_scnptr != 0) 183 CopyData (target_file, source_file, LONG_ALIGN(section->s_size)); 184 /* Skip over the .rwdi Section and Copy Remainder of Source File. */ 185 if (lseek (source_file, source_file_offset_past_rwdi, L_SET) == -1) 186 error ("cannot seek past .rwdi section"); 187 while ((byte_count = read (source_file, buffer, sizeof (buffer))) > 0) 188 if (write (target_file, buffer, byte_count) != byte_count) 189 error ("cannot write data"); 190 /* Unrelocate .data references to Global Symbols. */ 191 for (section = first_data_section; section <= last_data_section; section++) 192 for (i = 0; i < section->s_nreloc; i++) 193 { 194 if (lseek (source_file, section->s_relptr 195 +i*sizeof (struct reloc)-delta_after_rwdi, L_SET) == -1) 196 error ("cannot seek to relocation info"); 197 if (read (source_file, &reloc_entry, sizeof (reloc_entry)) 198 != sizeof (reloc_entry)) 199 error ("cannot read reloc entry"); 200 if (lseek (source_file, reloc_entry.r_vaddr-section->s_vaddr 201 +section->s_scnptr, L_SET) == -1) 202 error ("cannot seek to data element"); 203 if (lseek (target_file, reloc_entry.r_vaddr-section->s_vaddr 204 +section->s_scnptr, L_SET) == -1) 205 error ("cannot seek to data element"); 206 if (read (source_file, buffer, 4) != 4) 207 error ("cannot read data element"); 208 if (write (target_file, buffer, 4) != 4) 209 error ("cannot write data element"); 210 } 211 212 /* Correct virtual addresses in .blocks section. */ 213 if (blocks_section != (struct scnhdr *) 0) 214 { 215 dst_rec_t dst_record; 216 dst_rec_comp_unit_t *comp_unit; 217 unsigned short number_of_sections; 218 unsigned long section_base; 219 unsigned long section_offset = 0; 220 /* Find section tables and update section base addresses. */ 221 while (section_offset < blocks_section->s_size) 222 { 223 if (lseek (target_file, 224 blocks_section->s_scnptr+section_offset, L_SET) == -1) 225 error ("cannot seek to comp unit record"); 226 /* Handle pad records before the comp unit record. */ 227 if (read (target_file, &dst_record, DST_RECORD_HDR_SIZE) 228 != DST_RECORD_HDR_SIZE) 229 error ("cannot read dst record tag"); 230 if (dst_record.rec_type == dst_typ_pad) 231 section_offset += DST_RECORD_HDR_SIZE; 232 else if (dst_record.rec_type == dst_typ_comp_unit) 233 { 234 comp_unit = &dst_record.rec_data.comp_unit_; 235 if (read (target_file, comp_unit, sizeof (*comp_unit)) 236 != sizeof (*comp_unit)) 237 error ("cannot read comp unit record"); 238 if (lseek (target_file, blocks_section->s_scnptr 239 +section_offset 240#if dst_version_major == 1 && dst_version_minor < 4 241 +comp_unit->section_table 242#else 243 +comp_unit->section_table.rel_offset 244#endif 245 +DST_RECORD_HDR_SIZE, 246 L_SET) == -1) 247 error ("cannot seek to section table"); 248 if (read (target_file, &number_of_sections, sizeof (number_of_sections)) 249 != sizeof (number_of_sections)) 250 error ("cannot read section table size"); 251 for (i = 0; i < number_of_sections; i++) 252 { 253 if (read (target_file, §ion_base, sizeof (section_base)) 254 != sizeof (section_base)) 255 error ("cannot read section base value"); 256 if (section_base < first_changed_vaddr) 257 continue; 258 else if (section_base < old_rwdi_vaddr) 259 section_base += delta_before_rwdi; 260 else section_base += delta_after_rwdi; 261 if (lseek (target_file, -sizeof (section_base), L_INCR) == -1) 262 error ("cannot seek to section base value"); 263 if (write (target_file, §ion_base, sizeof (section_base)) 264 != sizeof (section_base)) 265 error ("cannot write section base"); 266 } 267 section_offset += comp_unit->data_size; 268 } 269 else error ("unexpected dst record type"); 270 } 271 } 272 273 if (close (source_file) == -1) 274 error("cannot close source file"); 275 if (close (target_file) == -1) 276 error ("cannot close target file"); 277} 278 279 280static 281CopyData (target_file, source_file, total_byte_count) 282 int target_file, source_file; 283 long total_byte_count; 284{ 285 unsigned char buffer[4096]; 286 long byte_count; 287 while (total_byte_count > 0) 288 { 289 if (total_byte_count > sizeof (buffer)) 290 byte_count = sizeof (buffer); 291 else byte_count = total_byte_count; 292 if (read (source_file, buffer, byte_count) != byte_count) 293 error ("cannot read data"); 294 if (write (target_file, buffer, byte_count) != byte_count) 295 error ("cannot write data"); 296 total_byte_count -= byte_count; 297 } 298} 299 300/* arch-tag: 783ebbdf-7d26-4df8-9469-17a1747dce96 301 (do not change this comment) */ 302