* dbusbind.c (xd_retrieve_arg): Pacify GCC on x86_64 GNU/Linux.
[bpt/emacs.git] / src / unexnext.c
index 08fe464..48743a3 100644 (file)
@@ -1,12 +1,13 @@
 /* Dump Emacs in macho format.
-   Copyright (C) 1990 Free Software Foundation, Inc.
+   Copyright (C) 1990, 1993, 2001, 2002, 2003, 2004,
+                 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
    Written by Bradley Taylor (btaylor@next.com).
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 1, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -16,7 +17,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 
 #undef __STRICT_BSD__
@@ -24,14 +26,18 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
-#include <mach.h>
-#include <sys/loader.h>
+#include <mach/mach.h>
+#include <mach-o/loader.h>
+#include <mach-o/reloc.h>
 #include <sys/file.h>
 #include <sys/stat.h>
-#include <libc.h>
+#include <unistd.h>
+/* Instead of unistd.h, this used to include libc.h.
+   "Nelson H. F. Beebe" <beebe@math.utah.edu> says that doesn't work
+   in system version 3.3.  */
 
 
-extern struct section *getsectbyname(char *, char *);
+int malloc_cookie;
 
 /*
  * Kludge: we don't expect any program data beyond VM_HIGHDATA
@@ -39,7 +45,7 @@ extern struct section *getsectbyname(char *, char *);
  * pages it vm_allocated and write only those out into the data segment.
  *
  * This kludge may break when we stop using fixed virtual address
- * shared libraries. Actually, emacs will probably continue working, but be 
+ * shared libraries. Actually, emacs will probably continue working, but be
  * much larger on disk than it needs to be (because non-malloced data will
  * be in the file).
  */
