]> Cypherpunks repositories - gostls13.git/commitdiff
make 6l produce dynamically linked binaries (although they are fully statically linke...
authorRob Pike <r@golang.org>
Tue, 21 Jul 2009 22:10:47 +0000 (15:10 -0700)
committerRob Pike <r@golang.org>
Tue, 21 Jul 2009 22:10:47 +0000 (15:10 -0700)
as go is concerned).  the -d flag is now flipped; as on the mac, -d disables dynamic.

much remains to be improved to move the output closer to the gcc format.

R=rsc
DELTA=366  (310 added, 30 deleted, 26 changed)
OCL=31929
CL=31951

src/cmd/6l/asm.c
src/cmd/6l/l.h
src/cmd/6l/obj.c
src/cmd/ld/elf64.c
src/cmd/ld/elf64.h

index c1d0a4d97a63221ed3a744f6c0e2f8068cf25b7e..850077b80c98d05757f409efa4c44f100880dbdb 100644 (file)
 
 #define PADDR(a)       ((uint32)(a) & ~0x80000000)
 
+char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2";
+
+char   zeroes[32];
+
 vlong
 entryvalue(void)
 {
@@ -124,11 +128,11 @@ asmb(void)
        int32 v, magic;
        int a, nl;
        uchar *op1;
-       vlong vl, va, fo, w, symo;
+       vlong vl, va, startva, fo, w, symo, hashoff;
        vlong symdatva = 0x99LL<<32;
        Elf64Hdr *eh;
-       Elf64PHdr *ph;
-       Elf64SHdr *sh;
+       Elf64PHdr *ph, *pph;
+       Elf64SHdr *sh, *dynsh;
 
        if(debug['v'])
                Bprint(&bso, "%5.2f asmb\n", cputime());
@@ -237,7 +241,7 @@ asmb(void)
                        symo = rnd(HEADR+textsize, INITRND)+rnd(datsize, INITRND);
                        break;
                case 7:
-                       symo = rnd(HEADR+textsize, INITRND)+datsize+STRTABSIZE;
+                       symo = rnd(HEADR+textsize, INITRND)+datsize;
                        symo = rnd(symo, INITRND);
                        break;
                }
@@ -419,16 +423,132 @@ asmb(void)
                /* elf amd-64 */
 
                fo = 0;
-               va = INITTEXT & ~((vlong)INITRND - 1);
+               startva = INITTEXT - HEADR;
+               va = startva;
                w = HEADR+textsize;
 
