1*60251Shibler /* Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc. 2*60251Shibler 3*60251Shibler This program is free software; you can redistribute it and/or modify 4*60251Shibler it under the terms of the GNU General Public License as published by 5*60251Shibler the Free Software Foundation; either version 1, or (at your option) 6*60251Shibler any later version. 7*60251Shibler 8*60251Shibler This program is distributed in the hope that it will be useful, 9*60251Shibler but WITHOUT ANY WARRANTY; without even the implied warranty of 10*60251Shibler MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11*60251Shibler GNU General Public License for more details. 12*60251Shibler 13*60251Shibler You should have received a copy of the GNU General Public License 14*60251Shibler along with this program; if not, write to the Free Software 15*60251Shibler Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 16*60251Shibler 17*60251Shibler In other words, you are welcome to use, share and improve this program. 18*60251Shibler You are forbidden to forbid anyone else to use, share and improve 19*60251Shibler what you give them. Help stamp out software-hoarding! */ 20*60251Shibler 21*60251Shibler 22*60251Shibler /* 23*60251Shibler * unexec.c - Convert a running program into an a.out file. 24*60251Shibler * 25*60251Shibler * Author: Spencer W. Thomas 26*60251Shibler * Computer Science Dept. 27*60251Shibler * University of Utah 28*60251Shibler * Date: Tue Mar 2 1982 29*60251Shibler * Modified heavily since then. 30*60251Shibler * 31*60251Shibler * Synopsis: 32*60251Shibler * unexec (new_name, a_name, data_start, bss_start, entry_address) 33*60251Shibler * char *new_name, *a_name; 34*60251Shibler * unsigned data_start, bss_start, entry_address; 35*60251Shibler * 36*60251Shibler * Takes a snapshot of the program and makes an a.out format file in the 37*60251Shibler * file named by the string argument new_name. 38*60251Shibler * If a_name is non-NULL, the symbol table will be taken from the given file. 39*60251Shibler * On some machines, an existing a_name file is required. 40*60251Shibler * 41*60251Shibler * The boundaries within the a.out file may be adjusted with the data_start 42*60251Shibler * and bss_start arguments. Either or both may be given as 0 for defaults. 43*60251Shibler * 44*60251Shibler * Data_start gives the boundary between the text segment and the data 45*60251Shibler * segment of the program. The text segment can contain shared, read-only 46*60251Shibler * program code and literal data, while the data segment is always unshared 47*60251Shibler * and unprotected. Data_start gives the lowest unprotected address. 48*60251Shibler * The value you specify may be rounded down to a suitable boundary 49*60251Shibler * as required by the machine you are using. 50*60251Shibler * 51*60251Shibler * Specifying zero for data_start means the boundary between text and data 52*60251Shibler * should not be the same as when the program was loaded. 53*60251Shibler * If NO_REMAP is defined, the argument data_start is ignored and the 54*60251Shibler * segment boundaries are never changed. 55*60251Shibler * 56*60251Shibler * Bss_start indicates how much of the data segment is to be saved in the 57*60251Shibler * a.out file and restored when the program is executed. It gives the lowest 58*60251Shibler * unsaved address, and is rounded up to a page boundary. The default when 0 59*60251Shibler * is given assumes that the entire data segment is to be stored, including 60*60251Shibler * the previous data and bss as well as any additional storage allocated with 61*60251Shibler * break (2). 62*60251Shibler * 63*60251Shibler * The new file is set up to start at entry_address. 64*60251Shibler * 65*60251Shibler * If you make improvements I'd like to get them too. 66*60251Shibler * harpo!utah-cs!thomas, thomas@Utah-20 67*60251Shibler * 68*60251Shibler */ 69*60251Shibler 70*60251Shibler /* Modified to support SysVr3 shared libraries by James Van Artsdalen 71*60251Shibler * of Dell Computer Corporation. james@bigtex.cactus.org. 72*60251Shibler */ 73*60251Shibler 74*60251Shibler /* There are several compilation parameters affecting unexec: 75*60251Shibler 76*60251Shibler * COFF 77*60251Shibler 78*60251Shibler Define this if your system uses COFF for executables. 79*60251Shibler Otherwise we assume you use Berkeley format. 80*60251Shibler 81*60251Shibler * NO_REMAP 82*60251Shibler 83*60251Shibler Define this if you do not want to try to save Emacs's pure data areas 84*60251Shibler as part of the text segment. 85*60251Shibler 86*60251Shibler Saving them as text is good because it allows users to share more. 87*60251Shibler 88*60251Shibler However, on machines that locate the text area far from the data area, 89*60251Shibler the boundary cannot feasibly be moved. Such machines require 90*60251Shibler NO_REMAP. 91*60251Shibler 92*60251Shibler Also, remapping can cause trouble with the built-in startup routine 93*60251Shibler /lib/crt0.o, which defines `environ' as an initialized variable. 94*60251Shibler Dumping `environ' as pure does not work! So, to use remapping, 95*60251Shibler you must write a startup routine for your machine in Emacs's crt0.c. 96*60251Shibler If NO_REMAP is defined, Emacs uses the system's crt0.o. 97*60251Shibler 98*60251Shibler * SECTION_ALIGNMENT 99*60251Shibler 100*60251Shibler Some machines that use COFF executables require that each section 101*60251Shibler start on a certain boundary *in the COFF file*. Such machines should 102*60251Shibler define SECTION_ALIGNMENT to a mask of the low-order bits that must be 103*60251Shibler zero on such a boundary. This mask is used to control padding between 104*60251Shibler segments in the COFF file. 105*60251Shibler 106*60251Shibler If SECTION_ALIGNMENT is not defined, the segments are written 107*60251Shibler consecutively with no attempt at alignment. This is right for 108*60251Shibler unmodified system V. 109*60251Shibler 110*60251Shibler * SEGMENT_MASK 111*60251Shibler 112*60251Shibler Some machines require that the beginnings and ends of segments 113*60251Shibler *in core* be on certain boundaries. For most machines, a page 114*60251Shibler boundary is sufficient. That is the default. When a larger 115*60251Shibler boundary is needed, define SEGMENT_MASK to a mask of 116*60251Shibler the bits that must be zero on such a boundary. 117*60251Shibler 118*60251Shibler * A_TEXT_OFFSET(HDR) 119*60251Shibler 120*60251Shibler Some machines count the a.out header as part of the size of the text 121*60251Shibler segment (a_text); they may actually load the header into core as the 122*60251Shibler first data in the text segment. Some have additional padding between 123*60251Shibler the header and the real text of the program that is counted in a_text. 124*60251Shibler 125*60251Shibler For these machines, define A_TEXT_OFFSET(HDR) to examine the header 126*60251Shibler structure HDR and return the number of bytes to add to `a_text' 127*60251Shibler before writing it (above and beyond the number of bytes of actual 128*60251Shibler program text). HDR's standard fields are already correct, except that 129*60251Shibler this adjustment to the `a_text' field has not yet been made; 130*60251Shibler thus, the amount of offset can depend on the data in the file. 131*60251Shibler 132*60251Shibler * A_TEXT_SEEK(HDR) 133*60251Shibler 134*60251Shibler If defined, this macro specifies the number of bytes to seek into the 135*60251Shibler a.out file before starting to write the text segment.a 136*60251Shibler 137*60251Shibler * EXEC_MAGIC 138*60251Shibler 139*60251Shibler For machines using COFF, this macro, if defined, is a value stored 140*60251Shibler into the magic number field of the output file. 141*60251Shibler 142*60251Shibler * ADJUST_EXEC_HEADER 143*60251Shibler 144*60251Shibler This macro can be used to generate statements to adjust or 145*60251Shibler initialize nonstandard fields in the file header 146*60251Shibler 147*60251Shibler * ADDR_CORRECT(ADDR) 148*60251Shibler 149*60251Shibler Macro to correct an int which is the bit pattern of a pointer to a byte 150*60251Shibler into an int which is the number of a byte. 151*60251Shibler 152*60251Shibler This macro has a default definition which is usually right. 153*60251Shibler This default definition is a no-op on most machines (where a 154*60251Shibler pointer looks like an int) but not on all machines. 155*60251Shibler 156*60251Shibler */ 157*60251Shibler 158*60251Shibler #ifndef emacs 159*60251Shibler #define PERROR(arg) perror (arg); return -1 160*60251Shibler #else 161*60251Shibler #include "config.h" 162*60251Shibler #define PERROR(file) report_error (file, new) 163*60251Shibler #endif 164*60251Shibler 165*60251Shibler #ifndef CANNOT_DUMP /* all rest of file! */ 166*60251Shibler 167*60251Shibler #ifndef CANNOT_UNEXEC /* most of rest of file */ 168*60251Shibler 169*60251Shibler #include <a.out.h> 170*60251Shibler /* Define getpagesize () if the system does not. 171*60251Shibler Note that this may depend on symbols defined in a.out.h 172*60251Shibler */ 173*60251Shibler #include "getpagesize.h" 174*60251Shibler 175*60251Shibler #ifndef makedev /* Try to detect types.h already loaded */ 176*60251Shibler #include <sys/types.h> 177*60251Shibler #endif 178*60251Shibler #include <stdio.h> 179*60251Shibler #include <sys/stat.h> 180*60251Shibler #include <errno.h> 181*60251Shibler 182*60251Shibler extern char *start_of_text (); /* Start of text */ 183*60251Shibler extern char *start_of_data (); /* Start of initialized data */ 184*60251Shibler 185*60251Shibler #ifdef COFF 186*60251Shibler #ifndef USG 187*60251Shibler #ifndef STRIDE 188*60251Shibler #ifndef UMAX 189*60251Shibler #ifndef sun386 190*60251Shibler /* I have a suspicion that these are turned off on all systems 191*60251Shibler and can be deleted. Try it in version 19. */ 192*60251Shibler #include <filehdr.h> 193*60251Shibler #include <aouthdr.h> 194*60251Shibler #include <scnhdr.h> 195*60251Shibler #include <syms.h> 196*60251Shibler #endif /* not sun386 */ 197*60251Shibler #endif /* not UMAX */ 198*60251Shibler #endif /* Not STRIDE */ 199*60251Shibler #endif /* not USG */ 200*60251Shibler static long block_copy_start; /* Old executable start point */ 201*60251Shibler static struct filehdr f_hdr; /* File header */ 202*60251Shibler static struct aouthdr f_ohdr; /* Optional file header (a.out) */ 203*60251Shibler long bias; /* Bias to add for growth */ 204*60251Shibler long lnnoptr; /* Pointer to line-number info within file */ 205*60251Shibler #define SYMS_START block_copy_start 206*60251Shibler 207*60251Shibler static long text_scnptr; 208*60251Shibler static long data_scnptr; 209*60251Shibler 210*60251Shibler #else /* not COFF */ 211*60251Shibler 212*60251Shibler extern char *sbrk (); 213*60251Shibler 214*60251Shibler #define SYMS_START ((long) N_SYMOFF (ohdr)) 215*60251Shibler 216*60251Shibler /* Some machines override the structure name for an a.out header. */ 217*60251Shibler #ifndef EXEC_HDR_TYPE 218*60251Shibler #define EXEC_HDR_TYPE struct exec 219*60251Shibler #endif 220*60251Shibler 221*60251Shibler #ifdef HPUX 222*60251Shibler #ifdef HP9000S200_ID 223*60251Shibler #define MY_ID HP9000S200_ID 224*60251Shibler #else 225*60251Shibler #include <model.h> 226*60251Shibler #define MY_ID MYSYS 227*60251Shibler #endif /* no HP9000S200_ID */ 228*60251Shibler static MAGIC OLDMAGIC = {MY_ID, SHARE_MAGIC}; 229*60251Shibler static MAGIC NEWMAGIC = {MY_ID, DEMAND_MAGIC}; 230*60251Shibler #define N_TXTOFF(x) TEXT_OFFSET(x) 231*60251Shibler #define N_SYMOFF(x) LESYM_OFFSET(x) 232*60251Shibler static EXEC_HDR_TYPE hdr, ohdr; 233*60251Shibler 234*60251Shibler #else /* not HPUX */ 235*60251Shibler 236*60251Shibler #if defined (USG) && !defined (IBMRTAIX) && !defined (IRIS) 237*60251Shibler static struct bhdr hdr, ohdr; 238*60251Shibler #define a_magic fmagic 239*60251Shibler #define a_text tsize 240*60251Shibler #define a_data dsize 241*60251Shibler #define a_bss bsize 242*60251Shibler #define a_syms ssize 243*60251Shibler #define a_trsize rtsize 244*60251Shibler #define a_drsize rdsize 245*60251Shibler #define a_entry entry 246*60251Shibler #define N_BADMAG(x) \ 247*60251Shibler (((x).fmagic)!=OMAGIC && ((x).fmagic)!=NMAGIC &&\ 248*60251Shibler ((x).fmagic)!=FMAGIC && ((x).fmagic)!=IMAGIC) 249*60251Shibler #define NEWMAGIC FMAGIC 250*60251Shibler #else /* IRIS or IBMRTAIX or not USG */ 251*60251Shibler static EXEC_HDR_TYPE hdr, ohdr; 252*60251Shibler #define NEWMAGIC ZMAGIC 253*60251Shibler #endif /* IRIS or IBMRTAIX not USG */ 254*60251Shibler #endif /* not HPUX */ 255*60251Shibler 256*60251Shibler static int unexec_text_start; 257*60251Shibler static int unexec_data_start; 258*60251Shibler 259*60251Shibler #endif /* not COFF */ 260*60251Shibler 261*60251Shibler static int pagemask; 262*60251Shibler 263*60251Shibler /* Correct an int which is the bit pattern of a pointer to a byte 264*60251Shibler into an int which is the number of a byte. 265*60251Shibler This is a no-op on ordinary machines, but not on all. */ 266*60251Shibler 267*60251Shibler #ifndef ADDR_CORRECT /* Let m-*.h files override this definition */ 268*60251Shibler #define ADDR_CORRECT(x) ((char *)(x) - (char*)0) 269*60251Shibler #endif 270*60251Shibler 271*60251Shibler #ifdef emacs 272*60251Shibler 273*60251Shibler static 274*60251Shibler report_error (file, fd) 275*60251Shibler char *file; 276*60251Shibler int fd; 277*60251Shibler { 278*60251Shibler if (fd) 279*60251Shibler close (fd); 280*60251Shibler error ("Failure operating on %s", file); 281*60251Shibler } 282*60251Shibler #endif /* emacs */ 283*60251Shibler 284*60251Shibler #define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1 285*60251Shibler #define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1 286*60251Shibler #define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1 287*60251Shibler 288*60251Shibler static 289*60251Shibler report_error_1 (fd, msg, a1, a2) 290*60251Shibler int fd; 291*60251Shibler char *msg; 292*60251Shibler int a1, a2; 293*60251Shibler { 294*60251Shibler close (fd); 295*60251Shibler #ifdef emacs 296*60251Shibler error (msg, a1, a2); 297*60251Shibler #else 298*60251Shibler fprintf (stderr, msg, a1, a2); 299*60251Shibler fprintf (stderr, "\n"); 300*60251Shibler #endif 301*60251Shibler } 302*60251Shibler 303*60251Shibler /* **************************************************************** 304*60251Shibler * unexec 305*60251Shibler * 306*60251Shibler * driving logic. 307*60251Shibler */ 308*60251Shibler unexec (new_name, a_name, data_start, bss_start, entry_address) 309*60251Shibler char *new_name, *a_name; 310*60251Shibler unsigned data_start, bss_start, entry_address; 311*60251Shibler { 312*60251Shibler int new, a_out = -1; 313*60251Shibler 314*60251Shibler if (a_name && (a_out = open (a_name, 0)) < 0) 315*60251Shibler { 316*60251Shibler PERROR (a_name); 317*60251Shibler } 318*60251Shibler if ((new = creat (new_name, 0666)) < 0) 319*60251Shibler { 320*60251Shibler PERROR (new_name); 321*60251Shibler } 322*60251Shibler 323*60251Shibler if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0 324*60251Shibler || copy_text_and_data (new, a_out) < 0 325*60251Shibler || copy_sym (new, a_out, a_name, new_name) < 0 326*60251Shibler #ifdef COFF 327*60251Shibler || adjust_lnnoptrs (new, a_out, new_name) < 0 328*60251Shibler #endif 329*60251Shibler ) 330*60251Shibler { 331*60251Shibler close (new); 332*60251Shibler /* unlink (new_name); /* Failed, unlink new a.out */ 333*60251Shibler return -1; 334*60251Shibler } 335*60251Shibler 336*60251Shibler close (new); 337*60251Shibler if (a_out >= 0) 338*60251Shibler close (a_out); 339*60251Shibler mark_x (new_name); 340*60251Shibler return 0; 341*60251Shibler } 342*60251Shibler 343*60251Shibler /* **************************************************************** 344*60251Shibler * make_hdr 345*60251Shibler * 346*60251Shibler * Make the header in the new a.out from the header in core. 347*60251Shibler * Modify the text and data sizes. 348*60251Shibler */ 349*60251Shibler static int 350*60251Shibler make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) 351*60251Shibler int new, a_out; 352*60251Shibler unsigned data_start, bss_start, entry_address; 353*60251Shibler char *a_name; 354*60251Shibler char *new_name; 355*60251Shibler { 356*60251Shibler int tem; 357*60251Shibler #ifdef COFF 358*60251Shibler auto struct scnhdr f_thdr; /* Text section header */ 359*60251Shibler auto struct scnhdr f_dhdr; /* Data section header */ 360*60251Shibler auto struct scnhdr f_bhdr; /* Bss section header */ 361*60251Shibler auto struct scnhdr scntemp; /* Temporary section header */ 362*60251Shibler register int scns; 363*60251Shibler #endif /* COFF */ 364*60251Shibler #ifdef USG_SHARED_LIBRARIES 365*60251Shibler extern unsigned int bss_end; 366*60251Shibler #else 367*60251Shibler unsigned int bss_end; 368*60251Shibler #endif 369*60251Shibler 370*60251Shibler pagemask = getpagesize () - 1; 371*60251Shibler 372*60251Shibler /* Adjust text/data boundary. */ 373*60251Shibler #ifdef NO_REMAP 374*60251Shibler data_start = (int) start_of_data (); 375*60251Shibler #else /* not NO_REMAP */ 376*60251Shibler if (!data_start) 377*60251Shibler data_start = (int) start_of_data (); 378*60251Shibler #endif /* not NO_REMAP */ 379*60251Shibler data_start = ADDR_CORRECT (data_start); 380*60251Shibler 381*60251Shibler #ifdef SEGMENT_MASK 382*60251Shibler data_start = data_start & ~SEGMENT_MASK; /* (Down) to segment boundary. */ 383*60251Shibler #else 384*60251Shibler data_start = data_start & ~pagemask; /* (Down) to page boundary. */ 385*60251Shibler #endif 386*60251Shibler 387*60251Shibler bss_end = ADDR_CORRECT (sbrk (0)) + pagemask; 388*60251Shibler bss_end &= ~ pagemask; 389*60251Shibler 390*60251Shibler /* Adjust data/bss boundary. */ 391*60251Shibler if (bss_start != 0) 392*60251Shibler { 393*60251Shibler bss_start = (ADDR_CORRECT (bss_start) + pagemask); 394*60251Shibler /* (Up) to page bdry. */ 395*60251Shibler bss_start &= ~ pagemask; 396*60251Shibler if (bss_start > bss_end) 397*60251Shibler { 398*60251Shibler ERROR1 ("unexec: Specified bss_start (%u) is past end of program", 399*60251Shibler bss_start); 400*60251Shibler } 401*60251Shibler } 402*60251Shibler else 403*60251Shibler bss_start = bss_end; 404*60251Shibler 405*60251Shibler if (data_start > bss_start) /* Can't have negative data size. */ 406*60251Shibler { 407*60251Shibler ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)", 408*60251Shibler data_start, bss_start); 409*60251Shibler } 410*60251Shibler 411*60251Shibler #ifdef COFF 412*60251Shibler /* Salvage as much info from the existing file as possible */ 413*60251Shibler if (a_out >= 0) 414*60251Shibler { 415*60251Shibler if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) 416*60251Shibler { 417*60251Shibler PERROR (a_name); 418*60251Shibler } 419*60251Shibler block_copy_start += sizeof (f_hdr); 420*60251Shibler if (f_hdr.f_opthdr > 0) 421*60251Shibler { 422*60251Shibler if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) 423*60251Shibler { 424*60251Shibler PERROR (a_name); 425*60251Shibler } 426*60251Shibler block_copy_start += sizeof (f_ohdr); 427*60251Shibler } 428*60251Shibler /* Loop through section headers, copying them in */ 429*60251Shibler for (scns = f_hdr.f_nscns; scns > 0; scns--) { 430*60251Shibler if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp)) 431*60251Shibler { 432*60251Shibler PERROR (a_name); 433*60251Shibler } 434*60251Shibler if (scntemp.s_scnptr > 0L) 435*60251Shibler { 436*60251Shibler if (block_copy_start < scntemp.s_scnptr + scntemp.s_size) 437*60251Shibler block_copy_start = scntemp.s_scnptr + scntemp.s_size; 438*60251Shibler } 439*60251Shibler if (strcmp (scntemp.s_name, ".text") == 0) 440*60251Shibler { 441*60251Shibler f_thdr = scntemp; 442*60251Shibler } 443*60251Shibler else if (strcmp (scntemp.s_name, ".data") == 0) 444*60251Shibler { 445*60251Shibler f_dhdr = scntemp; 446*60251Shibler } 447*60251Shibler else if (strcmp (scntemp.s_name, ".bss") == 0) 448*60251Shibler { 449*60251Shibler f_bhdr = scntemp; 450*60251Shibler } 451*60251Shibler } 452*60251Shibler } 453*60251Shibler else 454*60251Shibler { 455*60251Shibler ERROR0 ("can't build a COFF file from scratch yet"); 456*60251Shibler } 457*60251Shibler 458*60251Shibler /* Now we alter the contents of all the f_*hdr variables 459*60251Shibler to correspond to what we want to dump. */ 460*60251Shibler 461*60251Shibler #ifdef USG_SHARED_LIBRARIES 462*60251Shibler 463*60251Shibler /* The amount of data we're adding to the file is distance from the 464*60251Shibler * end of the original .data space to the current end of the .data 465*60251Shibler * space. 466*60251Shibler */ 467*60251Shibler 468*60251Shibler bias = bss_end - (f_ohdr.data_start + f_dhdr.s_size); 469*60251Shibler 470*60251Shibler #endif 471*60251Shibler 472*60251Shibler f_hdr.f_flags |= (F_RELFLG | F_EXEC); 473*60251Shibler #ifdef EXEC_MAGIC 474*60251Shibler f_ohdr.magic = EXEC_MAGIC; 475*60251Shibler #endif 476*60251Shibler #ifndef NO_REMAP 477*60251Shibler f_ohdr.text_start = (long) start_of_text (); 478*60251Shibler f_ohdr.tsize = data_start - f_ohdr.text_start; 479*60251Shibler f_ohdr.data_start = data_start; 480*60251Shibler #endif /* NO_REMAP */ 481*60251Shibler f_ohdr.dsize = bss_start - f_ohdr.data_start; 482*60251Shibler f_ohdr.bsize = bss_end - bss_start; 483*60251Shibler f_thdr.s_size = f_ohdr.tsize; 484*60251Shibler f_thdr.s_scnptr = sizeof (f_hdr) + sizeof (f_ohdr); 485*60251Shibler f_thdr.s_scnptr += (f_hdr.f_nscns) * (sizeof (f_thdr)); 486*60251Shibler lnnoptr = f_thdr.s_lnnoptr; 487*60251Shibler #ifdef SECTION_ALIGNMENT 488*60251Shibler /* Some systems require special alignment 489*60251Shibler of the sections in the file itself. */ 490*60251Shibler f_thdr.s_scnptr 491*60251Shibler = (f_thdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT; 492*60251Shibler #endif /* SECTION_ALIGNMENT */ 493*60251Shibler text_scnptr = f_thdr.s_scnptr; 494*60251Shibler f_dhdr.s_paddr = f_ohdr.data_start; 495*60251Shibler f_dhdr.s_vaddr = f_ohdr.data_start; 496*60251Shibler f_dhdr.s_size = f_ohdr.dsize; 497*60251Shibler f_dhdr.s_scnptr = f_thdr.s_scnptr + f_thdr.s_size; 498*60251Shibler #ifdef SECTION_ALIGNMENT 499*60251Shibler /* Some systems require special alignment 500*60251Shibler of the sections in the file itself. */ 501*60251Shibler f_dhdr.s_scnptr 502*60251Shibler = (f_dhdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT; 503*60251Shibler #endif /* SECTION_ALIGNMENT */ 504*60251Shibler #ifdef DATA_SECTION_ALIGNMENT 505*60251Shibler /* Some systems require special alignment 506*60251Shibler of the data section only. */ 507*60251Shibler f_dhdr.s_scnptr 508*60251Shibler = (f_dhdr.s_scnptr + DATA_SECTION_ALIGNMENT) & ~DATA_SECTION_ALIGNMENT; 509*60251Shibler #endif /* DATA_SECTION_ALIGNMENT */ 510*60251Shibler data_scnptr = f_dhdr.s_scnptr; 511*60251Shibler f_bhdr.s_paddr = f_ohdr.data_start + f_ohdr.dsize; 512*60251Shibler f_bhdr.s_vaddr = f_ohdr.data_start + f_ohdr.dsize; 513*60251Shibler f_bhdr.s_size = f_ohdr.bsize; 514*60251Shibler f_bhdr.s_scnptr = 0L; 515*60251Shibler #ifndef USG_SHARED_LIBRARIES 516*60251Shibler bias = f_dhdr.s_scnptr + f_dhdr.s_size - block_copy_start; 517*60251Shibler #endif 518*60251Shibler 519*60251Shibler if (f_hdr.f_symptr > 0L) 520*60251Shibler { 521*60251Shibler f_hdr.f_symptr += bias; 522*60251Shibler } 523*60251Shibler 524*60251Shibler if (f_thdr.s_lnnoptr > 0L) 525*60251Shibler { 526*60251Shibler f_thdr.s_lnnoptr += bias; 527*60251Shibler } 528*60251Shibler 529*60251Shibler #ifdef ADJUST_EXEC_HEADER 530*60251Shibler ADJUST_EXEC_HEADER 531*60251Shibler #endif /* ADJUST_EXEC_HEADER */ 532*60251Shibler 533*60251Shibler if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) 534*60251Shibler { 535*60251Shibler PERROR (new_name); 536*60251Shibler } 537*60251Shibler 538*60251Shibler if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) 539*60251Shibler { 540*60251Shibler PERROR (new_name); 541*60251Shibler } 542*60251Shibler 543*60251Shibler #ifndef USG_SHARED_LIBRARIES 544*60251Shibler 545*60251Shibler if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr)) 546*60251Shibler { 547*60251Shibler PERROR (new_name); 548*60251Shibler } 549*60251Shibler 550*60251Shibler if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr)) 551*60251Shibler { 552*60251Shibler PERROR (new_name); 553*60251Shibler } 554*60251Shibler 555*60251Shibler if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr)) 556*60251Shibler { 557*60251Shibler PERROR (new_name); 558*60251Shibler } 559*60251Shibler 560*60251Shibler #else /* USG_SHARED_LIBRARIES */ 561*60251Shibler 562*60251Shibler /* The purpose of this code is to write out the new file's section 563*60251Shibler * header table. 564*60251Shibler * 565*60251Shibler * Scan through the original file's sections. If the encountered 566*60251Shibler * section is one we know (.text, .data or .bss), write out the 567*60251Shibler * correct header. If it is a section we do not know (such as 568*60251Shibler * .lib), adjust the address of where the section data is in the 569*60251Shibler * file, and write out the header. 570*60251Shibler * 571*60251Shibler * If any section preceeds .text or .data in the file, this code 572*60251Shibler * will not adjust the file pointer for that section correctly. 573*60251Shibler */ 574*60251Shibler 575*60251Shibler lseek (a_out, sizeof (f_hdr) + sizeof (f_ohdr), 0); 576*60251Shibler 577*60251Shibler for (scns = f_hdr.f_nscns; scns > 0; scns--) 578*60251Shibler { 579*60251Shibler if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp)) 580*60251Shibler PERROR (a_name); 581*60251Shibler 582*60251Shibler if (!strcmp (scntemp.s_name, f_thdr.s_name)) /* .text */ 583*60251Shibler { 584*60251Shibler if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr)) 585*60251Shibler PERROR (new_name); 586*60251Shibler } 587*60251Shibler else if (!strcmp (scntemp.s_name, f_dhdr.s_name)) /* .data */ 588*60251Shibler { 589*60251Shibler if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr)) 590*60251Shibler PERROR (new_name); 591*60251Shibler } 592*60251Shibler else if (!strcmp (scntemp.s_name, f_bhdr.s_name)) /* .bss */ 593*60251Shibler { 594*60251Shibler if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr)) 595*60251Shibler PERROR (new_name); 596*60251Shibler } 597*60251Shibler else 598*60251Shibler { 599*60251Shibler if (scntemp.s_scnptr) 600*60251Shibler scntemp.s_scnptr += bias; 601*60251Shibler if (write (new, &scntemp, sizeof (scntemp)) != sizeof (scntemp)) 602*60251Shibler PERROR (new_name); 603*60251Shibler } 604*60251Shibler } 605*60251Shibler #endif /* USG_SHARED_LIBRARIES */ 606*60251Shibler 607*60251Shibler return (0); 608*60251Shibler 609*60251Shibler #else /* if not COFF */ 610*60251Shibler 611*60251Shibler /* Get symbol table info from header of a.out file if given one. */ 612*60251Shibler if (a_out >= 0) 613*60251Shibler { 614*60251Shibler if (read (a_out, &ohdr, sizeof hdr) != sizeof hdr) 615*60251Shibler { 616*60251Shibler PERROR (a_name); 617*60251Shibler } 618*60251Shibler 619*60251Shibler if (N_BADMAG (ohdr)) 620*60251Shibler { 621*60251Shibler ERROR1 ("invalid magic number in %s", a_name); 622*60251Shibler } 623*60251Shibler hdr = ohdr; 624*60251Shibler } 625*60251Shibler else 626*60251Shibler { 627*60251Shibler bzero (hdr, sizeof hdr); 628*60251Shibler } 629*60251Shibler 630*60251Shibler unexec_text_start = (long) start_of_text (); 631*60251Shibler unexec_data_start = data_start; 632*60251Shibler 633*60251Shibler /* Machine-dependent fixup for header, or maybe for unexec_text_start */ 634*60251Shibler #ifdef ADJUST_EXEC_HEADER 635*60251Shibler ADJUST_EXEC_HEADER; 636*60251Shibler #endif /* ADJUST_EXEC_HEADER */ 637*60251Shibler 638*60251Shibler hdr.a_trsize = 0; 639*60251Shibler hdr.a_drsize = 0; 640*60251Shibler if (entry_address != 0) 641*60251Shibler hdr.a_entry = entry_address; 642*60251Shibler 643*60251Shibler hdr.a_bss = bss_end - bss_start; 644*60251Shibler hdr.a_data = bss_start - data_start; 645*60251Shibler #ifdef NO_REMAP 646*60251Shibler hdr.a_text = ohdr.a_text; 647*60251Shibler #else /* not NO_REMAP */ 648*60251Shibler hdr.a_text = data_start - unexec_text_start; 649*60251Shibler 650*60251Shibler #ifdef A_TEXT_OFFSET 651*60251Shibler hdr.a_text += A_TEXT_OFFSET (ohdr); 652*60251Shibler #endif 653*60251Shibler 654*60251Shibler #endif /* not NO_REMAP */ 655*60251Shibler 656*60251Shibler if (write (new, &hdr, sizeof hdr) != sizeof hdr) 657*60251Shibler { 658*60251Shibler PERROR (new_name); 659*60251Shibler } 660*60251Shibler 661*60251Shibler #ifdef A_TEXT_OFFSET 662*60251Shibler hdr.a_text -= A_TEXT_OFFSET (ohdr); 663*60251Shibler #endif 664*60251Shibler 665*60251Shibler return 0; 666*60251Shibler 667*60251Shibler #endif /* not COFF */ 668*60251Shibler } 669*60251Shibler 670*60251Shibler /* **************************************************************** 671*60251Shibler * copy_text_and_data 672*60251Shibler * 673*60251Shibler * Copy the text and data segments from memory to the new a.out 674*60251Shibler */ 675*60251Shibler static int 676*60251Shibler copy_text_and_data (new, a_out) 677*60251Shibler int new, a_out; 678*60251Shibler { 679*60251Shibler register char *end; 680*60251Shibler register char *ptr; 681*60251Shibler 682*60251Shibler #ifdef COFF 683*60251Shibler 684*60251Shibler #ifdef USG_SHARED_LIBRARIES 685*60251Shibler 686*60251Shibler int scns; 687*60251Shibler struct scnhdr scntemp; /* Temporary section header */ 688*60251Shibler 689*60251Shibler /* The purpose of this code is to write out the new file's section 690*60251Shibler * contents. 691*60251Shibler * 692*60251Shibler * Step through the section table. If we know the section (.text, 693*60251Shibler * .data) do the appropriate thing. Otherwise, if the section has 694*60251Shibler * no allocated space in the file (.bss), do nothing. Otherwise, 695*60251Shibler * the section has space allocated in the file, and is not a section 696*60251Shibler * we know. So just copy it. 697*60251Shibler */ 698*60251Shibler 699*60251Shibler lseek (a_out, sizeof (struct filehdr) + sizeof (struct aouthdr), 0); 700*60251Shibler 701*60251Shibler for (scns = f_hdr.f_nscns; scns > 0; scns--) 702*60251Shibler { 703*60251Shibler if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp)) 704*60251Shibler PERROR ("temacs"); 705*60251Shibler 706*60251Shibler if (!strcmp (scntemp.s_name, ".text")) 707*60251Shibler { 708*60251Shibler lseek (new, (long) text_scnptr, 0); 709*60251Shibler ptr = (char *) f_ohdr.text_start; 710*60251Shibler end = ptr + f_ohdr.tsize; 711*60251Shibler write_segment (new, ptr, end); 712*60251Shibler } 713*60251Shibler else if (!strcmp (scntemp.s_name, ".data")) 714*60251Shibler { 715*60251Shibler lseek (new, (long) data_scnptr, 0); 716*60251Shibler ptr = (char *) f_ohdr.data_start; 717*60251Shibler end = ptr + f_ohdr.dsize; 718*60251Shibler write_segment (new, ptr, end); 719*60251Shibler } 720*60251Shibler else if (!scntemp.s_scnptr) 721*60251Shibler ; /* do nothing - no data for this section */ 722*60251Shibler else 723*60251Shibler { 724*60251Shibler char page[BUFSIZ]; 725*60251Shibler int size, n; 726*60251Shibler long old_a_out_ptr = lseek (a_out, 0, 1); 727*60251Shibler 728*60251Shibler lseek (a_out, scntemp.s_scnptr, 0); 729*60251Shibler for (size = scntemp.s_size; size > 0; size -= sizeof (page)) 730*60251Shibler { 731*60251Shibler n = size > sizeof (page) ? sizeof (page) : size; 732*60251Shibler if (read (a_out, page, n) != n || write (new, page, n) != n) 733*60251Shibler PERROR ("xemacs"); 734*60251Shibler } 735*60251Shibler lseek (a_out, old_a_out_ptr, 0); 736*60251Shibler } 737*60251Shibler } 738*60251Shibler 739*60251Shibler #else /* COFF, but not USG_SHARED_LIBRARIES */ 740*60251Shibler 741*60251Shibler lseek (new, (long) text_scnptr, 0); 742*60251Shibler ptr = (char *) f_ohdr.text_start; 743*60251Shibler end = ptr + f_ohdr.tsize; 744*60251Shibler write_segment (new, ptr, end); 745*60251Shibler 746*60251Shibler lseek (new, (long) data_scnptr, 0); 747*60251Shibler ptr = (char *) f_ohdr.data_start; 748*60251Shibler end = ptr + f_ohdr.dsize; 749*60251Shibler write_segment (new, ptr, end); 750*60251Shibler 751*60251Shibler #endif /* USG_SHARED_LIBRARIES */ 752*60251Shibler 753*60251Shibler #else /* if not COFF */ 754*60251Shibler 755*60251Shibler /* Some machines count the header as part of the text segment. 756*60251Shibler That is to say, the header appears in core 757*60251Shibler just before the address that start_of_text () returns. 758*60251Shibler For them, N_TXTOFF is the place where the header goes. 759*60251Shibler We must adjust the seek to the place after the header. 760*60251Shibler Note that at this point hdr.a_text does *not* count 761*60251Shibler the extra A_TEXT_OFFSET bytes, only the actual bytes of code. */ 762*60251Shibler 763*60251Shibler #ifdef A_TEXT_SEEK 764*60251Shibler lseek (new, (long) A_TEXT_SEEK (hdr), 0); 765*60251Shibler #else 766*60251Shibler #ifdef A_TEXT_OFFSET 767*60251Shibler /* Note that on the Sequent machine A_TEXT_OFFSET != sizeof (hdr) 768*60251Shibler and sizeof (hdr) is the correct amount to add here. */ 769*60251Shibler /* In version 19, eliminate this case and use A_TEXT_SEEK whenever 770*60251Shibler N_TXTOFF is not right. */ 771*60251Shibler lseek (new, (long) N_TXTOFF (hdr) + sizeof (hdr), 0); 772*60251Shibler #else 773*60251Shibler lseek (new, (long) N_TXTOFF (hdr), 0); 774*60251Shibler #endif /* no A_TEXT_OFFSET */ 775*60251Shibler #endif /* no A_TEXT_SEEK */ 776*60251Shibler 777*60251Shibler ptr = (char *) unexec_text_start; 778*60251Shibler end = ptr + hdr.a_text; 779*60251Shibler write_segment (new, ptr, end); 780*60251Shibler 781*60251Shibler ptr = (char *) unexec_data_start; 782*60251Shibler end = ptr + hdr.a_data; 783*60251Shibler /* This lseek is certainly incorrect when A_TEXT_OFFSET 784*60251Shibler and I believe it is a no-op otherwise. 785*60251Shibler Let's see if its absence ever fails. */ 786*60251Shibler /* lseek (new, (long) N_TXTOFF (hdr) + hdr.a_text, 0); */ 787*60251Shibler write_segment (new, ptr, end); 788*60251Shibler 789*60251Shibler #endif /* not COFF */ 790*60251Shibler 791*60251Shibler return 0; 792*60251Shibler } 793*60251Shibler 794*60251Shibler write_segment (new, ptr, end) 795*60251Shibler int new; 796*60251Shibler register char *ptr, *end; 797*60251Shibler { 798*60251Shibler register int i, nwrite, ret; 799*60251Shibler char buf[80]; 800*60251Shibler extern int errno; 801*60251Shibler char zeros[128]; 802*60251Shibler 803*60251Shibler bzero (zeros, sizeof zeros); 804*60251Shibler 805*60251Shibler for (i = 0; ptr < end;) 806*60251Shibler { 807*60251Shibler /* distance to next multiple of 128. */ 808*60251Shibler nwrite = (((int) ptr + 128) & -128) - (int) ptr; 809*60251Shibler /* But not beyond specified end. */ 810*60251Shibler if (nwrite > end - ptr) nwrite = end - ptr; 811*60251Shibler ret = write (new, ptr, nwrite); 812*60251Shibler /* If write gets a page fault, it means we reached 813*60251Shibler a gap between the old text segment and the old data segment. 814*60251Shibler This gap has probably been remapped into part of the text segment. 815*60251Shibler So write zeros for it. */ 816*60251Shibler if (ret == -1 && errno == EFAULT) 817*60251Shibler write (new, zeros, nwrite); 818*60251Shibler else if (nwrite != ret) 819*60251Shibler { 820*60251Shibler sprintf (buf, 821*60251Shibler "unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d", 822*60251Shibler ptr, new, nwrite, ret, errno); 823*60251Shibler PERROR (buf); 824*60251Shibler } 825*60251Shibler i += nwrite; 826*60251Shibler ptr += nwrite; 827*60251Shibler } 828*60251Shibler } 829*60251Shibler 830*60251Shibler /* **************************************************************** 831*60251Shibler * copy_sym 832*60251Shibler * 833*60251Shibler * Copy the relocation information and symbol table from the a.out to the new 834*60251Shibler */ 835*60251Shibler static int 836*60251Shibler copy_sym (new, a_out, a_name, new_name) 837*60251Shibler int new, a_out; 838*60251Shibler char *a_name, *new_name; 839*60251Shibler { 840*60251Shibler char page[1024]; 841*60251Shibler int n; 842*60251Shibler 843*60251Shibler if (a_out < 0) 844*60251Shibler return 0; 845*60251Shibler 846*60251Shibler #ifdef COFF 847*60251Shibler if (SYMS_START == 0L) 848*60251Shibler return 0; 849*60251Shibler #endif /* COFF */ 850*60251Shibler 851*60251Shibler #ifdef COFF 852*60251Shibler if (lnnoptr) /* if there is line number info */ 853*60251Shibler lseek (a_out, lnnoptr, 0); /* start copying from there */ 854*60251Shibler else 855*60251Shibler #endif /* COFF */ 856*60251Shibler lseek (a_out, SYMS_START, 0); /* Position a.out to symtab. */ 857*60251Shibler 858*60251Shibler while ((n = read (a_out, page, sizeof page)) > 0) 859*60251Shibler { 860*60251Shibler if (write (new, page, n) != n) 861*60251Shibler { 862*60251Shibler PERROR (new_name); 863*60251Shibler } 864*60251Shibler } 865*60251Shibler if (n < 0) 866*60251Shibler { 867*60251Shibler PERROR (a_name); 868*60251Shibler } 869*60251Shibler return 0; 870*60251Shibler } 871*60251Shibler 872*60251Shibler /* **************************************************************** 873*60251Shibler * mark_x 874*60251Shibler * 875*60251Shibler * After succesfully building the new a.out, mark it executable 876*60251Shibler */ 877*60251Shibler static 878*60251Shibler mark_x (name) 879*60251Shibler char *name; 880*60251Shibler { 881*60251Shibler struct stat sbuf; 882*60251Shibler int um; 883*60251Shibler int new = 0; /* for PERROR */ 884*60251Shibler 885*60251Shibler um = umask (777); 886*60251Shibler umask (um); 887*60251Shibler if (stat (name, &sbuf) == -1) 888*60251Shibler { 889*60251Shibler PERROR (name); 890*60251Shibler } 891*60251Shibler sbuf.st_mode |= 0111 & ~um; 892*60251Shibler if (chmod (name, sbuf.st_mode) == -1) 893*60251Shibler PERROR (name); 894*60251Shibler } 895*60251Shibler 896*60251Shibler /* 897*60251Shibler * If the COFF file contains a symbol table and a line number section, 898*60251Shibler * then any auxiliary entries that have values for x_lnnoptr must 899*60251Shibler * be adjusted by the amount that the line number section has moved 900*60251Shibler * in the file (bias computed in make_hdr). The #@$%&* designers of 901*60251Shibler * the auxiliary entry structures used the absolute file offsets for 902*60251Shibler * the line number entry rather than an offset from the start of the 903*60251Shibler * line number section! 904*60251Shibler * 905*60251Shibler * When I figure out how to scan through the symbol table and pick out 906*60251Shibler * the auxiliary entries that need adjustment, this routine will 907*60251Shibler * be fixed. As it is now, all such entries are wrong and sdb 908*60251Shibler * will complain. Fred Fish, UniSoft Systems Inc. 909*60251Shibler */ 910*60251Shibler 911*60251Shibler #ifdef COFF 912*60251Shibler 913*60251Shibler /* This function is probably very slow. Instead of reopening the new 914*60251Shibler file for input and output it should copy from the old to the new 915*60251Shibler using the two descriptors already open (WRITEDESC and READDESC). 916*60251Shibler Instead of reading one small structure at a time it should use 917*60251Shibler a reasonable size buffer. But I don't have time to work on such 918*60251Shibler things, so I am installing it as submitted to me. -- RMS. */ 919*60251Shibler 920*60251Shibler adjust_lnnoptrs (writedesc, readdesc, new_name) 921*60251Shibler int writedesc; 922*60251Shibler int readdesc; 923*60251Shibler char *new_name; 924*60251Shibler { 925*60251Shibler register int nsyms; 926*60251Shibler register int new; 927*60251Shibler #ifdef amdahl_uts 928*60251Shibler SYMENT symentry; 929*60251Shibler AUXENT auxentry; 930*60251Shibler #else 931*60251Shibler struct syment symentry; 932*60251Shibler union auxent auxentry; 933*60251Shibler #endif 934*60251Shibler 935*60251Shibler if (!lnnoptr || !f_hdr.f_symptr) 936*60251Shibler return 0; 937*60251Shibler 938*60251Shibler if ((new = open (new_name, 2)) < 0) 939*60251Shibler { 940*60251Shibler PERROR (new_name); 941*60251Shibler return -1; 942*60251Shibler } 943*60251Shibler 944*60251Shibler lseek (new, f_hdr.f_symptr, 0); 945*60251Shibler for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++) 946*60251Shibler { 947*60251Shibler read (new, &symentry, SYMESZ); 948*60251Shibler if (symentry.n_numaux) 949*60251Shibler { 950*60251Shibler read (new, &auxentry, AUXESZ); 951*60251Shibler nsyms++; 952*60251Shibler if (ISFCN (symentry.n_type)) { 953*60251Shibler auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias; 954*60251Shibler lseek (new, -AUXESZ, 1); 955*60251Shibler write (new, &auxentry, AUXESZ); 956*60251Shibler } 957*60251Shibler } 958*60251Shibler } 959*60251Shibler close (new); 960*60251Shibler } 961*60251Shibler 962*60251Shibler #endif /* COFF */ 963*60251Shibler 964*60251Shibler #endif /* not CANNOT_UNEXEC */ 965*60251Shibler 966*60251Shibler #endif /* not CANNOT_DUMP */ 967