@@ -68,7 +74,7 @@ grow(
                *the_commands = malloc(sizeof(*the_commands));
        } else {
                (*the_commands_len)++;
-               *the_commands = realloc(*the_commands, 
+               *the_commands = realloc(*the_commands,
                                        (*the_commands_len *
                                         sizeof(**the_commands)));
        }
@@ -120,7 +126,7 @@ read_macho(
                return (0);
        }
        for (i = 0; i < the_header->ncmds; i++) {
-               if (read(fd, &command, sizeof(struct load_command)) != 
+               if (read(fd, &command, sizeof(struct load_command)) !=
                    sizeof(struct load_command)) {
                        fatal_unexec("cannot read macho load command header");
                        return (0);
@@ -133,8 +139,8 @@ read_macho(
                buf = malloc(command.cmdsize);
                buf->cmd = command.cmd;
                buf->cmdsize = command.cmdsize;
-               if (read(fd, ((char *)buf + 
-                             sizeof(struct load_command)), 
+               if (read(fd, ((char *)buf +
+                             sizeof(struct load_command)),
                         size) != size) {
                        fatal_unexec("cannot read load command data");
                        return (0);
@@ -175,35 +181,35 @@ get_data_region(
        kern_return_t ret;
        struct section *sect;
 
-       sect = getsectbyname(SEG_DATA, SECT_DATA);
+       sect = (struct section *) getsectbyname(SEG_DATA, SECT_DATA);
        region.address = 0;
        *address = 0;
        for (;;) {
-               ret = vm_region(task_self(), 
-                               &region.address, 
-                               &region.size, 
-                               &region.protection, 
-                               &region.max_protection, 
+               ret = vm_region(task_self(),
+                               &region.address,
+                               &region.size,
+                               &region.protection,
+                               &region.max_protection,
                                &region.inheritance,
-                               &region.shared, 
-                               &region.object_name, 
+                               &region.shared,
+                               &region.object_name,
                                &region.offset);
                if (ret != KERN_SUCCESS || region.address >= VM_HIGHDATA) {
                        break;
                }
                if (*address != 0) {
                        if (region.address > *address + *size) {
-                               if (!filldatagap(*address, size, 
+                               if (!filldatagap(*address, size,
                                                 region.address)) {
                                        return (0);
                                }
-                       } 
+                       }
                        *size += region.size;
                } else {
                        if (region.address == sect->addr) {
                                *address = region.address;
                                *size = region.size;
-                       } 
+                       }
                }
                region.address += region.size;
        }
@@ -242,7 +248,7 @@ unexec_doit(
        struct load_command **the_commands = NULL;
        unsigned the_commands_len;
        struct mach_header the_header;
-       int fgrowth;
+       int fgrowth = 0;
        int fdatastart;
        int fdatasize;
        int size;
@@ -250,18 +256,24 @@ unexec_doit(
        char *buf;
        vm_address_t data_address;
        vm_size_t data_size;
+       vm_size_t vmaddr_growth = 0;
+       vm_size_t dataseg_vmaddr, dataseg_vmend;
 
        struct segment_command *segment;
 
+#ifdef NS_TARGET
+       unsigned long extreloff = 0;
+       unsigned long nextrel = 0;
+       struct dysymtab_command *dysymtab;
+       struct relocation_info reloc_info;
+#endif
+
        if (!read_macho(infd, &the_header, &the_commands, &the_commands_len)) {
                return (0);
        }
 
 
-       {
-         extern int malloc_cookie;
-         malloc_cookie = malloc_freezedry();
-       }
+       malloc_cookie = malloc_freezedry ();
        if (!get_data_region(&data_address, &data_size)) {
                return (0);
        }
@@ -282,11 +294,21 @@ unexec_doit(
                                if (strcmp(segment->segname, SEG_DATA) == 0) {
                                        fdatastart = segment->fileoff;
                                        fdatasize = segment->filesize;
-                                       fgrowth = (data_size - 
+                                       fgrowth = (data_size -
                                                   segment->filesize);
                                        segment->vmsize = data_size;
                                        segment->filesize = data_size;
+                                       dataseg_vmaddr = segment->vmaddr;
+                                       dataseg_vmend = segment->vmaddr + segment->vmsize;
+                                       vmaddr_growth = segment->vmaddr + segment->vmsize;
+                               } else {
+                                       ((struct segment_command *)the_commands[i])->fileoff += fgrowth;
                                }
+
+                               if( strcmp( segment->segname, SEG_LINKEDIT ) == 0 ) {
+                                       segment->vmaddr = vmaddr_growth;
+                               }
+
                                break;
                        case LC_SYMTAB:
                                ((struct symtab_command *)
@@ -298,41 +320,50 @@ unexec_doit(
                                ((struct symseg_command *)
                                 the_commands[i])->offset += fgrowth;
                                break;
+#ifdef NS_TARGET
+                       case LC_DYSYMTAB:
+                               dysymtab = ((struct dysymtab_command *)the_commands[i]);
+                               extreloff = dysymtab->extreloff;
+                               nextrel = dysymtab->nextrel;
+                               dysymtab->indirectsymoff += fgrowth;
+                               dysymtab->extreloff += fgrowth;
+                               break;
+#endif
                        default:
                                break;
                        }
                }
-               
+
                /*
                 * Write header
                 */
-               if (write(outfd, &the_header, 
+               if (write(outfd, &the_header,
                          sizeof(the_header)) != sizeof(the_header)) {
                        fatal_unexec("cannot write output file");
                        return (0);
                }
-               
+
                /*
                 * Write commands
                 */
                for (i = 0; i < the_commands_len; i++) {
-                       if (write(outfd, the_commands[i], 
-                                 the_commands[i]->cmdsize) != 
+                       if (write(outfd, the_commands[i],
+                                 the_commands[i]->cmdsize) !=
                            the_commands[i]->cmdsize) {
                                fatal_unexec("cannot write output file");
                                return (0);
                        }
                }
-               
+
                /*
                 * Write original text
                 */
-               if (lseek(infd, the_header.sizeofcmds + sizeof(the_header), 
+               if (lseek(infd, the_header.sizeofcmds + sizeof(the_header),
                          L_SET) < 0) {
                        fatal_unexec("cannot seek input file");
                        return (0);
                }
-               size = fdatastart - (sizeof(the_header) + 
+               size = fdatastart - (sizeof(the_header) +
                                     the_header.sizeofcmds);
                buf = my_malloc(size);
                if (read(infd, buf, size) != size) {
@@ -345,17 +376,17 @@ unexec_doit(
                        return (0);
                }
                my_free(buf, size);
-               
-               
+
+
                /*
                 * Write new data
                 */
-               if (write(outfd, (char *)data_address, 
+               if (write(outfd, (char *)data_address,
                          data_size) != data_size) {
                        fatal_unexec("cannot write output file");
                        return (0);
                }
-               
+
        }
 
        /*
@@ -384,6 +415,55 @@ unexec_doit(
                return (0);
        }
        free(buf);
+
+#ifdef NS_TARGET
+        /*
+         * Fix up relocation entries in the data segment.
+         */
+
+       if (lseek(infd, extreloff, L_SET) < 0) {
+               fatal_unexec("cannot seek input file");
+               return (0);
+       }
+
+        for (i = 0; i < nextrel; i++)
+        {
+          long zeroval = 0;
+
+          if (read(infd, &reloc_info, sizeof (reloc_info)) != sizeof (reloc_info)) {
+            fatal_unexec("cannot read input file");
+            return (0);
+          }
+          if (reloc_info.r_address >= dataseg_vmaddr && reloc_info.r_address < dataseg_vmend)
+          {
+            if (lseek (outfd, fdatastart + reloc_info.r_address - dataseg_vmaddr, L_SET) < 0 ) {
+              fatal_unexec("cannot seek input file");
+              return (0);
+            }
+            switch (reloc_info.r_length) {
+              case 0:
+               if (write(outfd, &zeroval, 1) != 1) {
+                       fatal_unexec("cannot write output file");
+                       return (0);
+               }
+                break;
+              case 1:
+               if (write(outfd, &zeroval, 2) != 2) {
+                       fatal_unexec("cannot write output file");
+                       return (0);
+               }
+                break;
+              case 2:
+               if (write(outfd, &zeroval, 4) != 4) {
+                       fatal_unexec("cannot write output file");
+                       return (0);
+               }
+                break;
+            }
+          }
+        }
+#endif
+
        return (1);
 }
 
@@ -403,7 +483,7 @@ unexec(
                fatal_unexec("cannot open input file `%s'", infile);
                exit(1);
        }
-       
+
        tmpnam(tmpbuf);
        tmpfile = rindex(tmpbuf, '/');
        if (tmpfile == NULL) {
@@ -431,3 +511,6 @@ unexec(
                exit(1);
        }
 }
+
+/* arch-tag: 9796bdc3-c050-417a-b2f5-4cfd31032634
+   (do not change this comment) */