+               /* This null SHdr must appear before all others */
+               sh = newElf64SHdr("");
+
+               pph = nil;      /* silence compiler */
+
+               /* Dynamic linking sections */
+               if (!debug['d']) {      /* -d suppresses dynamic loader format */
+
+                       /* P headers */
+                       /* program header info */
+                       pph = newElf64PHdr();
+                       pph->type = PT_PHDR;
+                       pph->flags = PF_R + PF_X;
+                       pph->off = ELF64HDRSIZE;
+                       pph->vaddr = startva + pph->off;
+                       pph->paddr = startva + pph->off;
+                       pph->align = 8;
+
+                       /* interpreter */
+                       ph = newElf64PHdr();
+                       ph->type = PT_INTERP;
+                       ph->flags = PF_R;
+                       ph->off = startelf();
+                       ph->vaddr = startva;
+                       ph->paddr = startva;
+                       write(cout, linuxdynld, sizeof linuxdynld);
+                       ph->filesz = endelf() - ph->off;
+                       ph->align = 1;
+
+                       /* dynamic load section */
+                       ph = newElf64PHdr();
+                       ph->type = PT_LOAD;
+                       ph->flags = PF_R + PF_W;
+                       ph->off = 0;
+                       ph->vaddr = startva + ph->off;
+                       ph->paddr = startva + ph->off;
+                       ph->align = 8;
+
+                       /* S headers inside dynamic load section */
+                       dynsh = newElf64SHdr(".dynamic");       // must be first
+                       dynsh->off = startelf();
+
+                       seek(cout, ELFDYNAMICSIZE, 1);  // leave room for dynamic table
+
+                       sh = newElf64SHdr(".hash");
+                       sh->type = SHT_HASH;
+                       sh->flags = SHF_ALLOC;
+                       sh->entsize = 4;
+                       sh->addr = va;
+                       sh->off = seek(cout, 0, 1);
+                       hashoff = sh->off;
+                       sh->addr = startva + sh->off;
+                       /* temporary hack: 8 zeroes means 0 buckets, 0 chains */
+                       write(cout, zeroes, 8);
+                       sh->size = endelf() - sh->off;
+                       sh->addralign = 8;
+
+                       sh = newElf64SHdr(".got");
+                       sh->type = SHT_PROGBITS;
+                       sh->flags = SHF_ALLOC+SHF_WRITE;
+                       sh->entsize = 8;
+                       sh->addr = va;
+                       sh->off = startelf();
+                       sh->addr = startva + sh->off;
+                       sh->size = endelf() - sh->off;
+                       sh->addralign = 8;
+
+                       sh = newElf64SHdr(".got.plt");
+                       sh->type = SHT_PROGBITS;
+                       sh->flags = SHF_ALLOC+SHF_WRITE;
+                       sh->entsize = 8;
+                       sh->addr = va;
+                       sh->off = startelf();
+                       sh->addr = startva + sh->off;
+                       sh->size = endelf() - sh->off;
+                       sh->addralign = 8;
+
+                       /* +8 necessary for now to silence readelf addressing at end of hash section */
+                       ph->filesz = endelf() - ph->off +8;     /* dynamic section maps these shdrs' data */
+                       ph->memsz = ph->filesz;
+
+                       dynsh->type = SHT_DYNAMIC;
+                       dynsh->flags = SHF_ALLOC+SHF_WRITE;
+                       dynsh->entsize = 16;
+                       dynsh->addr = startva + dynsh->off;
+                       seek(cout, dynsh->off, 0);
+                       elf64writedynent(DT_HASH, startva+hashoff);
+                       elf64writedynent(DT_STRTAB, startva+ELF64FULLHDRSIZE-STRTABSIZE);
+                       elf64writedynent(DT_SYMTAB, startva);
+                       elf64writedynent(DT_RELA, startva);
+                       elf64writedynent(DT_RELASZ, 0); // size of the whole rela in bytes
+                       elf64writedynent(DT_RELAENT, ELF64RELASIZE);
+                       elf64writedynent(DT_STRSZ, STRTABSIZE);
+                       elf64writedynent(DT_SYMENT, 0);
+                       elf64writedynent(DT_REL, startva);
+                       elf64writedynent(DT_RELSZ, 0);
+                       elf64writedynent(DT_RELENT, ELF64RELSIZE);
+                       elf64writedynent(DT_NULL, 0);
+                       cflush();
+                       dynsh->size = seek(cout, 0, 1) - dynsh->off;
+                       dynsh->addralign = 8;
+
+                       /* dynamic section */
+                       ph = newElf64PHdr();
+                       ph->type = PT_DYNAMIC;
+                       ph->flags = PF_R + PF_W;
+                       ph->off = dynsh->off;
+                       ph->filesz = dynsh->size;
+                       ph->memsz = dynsh->size;
+                       ph->vaddr = startva + ph->off;
+                       ph->paddr = startva + ph->off;
+                       ph->align = 8;
+               }
+
                ph = newElf64PHdr();
-               ph->type = PT_LOAD;     
+               ph->type = PT_LOAD;
                ph->flags = PF_X+PF_R;
-               ph->vaddr = va;
-               ph->paddr = va;
-               ph->filesz = w;
-               ph->memsz = w;
+               ph->vaddr = va + ELF64RESERVE;
+               ph->paddr = va + ELF64RESERVE;
+               ph->off = ELF64RESERVE;
+               ph->filesz = w - ELF64RESERVE;
+               ph->memsz = w - ELF64RESERVE;
                ph->align = INITRND;
 
                fo = rnd(fo+w, INITRND);
@@ -462,11 +582,8 @@ asmb(void)
                ph->flags = PF_X+PF_W+PF_R;
                ph->align = 8;
 
-               sh = newElf64SHdr("");
-
-               stroffset = 1;  /* 0 means no name, so start at 1 */
-               fo = HEADR;
-               va = (INITTEXT & ~((vlong)INITRND - 1)) + HEADR;
+               fo = ELF64RESERVE;
+               va = startva + fo;
                w = textsize;
 
                sh = newElf64SHdr(".text");
@@ -501,38 +618,37 @@ asmb(void)
                sh->size = w;
                sh->addralign = 8;
 
