2009-07-17 15:32:37 -06:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// Support for 64-bit Elf binaries
|
|
|
|
|
|
|
|
#include "../ld/elf64.h"
|
|
|
|
|
2009-07-17 17:34:58 -06:00
|
|
|
#define NSECT 16
|
2009-07-20 14:19:47 -06:00
|
|
|
static int numstr;
|
2009-07-21 16:10:47 -06:00
|
|
|
static int stroffset;
|
2009-07-20 11:08:48 -06:00
|
|
|
static Elf64Hdr hdr;
|
2009-07-17 17:34:58 -06:00
|
|
|
static Elf64PHdr *phdr[NSECT];
|
|
|
|
static Elf64SHdr *shdr[NSECT];
|
|
|
|
static char *sname[NSECT];
|
2009-08-20 17:09:38 -06:00
|
|
|
static char *str[20];
|
2009-07-17 17:34:58 -06:00
|
|
|
|
2009-07-21 16:10:47 -06:00
|
|
|
/*
|
|
|
|
Initialize the global variable that describes the ELF header. It will be updated as
|
|
|
|
we write section and prog headers.
|
|
|
|
*/
|
2009-07-20 14:19:47 -06:00
|
|
|
void
|
|
|
|
elf64init(void)
|
|
|
|
{
|
2009-07-21 16:10:47 -06:00
|
|
|
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 */
|
2009-07-20 14:19:47 -06:00
|
|
|
}
|
|
|
|
|
2009-07-17 15:32:37 -06:00
|
|
|
void
|
2009-07-17 16:09:17 -06:00
|
|
|
elf64phdr(Elf64PHdr *e)
|
2009-07-17 15:32:37 -06:00
|
|
|
{
|
2009-07-20 11:08:48 -06:00
|
|
|
LPUT(e->type);
|
|
|
|
LPUT(e->flags);
|
|
|
|
VPUT(e->off);
|
|
|
|
VPUT(e->vaddr);
|
|
|
|
VPUT(e->paddr);
|
|
|
|
VPUT(e->filesz);
|
|
|
|
VPUT(e->memsz);
|
|
|
|
VPUT(e->align);
|
2009-07-17 15:32:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
elf64shdr(char *name, Elf64SHdr *e)
|
|
|
|
{
|
2009-07-20 11:08:48 -06:00
|
|
|
LPUT(e->name);
|
|
|
|
LPUT(e->type);
|
|
|
|
VPUT(e->flags);
|
|
|
|
VPUT(e->addr);
|
|
|
|
VPUT(e->off);
|
|
|
|
VPUT(e->size);
|
|
|
|
LPUT(e->link);
|
|
|
|
LPUT(e->info);
|
|
|
|
VPUT(e->addralign);
|
|
|
|
VPUT(e->entsize);
|
2009-07-17 15:32:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
putelf64strtab(char* name)
|
|
|
|
{
|
|
|
|
int w;
|
|
|
|
|
|
|
|
w = strlen(name)+1;
|
|
|
|
strnput(name, w);
|
|
|
|
return w;
|
|
|
|
}
|
|
|
|
|
2009-07-17 17:34:58 -06:00
|
|
|
void
|
|
|
|
elf64writestrtable(void)
|
2009-07-17 15:32:37 -06:00
|
|
|
{
|
2009-07-17 17:34:58 -06:00
|
|
|
int i;
|
2009-07-20 14:19:47 -06:00
|
|
|
uint32 size;
|
2009-07-17 15:32:37 -06:00
|
|
|
|
|
|
|
size = 0;
|
2009-07-20 14:19:47 -06:00
|
|
|
for (i = 0; i < numstr; i++)
|
2009-07-17 17:34:58 -06:00
|
|
|
size += putelf64strtab(str[i]);
|
|
|
|
if (size > STRTABSIZE)
|
|
|
|
diag("elf64 string table overflow");
|
2009-07-17 15:32:37 -06:00
|
|
|
}
|
|
|
|
|
2009-08-20 17:09:38 -06:00
|
|
|
uint32
|
|
|
|
elf64addstr(char *name)
|
2009-07-17 17:34:58 -06:00
|
|
|
{
|
2009-08-20 17:09:38 -06:00
|
|
|
int r;
|
|
|
|
|
|
|
|
if (numstr >= nelem(str)) {
|
2009-07-17 17:34:58 -06:00
|
|
|
diag("too many elf strings");
|
2009-08-20 17:09:38 -06:00
|
|
|
return 0;
|
2009-07-17 17:34:58 -06:00
|
|
|
}
|
2009-07-20 14:19:47 -06:00
|
|
|
str[numstr++] = strdup(name);
|
2009-08-20 17:09:38 -06:00
|
|
|
r = stroffset;
|
2009-07-17 17:34:58 -06:00
|
|
|
stroffset += strlen(name)+1;
|
2009-08-20 17:09:38 -06:00
|
|
|
return r;
|
2009-07-17 17:34:58 -06:00
|
|
|
}
|
2009-07-17 15:32:37 -06:00
|
|
|
|
|
|
|
uint32
|
2009-07-17 17:34:58 -06:00
|
|
|
elf64writeshdrs(void)
|
2009-07-17 15:32:37 -06:00
|
|
|
{
|
2009-07-17 17:34:58 -06:00
|
|
|
int i;
|
2009-07-17 15:32:37 -06:00
|
|
|
|
2009-07-20 11:08:48 -06:00
|
|
|
for (i = 0; i < hdr.shnum; i++)
|
2009-07-17 17:34:58 -06:00
|
|
|
elf64shdr(sname[i], shdr[i]);
|
2009-07-20 14:19:47 -06:00
|
|
|
return hdr.shnum * ELF64SHDRSIZE;
|
2009-07-17 15:32:37 -06:00
|
|
|
}
|
|
|
|
|
2009-07-20 14:19:47 -06:00
|
|
|
uint32
|
2009-07-17 17:34:58 -06:00
|
|
|
elf64writephdrs(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2009-07-20 11:08:48 -06:00
|
|
|
for (i = 0; i < hdr.phnum; i++)
|
2009-07-17 17:34:58 -06:00
|
|
|
elf64phdr(phdr[i]);
|
2009-07-20 14:19:47 -06:00
|
|
|
return hdr.phnum * ELF64PHDRSIZE;
|
2009-07-17 17:34:58 -06:00
|
|
|
}
|
2009-07-17 16:09:17 -06:00
|
|
|
|
|
|
|
Elf64PHdr*
|
2009-07-17 17:34:58 -06:00
|
|
|
newElf64PHdr(void)
|
2009-07-17 16:09:17 -06:00
|
|
|
{
|
|
|
|
Elf64PHdr *e;
|
|
|
|
|
|
|
|
e = malloc(sizeof *e);
|
|
|
|
memset(e, 0, sizeof *e);
|
2009-07-20 11:08:48 -06:00
|
|
|
if (hdr.phnum >= NSECT)
|
2009-07-17 17:34:58 -06:00
|
|
|
diag("too many phdrs");
|
|
|
|
else
|
2009-07-20 11:08:48 -06:00
|
|
|
phdr[hdr.phnum++] = e;
|
2009-07-20 14:19:47 -06:00
|
|
|
hdr.shoff += ELF64PHDRSIZE;
|
2009-07-17 16:09:17 -06:00
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
2009-07-17 17:34:58 -06:00
|
|
|
Elf64SHdr*
|
|
|
|
newElf64SHdr(char *name)
|
|
|
|
{
|
|
|
|
Elf64SHdr *e;
|
|
|
|
|
2009-07-20 11:08:48 -06:00
|
|
|
if (strcmp(name, ".shstrtab") == 0)
|
|
|
|
hdr.shstrndx = hdr.shnum;
|
2009-07-17 17:34:58 -06:00
|
|
|
e = malloc(sizeof *e);
|
|
|
|
memset(e, 0, sizeof *e);
|
2009-08-20 17:09:38 -06:00
|
|
|
e->name = elf64addstr(name);
|
2009-07-20 11:08:48 -06:00
|
|
|
if (hdr.shnum >= NSECT) {
|
2009-07-17 17:34:58 -06:00
|
|
|
diag("too many shdrs");
|
|
|
|
} else {
|
2009-07-20 11:08:48 -06:00
|
|
|
shdr[hdr.shnum++] = e;
|
2009-07-17 17:34:58 -06:00
|
|
|
}
|
|
|
|
return e;
|
|
|
|
}
|
2009-07-20 11:08:48 -06:00
|
|
|
|
|
|
|
Elf64Hdr*
|
|
|
|
getElf64Hdr(void)
|
|
|
|
{
|
|
|
|
return &hdr;
|
|
|
|
}
|
|
|
|
|
2009-07-20 14:19:47 -06:00
|
|
|
uint32
|
2009-08-20 17:09:38 -06:00
|
|
|
elf64writehdr(void)
|
2009-07-20 11:08:48 -06:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < EI_NIDENT; i++)
|
|
|
|
cput(hdr.ident[i]);
|
|
|
|
WPUT(hdr.type);
|
|
|
|
WPUT(hdr.machine);
|
|
|
|
LPUT(hdr.version);
|
|
|
|
VPUT(hdr.entry);
|
|
|
|
VPUT(hdr.phoff);
|
|
|
|
VPUT(hdr.shoff);
|
|
|
|
LPUT(hdr.flags);
|
|
|
|
WPUT(hdr.ehsize);
|
|
|
|
WPUT(hdr.phentsize);
|
|
|
|
WPUT(hdr.phnum);
|
|
|
|
WPUT(hdr.shentsize);
|
|
|
|
WPUT(hdr.shnum);
|
|
|
|
WPUT(hdr.shstrndx);
|
2009-07-20 14:19:47 -06:00
|
|
|
return ELF64HDRSIZE;
|
2009-07-20 11:08:48 -06:00
|
|
|
}
|
2009-07-21 16:10:47 -06:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|