-               w = STRTABSIZE;
+               if (!debug['s']) {
+                       fo = symo+8;
+                       w = symsize;
+
+                       sh = newElf64SHdr(".gosymtab");
+                       sh->type = SHT_PROGBITS;
+                       sh->off = fo;
+                       sh->size = w;
+                       sh->addralign = 1;
+                       sh->entsize = 24;
+
+                       fo += w;
+                       w = lcsize;
+
+                       sh = newElf64SHdr(".gopclntab");
+                       sh->type = SHT_PROGBITS;
+                       sh->off = fo;
+                       sh->size = w;
+                       sh->addralign = 1;
+                       sh->entsize = 24;
+               }
 
                sh = newElf64SHdr(".shstrtab");
                sh->type = SHT_STRTAB;
-               sh->off = fo;
-               sh->size = w;
-               sh->addralign = 1;
-
-               if (debug['s'])
-                       break;
-
-               fo = symo+8;
-               w = symsize;
-
-               sh = newElf64SHdr(".gosymtab");
-               sh->type = SHT_PROGBITS;
-               sh->off = fo;
-               sh->size = w;
+               sh->off = startelf();
+               sh->addr = sh->off + startva;
                sh->addralign = 1;
-               sh->entsize = 24;
-
-               fo += w;
-               w = lcsize;
-
-               sh = newElf64SHdr(".gopclntab");
-               sh->type = SHT_PROGBITS;
-               sh->off = fo;
-               sh->size = w;
-               sh->addralign = 1;
-               sh->entsize = 24;
+               elf64writestrtable();
+               sh->size = endelf() - sh->off;
 
-               // main header */
+               /* Main header */
                eh = getElf64Hdr();
                eh->ident[EI_MAG0] = '\177';
                eh->ident[EI_MAG1] = 'E';
@@ -547,6 +663,12 @@ asmb(void)
                eh->version = EV_CURRENT;
                eh->entry = entryvalue();
 
+               if (!debug['d']) {
+                       pph->filesz = eh->phnum * ELF64PHDRSIZE;
+                       pph->memsz = pph->filesz;
+               }
+
+               seek(cout, 0, 0);
                a = 0;
                a += elf64writehdr();
                a += elf64writephdrs();
@@ -556,11 +678,6 @@ asmb(void)
                }
                cflush();
 
-               /* string table */
-               seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0);
-               elf64writestrtable();
-               cflush();
-
                break;
        }
        cflush();
index 4a7cfc8347da727faa3d258ca6a2ced0e8ad9203..ea6f2c9b5c42d2741030612ebfc62d0332c405c0 100644 (file)
@@ -353,7 +353,6 @@ EXTERN      int     imports, nimports;
 EXTERN int     exports, nexports;
 EXTERN char*   EXPTAB;
 EXTERN Prog    undefp;
-EXTERN uint32  stroffset;
 EXTERN vlong   textstksiz;
 EXTERN vlong   textarg;
 
index 8538e064e4dc4e35160555829551790707f96791..66d1e7eedec4eb9fd28b9b933cffbdd60b6f4757 100644 (file)
@@ -197,7 +197,7 @@ main(int argc, char *argv[])
                        INITRND = 4096;
                break;
        case 7: /* elf64 executable */
-               HEADR = ELF64FULLHDRSIZE;
+               HEADR = ELF64RESERVE;
                if(INITTEXT == -1)
                        INITTEXT = (1<<22)+HEADR;
                if(INITDAT == -1)
index ea1a39b418090386b7a962b6ee8b42c0ffee0d42..dc9f4196b1d99be9aa9ee715cd8bdb8d60e71209 100644 (file)
@@ -8,20 +8,25 @@
 
 #define        NSECT   16
 static int     numstr;
+static int     stroffset;
 static Elf64Hdr        hdr;
 static Elf64PHdr       *phdr[NSECT];
 static Elf64SHdr       *shdr[NSECT];
 static char    *sname[NSECT];
 static char    *str[NSECT];
 
+/*
+ Initialize the global variable that describes the ELF header. It will be updated as
+ we write section and prog headers.
+ */
 void
 elf64init(void)
 {
-       hdr.phoff = ELF64HDRSIZE;
-       hdr.shoff = ELF64HDRSIZE;
-       hdr.ehsize = ELF64HDRSIZE;
-       hdr.phentsize = ELF64PHDRSIZE;
-       hdr.shentsize = ELF64SHDRSIZE;
+       hdr.phoff = ELF64HDRSIZE;       /* Must be be ELF64HDRSIZE: first PHdr must follow ELF header */
+       hdr.shoff = ELF64HDRSIZE;       /* Will move as we add PHeaders */
+       hdr.ehsize = ELF64HDRSIZE;      /* Must be ELF64HDRSIZE */
+       hdr.phentsize = ELF64PHDRSIZE;  /* Must be ELF64PHDRSIZE */
+       hdr.shentsize = ELF64SHDRSIZE;  /* Must be ELF64SHDRSIZE */
 }
 
 void
@@ -168,3 +173,57 @@ elf64writehdr()
        WPUT(hdr.shstrndx);
        return ELF64HDRSIZE;
 }
+
+/* Taken directly from the definition document for ELF64 */
+uint32
+elf64_hash(uchar *name)
+{
+       unsigned long h = 0, g;
+       while (*name) {
+               h = (h << 4) + *name++;
+               if (g = h & 0xf0000000)
+                       h ^= g >> 24;
+               h &= 0x0fffffff;
+       }
+       return h;
+}
+
+void
+elf64writedynent(int tag, uint64 val)
+{
+       VPUT(tag);
+       VPUT(val);
+}
+
+/* Where to write the next piece of data attached to an SHeader */
+uint64 elfaddr = ELF64FULLHDRSIZE;
+
+/* Mark a start location in the SHeader data */
+uint64
+startelf(void)
+{
+       seek(cout, elfaddr, 0);
+       return elfaddr;
+}
+
+/* Mark the end of a location in the SHeader data */
+uint64
+endelf(void)
+{
+       uint64 p;
+
+       cflush();
+       p = seek(cout, 0, 1);
+       if (p < elfaddr) {
+               diag("endelf before elfaddr");
+       }
+       if ((p & 7) != 0) {
+               p = (p + 7) & ~7LL;
+               seek(cout, p, 0);
+       }
+       elfaddr = p;
+       if (p > ELF64RESERVE) {
+               diag("endelf overflows reserve %lld\n", p);
+       }
+       return elfaddr;
+}
index f42ae9425202ccc617a717edc1289bde6ddb1d46..55d0ca3098c6a6e2735231a1092d92857e34329c 100644 (file)
@@ -121,6 +121,7 @@ struct Elf64PHdr
 #define        PT_DYNAMIC      2       /* Dynamic linking tables */
 #define        PT_INTERP       3       /* Program interpreter path name */
 #define        PT_NOTE         4       /* Note sections */
+#define        PT_PHDR         6       /* Program header table */
 
 /* P flags */
 #define        PF_X    0x1     /* Execute permission */
@@ -169,6 +170,103 @@ struct Elf64SHdr
 #define        SHF_MASKOS      0x0F000000      /* Environment-specific use */
 #define        SHF_MASKPROC    0xF0000000      /* Processor-specific use */
 
+
+typedef struct Elf64Dyn Elf64Dyn;
+struct Elf64Dyn
+{
+       Elf64_Sxword d_tag;
+       union {
+               Elf64_Xword d_val;
+               Elf64_Addr d_ptr;
+       } d_un;
+};
+
+/* Dyn table entries */
+#define        DT_NULL         0       /* ignored: Marks the end of the dynamic array */
+#define        DT_NEEDED       1       /* d_val: The string table offset of the name of
+                                  a needed library. */
+#define        DT_PLTRELSZ     2       /* d_val: Total size, in bytes, of the relocation
+                                  entries associated with  the procedure linkage table. */
+#define        DT_PLTGOT       3       /* d_ptr: Contains an address associated with the linkage
+                                  table. The specific meaning of this field is
+                                  processor-dependent. */
+#define        DT_HASH         4       /* d_ptr: Address of the symbol hash table. */
+#define        DT_STRTAB       5       /* d_ptr: Address of the dynamic string table. */
+#define        DT_SYMTAB       6       /* d_ptr: Address of the dynamic symbol table. */
+#define        DT_RELA         7       /* d_ptr Address of a relocation table with Elf64_Rela
+                                  entries. */
+#define        DT_RELASZ       8       /* d_val: Total size, in bytes, of the DT_RELA relocation
+                                  table. */
+#define        DT_RELAENT      9       /* d_val: Size, in bytes, of each DT_RELA relocation
+                                  entry. */
+#define        DT_STRSZ        10      /* d_val: Total size, in bytes, of the string table. */
+#define        DT_SYMENT       11      /* d_val: Size, in bytes, of each symbol table entry. */
+#define        DT_INIT         12      /* d_ptr Address of the initialization function. */
+#define        DT_FINI         13      /* d_ptr Address of the termination function. */
+#define        DT_SONAME       14      /* d_val The string table offset of the name of this
+                                  shared object. */
+#define        DT_RPATH        15      /* d_val The string table offset of a shared library
+                                  search path string. */
+#define        DT_SYMBOLIC     16      /* ignored The presence of this dynamic table entry
+                                  modifies the symbol resolution algorithm for references
+                                  within the library. Symbols defined within the library
+                                  are used to resolve references before the dynamic
+                                  linker searches the usual search path. */
+#define        DT_REL          17      /* d_ptr Address of a relocation table with Elf64_Rel
+                                  entries. */
+#define        DT_RELSZ        18      /* d_val Total size, in bytes, of the DT_REL relocation
+                                  table. */
+#define        DT_RELENT       19      /* d_val Size, in bytes, of each DT_REL relocation
+                                  entry. */
+#define        DT_PLTREL       20      /* d_val Type of relocation entry used for the procedure
+                                  linkage table. The d_val member contains either DT_REL
+                                  or DT_RELA. */
+#define        DT_DEBUG        21      /* d_ptr Reserved for debugger use. */
+#define        DT_TEXTREL      22      /* ignored The presence of this dynamic table entry
+                                  signals that the relocation table contains relocations
+                                  for a non-writable segment. */
+#define        DT_JMPREL       23      /* d_ptr Address of the relocations associated with the
+                                  procedure linkage table. */
+#define        DT_BIND_NOW     24      /* ignored The presence of this dynamic table entry
+                                  signals that the dynamic loader should process all
+                                  relocations for this object before transferring
+                                  control to the program. */
+#define        DT_INIT_ARRAY   25      /* d_ptr Pointer to an array of pointers to initialization
+                                  functions. */
+#define        DT_FINI_ARRAY   26      /* d_ptr Pointer to an array of pointers to termination
+                                  functions. */
+#define        DT_INIT_ARRAYSZ 27      /* d_val Size, in bytes, of the array of initialization
+                                  functions. */
+#define        DT_FINI_ARRAYSZ 28      /* d_val Size, in bytes, of the array of termination
+                                  functions. */
+#define        DT_LOOS 0x60000000      /* Defines a range of dynamic table tags that are reserved
+                                  for environment-specific use. */
+#define        DT_HIOS         0x6FFFFFFF
+#define        DT_LOPROC       0x70000000      /* Defines a range of dynamic table tags that are
+                                          reserved for processor-specific use. */
+#define        DT_HIPROC       0x7FFFFFFF
+
+typedef struct Elf64_Rel Elf64_Rel;
+struct Elf64_Rel
+{
+       Elf64_Addr r_offset;    /* Address of reference */
+       Elf64_Xword r_info;     /* Symbol index and type of relocation */
+};
+#define ELF64RELSIZE 8
+
+typedef struct Elf64_Rela Elf64_Rela;
+struct Elf64_Rela
+{
+       Elf64_Addr r_offset;    /* Address of reference */
+       Elf64_Xword r_info;     /* Symbol index and type of relocation */
+       Elf64_Sxword r_addend;  /* Constant part of expression */
+};
+#define ELF64RELASIZE 24
+
+#define        ELF64_R_SYM(i)  ((i) >> 32)
+#define        ELF64_R_TYPE(i) ((i) & 0xffffffffL)
+#define        ELF64_R_INFO(s, t)      (((s) << 32) + ((t) & 0xffffffffL))
+
 void   elf64init(void);
 Elf64Hdr       *getElf64Hdr();
 Elf64SHdr      *newElf64SHdr(char*);
@@ -177,10 +275,17 @@ uint32    elf64writehdr(void);
 uint32 elf64writephdrs(void);
 uint32 elf64writeshdrs(void);
 void   elf64writestrtable(void);
-
+void   elf64writedynent(int, uint64);
+uint32 elf64_hash(uchar*);
+uint64 startelf(void);
+uint64 endelf(void);
 extern int     nume64phdr;
 extern int     nume64shdr;
 
 #define        STRTABSIZE      256
-/* Amount of space to reserve at the start of the file; may waste some */
+/* Amount of space available for Header, PHeaders and SHeaders */
 #define        ELF64FULLHDRSIZE        2048
+/* Space reserved after ELF64FULLHEADERSIZE for dynamic info */
+#define        ELFDYNAMICSIZE  256
+/* Total amount of ELF space to reserve at the start of the file; may waste some */
+#define        ELF64RESERVE    4096