This source file includes following definitions.
- elfinit
 
- elf64phdr
 
- elf32phdr
 
- elf64shdr
 
- elf32shdr
 
- elfwriteshdrs
 
- elfsetstring
 
- elfwritephdrs
 
- newElfPhdr
 
- newElfShdr
 
- getElfEhdr
 
- elf64writehdr
 
- elf32writehdr
 
- elfwritehdr
 
- elfhash
 
- elfwritedynent
 
- elfwritedynentsym
 
- elfwritedynentsymsize
 
- elfinterp
 
- elfwriteinterp
 
- elfnote
 
- elfwritenotehdr
 
- elfnetbsdsig
 
- elfwritenetbsdsig
 
- elfopenbsdsig
 
- elfwriteopenbsdsig
 
- addbuildinfo
 
- elfbuildinfo
 
- elfwritebuildinfo
 
- addelflib
 
- elfdynhash
 
- elfphload
 
- elfshname
 
- elfshalloc
 
- elfshbits
 
- elfshreloc
 
- elfrelocsect
 
- elfemitreloc
 
- doelf
 
- shsym
 
- phsh
 
- asmbelfsetup
 
- asmbelf
 
#include        "l.h"
#include        "lib.h"
#include        "../ld/elf.h"
#define NSECT   48
int     iself;
static  int     elf64;
static  ElfEhdr hdr;
static  ElfPhdr *phdr[NSECT];
static  ElfShdr *shdr[NSECT];
static  char    *interp;
typedef struct Elfstring Elfstring;
struct Elfstring
{
        char *s;
        int off;
};
static Elfstring elfstr[100];
static int nelfstr;
static char buildinfo[32];
void
elfinit(void)
{
        iself = 1;
        switch(thechar) {
        
        case '6':
                elf64 = 1;
                hdr.phoff = ELF64HDRSIZE;       
                hdr.shoff = ELF64HDRSIZE;       
                hdr.ehsize = ELF64HDRSIZE;      
                hdr.phentsize = ELF64PHDRSIZE;  
                hdr.shentsize = ELF64SHDRSIZE;  
                break;
        
        case '5':
                
                if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd)
                        hdr.flags = 0x5000002; 
                
        default:
                hdr.phoff = ELF32HDRSIZE;       
                hdr.shoff = ELF32HDRSIZE;       
                hdr.ehsize = ELF32HDRSIZE;      
                hdr.phentsize = ELF32PHDRSIZE;  
                hdr.shentsize = ELF32SHDRSIZE;  
        }
}
void
elf64phdr(ElfPhdr *e)
{
        LPUT(e->type);
        LPUT(e->flags);
        VPUT(e->off);
        VPUT(e->vaddr);
        VPUT(e->paddr);
        VPUT(e->filesz);
        VPUT(e->memsz);
        VPUT(e->align);
}
void
elf32phdr(ElfPhdr *e)
{
        int frag;
        
        if(e->type == PT_LOAD) {
                
                
                
                frag = e->vaddr&(e->align-1);
                e->off -= frag;
                e->vaddr -= frag;
                e->paddr -= frag;
                e->filesz += frag;
                e->memsz += frag;
        }
        LPUT(e->type);
        LPUT(e->off);
        LPUT(e->vaddr);
        LPUT(e->paddr);
        LPUT(e->filesz);
        LPUT(e->memsz);
        LPUT(e->flags);
        LPUT(e->align);
}
void
elf64shdr(ElfShdr *e)
{
        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);
}
void
elf32shdr(ElfShdr *e)
{
        LPUT(e->name);
        LPUT(e->type);
        LPUT(e->flags);
        LPUT(e->addr);
        LPUT(e->off);
        LPUT(e->size);
        LPUT(e->link);
        LPUT(e->info);
        LPUT(e->addralign);
        LPUT(e->entsize);
}
uint32
elfwriteshdrs(void)
{
        int i;
        if (elf64) {
                for (i = 0; i < hdr.shnum; i++)
                        elf64shdr(shdr[i]);
                return hdr.shnum * ELF64SHDRSIZE;
        }
        for (i = 0; i < hdr.shnum; i++)
                elf32shdr(shdr[i]);
        return hdr.shnum * ELF32SHDRSIZE;
}
void
elfsetstring(char *s, int off)
{
        if(nelfstr >= nelem(elfstr)) {
                diag("too many elf strings");
                errorexit();
        }
        elfstr[nelfstr].s = s;
        elfstr[nelfstr].off = off;
        nelfstr++;
}
uint32
elfwritephdrs(void)
{
        int i;
        if (elf64) {
                for (i = 0; i < hdr.phnum; i++)
                        elf64phdr(phdr[i]);
                return hdr.phnum * ELF64PHDRSIZE;
        }
        for (i = 0; i < hdr.phnum; i++)
                elf32phdr(phdr[i]);
        return hdr.phnum * ELF32PHDRSIZE;
}
ElfPhdr*
newElfPhdr(void)
{
        ElfPhdr *e;
        e = mal(sizeof *e);
        if (hdr.phnum >= NSECT)
                diag("too many phdrs");
        else
                phdr[hdr.phnum++] = e;
        if (elf64)
                hdr.shoff += ELF64PHDRSIZE;
        else
                hdr.shoff += ELF32PHDRSIZE;
        return e;
}
ElfShdr*
newElfShdr(vlong name)
{
        ElfShdr *e;
        e = mal(sizeof *e);
        e->name = name;
        e->shnum = hdr.shnum;
        if (hdr.shnum >= NSECT) {
                diag("too many shdrs");
        } else {
                shdr[hdr.shnum++] = e;
        }
        return e;
}
ElfEhdr*
getElfEhdr(void)
{
        return &hdr;
}
uint32
elf64writehdr(void)
{
        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);
        return ELF64HDRSIZE;
}
uint32
elf32writehdr(void)
{
        int i;
        for (i = 0; i < EI_NIDENT; i++)
                cput(hdr.ident[i]);
        WPUT(hdr.type);
        WPUT(hdr.machine);
        LPUT(hdr.version);
        LPUT(hdr.entry);
        LPUT(hdr.phoff);
        LPUT(hdr.shoff);
        LPUT(hdr.flags);
        WPUT(hdr.ehsize);
        WPUT(hdr.phentsize);
        WPUT(hdr.phnum);
        WPUT(hdr.shentsize);
        WPUT(hdr.shnum);
        WPUT(hdr.shstrndx);
        return ELF32HDRSIZE;
}
uint32
elfwritehdr(void)
{
        if(elf64)
                return elf64writehdr();
        return elf32writehdr();
}
uint32
elfhash(uchar *name)
{
        uint32 h = 0, g;
        while (*name) {
                h = (h << 4) + *name++;
                if (g = h & 0xf0000000)
                        h ^= g >> 24;
                h &= 0x0fffffff;
        }
        return h;
}
void
elfwritedynent(LSym *s, int tag, uint64 val)
{
        if(elf64) {
                adduint64(ctxt, s, tag);
                adduint64(ctxt, s, val);
        } else {
                adduint32(ctxt, s, tag);
                adduint32(ctxt, s, val);
        }
}
void
elfwritedynentsym(LSym *s, int tag, LSym *t)
{
        if(elf64)
                adduint64(ctxt, s, tag);
        else
                adduint32(ctxt, s, tag);
        addaddr(ctxt, s, t);
}
void
elfwritedynentsymsize(LSym *s, int tag, LSym *t)
{
        if(elf64)
                adduint64(ctxt, s, tag);
        else
                adduint32(ctxt, s, tag);
        addsize(ctxt, s, t);
}
int
elfinterp(ElfShdr *sh, uint64 startva, uint64 resoff, char *p)
{
        int n;
        interp = p;
        n = strlen(interp)+1;
        sh->addr = startva + resoff - n;
        sh->off = resoff - n;
        sh->size = n;
        return n;
}
int
elfwriteinterp(void)
{
        ElfShdr *sh;
        
        sh = elfshname(".interp");
        cseek(sh->off);
        cwrite(interp, sh->size);
        return sh->size;
}
int
elfnote(ElfShdr *sh, uint64 startva, uint64 resoff, int sz)
{
        uint64 n;
        n = sizeof(Elf_Note) + sz + resoff % 4;
        sh->type = SHT_NOTE;
        sh->flags = SHF_ALLOC;
        sh->addralign = 4;
        sh->addr = startva + resoff - n;
        sh->off = resoff - n;
        sh->size = n - resoff % 4;
        return n;
}
ElfShdr *
elfwritenotehdr(char *str, uint32 namesz, uint32 descsz, uint32 tag)
{
        ElfShdr *sh;
        
        sh = elfshname(str);
        
        cseek(sh->off);
        LPUT(namesz);
        LPUT(descsz);
        LPUT(tag);
        return sh;
}
#define ELF_NOTE_NETBSD_NAMESZ          7
#define ELF_NOTE_NETBSD_DESCSZ          4
#define ELF_NOTE_NETBSD_TAG             1
#define ELF_NOTE_NETBSD_NAME            "NetBSD\0\0"
#define ELF_NOTE_NETBSD_VERSION         599000000       
int
elfnetbsdsig(ElfShdr *sh, uint64 startva, uint64 resoff)
{
        int n;
        n = rnd(ELF_NOTE_NETBSD_NAMESZ, 4) + rnd(ELF_NOTE_NETBSD_DESCSZ, 4);
        return elfnote(sh, startva, resoff, n);
}
int
elfwritenetbsdsig(void)
{
        ElfShdr *sh;
        
        sh = elfwritenotehdr(".note.netbsd.ident", ELF_NOTE_NETBSD_NAMESZ, ELF_NOTE_NETBSD_DESCSZ, ELF_NOTE_NETBSD_TAG);
        if(sh == nil)
                return 0;
        
        cwrite(ELF_NOTE_NETBSD_NAME, ELF_NOTE_NETBSD_NAMESZ + 1);
        LPUT(ELF_NOTE_NETBSD_VERSION);
        return sh->size;
}
#define ELF_NOTE_OPENBSD_NAMESZ         8
#define ELF_NOTE_OPENBSD_DESCSZ         4
#define ELF_NOTE_OPENBSD_TAG            1
#define ELF_NOTE_OPENBSD_NAME           "OpenBSD\0"
#define ELF_NOTE_OPENBSD_VERSION        0
int
elfopenbsdsig(ElfShdr *sh, uint64 startva, uint64 resoff)
{
        int n;
        n = ELF_NOTE_OPENBSD_NAMESZ + ELF_NOTE_OPENBSD_DESCSZ;
        return elfnote(sh, startva, resoff, n);
}
int
elfwriteopenbsdsig(void)
{
        ElfShdr *sh;
        
        sh = elfwritenotehdr(".note.openbsd.ident", ELF_NOTE_OPENBSD_NAMESZ, ELF_NOTE_OPENBSD_DESCSZ, ELF_NOTE_OPENBSD_TAG);
        if(sh == nil)
                return 0;
        
        cwrite(ELF_NOTE_OPENBSD_NAME, ELF_NOTE_OPENBSD_NAMESZ);
        LPUT(ELF_NOTE_OPENBSD_VERSION);
        return sh->size;
}
void
addbuildinfo(char *val)
{
        char *ov;
        int i, b, j;
        if(val[0] != '0' || val[1] != 'x') {
                fprint(2, "%s: -B argument must start with 0x: %s\n", argv0, val);
                exits("usage");
        }
        ov = val;
        val += 2;
        i = 0;
        while(*val != '\0') {
                if(val[1] == '\0') {
                        fprint(2, "%s: -B argument must have even number of digits: %s\n", argv0, ov);
                        exits("usage");
                }
                b = 0;
                for(j = 0; j < 2; j++, val++) {
                        b *= 16;
                        if(*val >= '0' && *val <= '9')
                                b += *val - '0';
                        else if(*val >= 'a' && *val <= 'f')
                                b += *val - 'a' + 10;
                        else if(*val >= 'A' && *val <= 'F')
                                b += *val - 'A' + 10;
                        else {
                                fprint(2, "%s: -B argument contains invalid hex digit %c: %s\n", argv0, *val, ov);
                                exits("usage");
                        }
                }
                if(i >= nelem(buildinfo)) {
                        fprint(2, "%s: -B option too long (max %d digits): %s\n", argv0, (int)nelem(buildinfo), ov);
                        exits("usage");
                }
                buildinfo[i++] = b;
        }
        buildinfolen = i;
}
#define ELF_NOTE_BUILDINFO_NAMESZ       4
#define ELF_NOTE_BUILDINFO_TAG          3
#define ELF_NOTE_BUILDINFO_NAME         "GNU\0"
int
elfbuildinfo(ElfShdr *sh, uint64 startva, uint64 resoff)
{
        int n;
        n = ELF_NOTE_BUILDINFO_NAMESZ + rnd(buildinfolen, 4);
        return elfnote(sh, startva, resoff, n);
}
int
elfwritebuildinfo(void)
{
        ElfShdr *sh;
        sh = elfwritenotehdr(".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, buildinfolen, ELF_NOTE_BUILDINFO_TAG);
        if(sh == nil)
                return 0;
        cwrite(ELF_NOTE_BUILDINFO_NAME, ELF_NOTE_BUILDINFO_NAMESZ);
        cwrite(buildinfo, buildinfolen);
        cwrite("\0\0\0", rnd(buildinfolen, 4) - buildinfolen);
        return sh->size;
}
extern int nelfsym;
int elfverneed;
typedef struct Elfaux Elfaux;
typedef struct Elflib Elflib;
struct Elflib
{
        Elflib *next;
        Elfaux *aux;
        char *file;
};
struct Elfaux
{
        Elfaux *next;
        int num;
        char *vers;
};
Elfaux*
addelflib(Elflib **list, char *file, char *vers)
{
        Elflib *lib;
        Elfaux *aux;
        
        for(lib=*list; lib; lib=lib->next)
                if(strcmp(lib->file, file) == 0)
                        goto havelib;
        lib = mal(sizeof *lib);
        lib->next = *list;
        lib->file = file;
        *list = lib;
havelib:
        for(aux=lib->aux; aux; aux=aux->next)
                if(strcmp(aux->vers, vers) == 0)
                        goto haveaux;
        aux = mal(sizeof *aux);
        aux->next = lib->aux;
        aux->vers = vers;
        lib->aux = aux;
haveaux:
        return aux;
}
void
elfdynhash(void)
{
        LSym *s, *sy, *dynstr;
        int i, j, nbucket, b, nfile;
        uint32 hc, *chain, *buckets;
        int nsym;
        char *name;
        Elfaux **need;
        Elflib *needlib;
        Elflib *l;
        Elfaux *x;
        
        if(!iself)
                return;
        nsym = nelfsym;
        s = linklookup(ctxt, ".hash", 0);
        s->type = SELFROSECT;
        s->reachable = 1;
        i = nsym;
        nbucket = 1;
        while(i > 0) {
                ++nbucket;
                i >>= 1;
        }
        needlib = nil;
        need = malloc(nsym * sizeof need[0]);
        chain = malloc(nsym * sizeof chain[0]);
        buckets = malloc(nbucket * sizeof buckets[0]);
        if(need == nil || chain == nil || buckets == nil) {
                ctxt->cursym = nil;
                diag("out of memory");
                errorexit();
        }
        memset(need, 0, nsym * sizeof need[0]);
        memset(chain, 0, nsym * sizeof chain[0]);
        memset(buckets, 0, nbucket * sizeof buckets[0]);
        for(sy=ctxt->allsym; sy!=S; sy=sy->allsym) {
                if (sy->dynid <= 0)
                        continue;
                if(sy->dynimpvers)
                        need[sy->dynid] = addelflib(&needlib, sy->dynimplib, sy->dynimpvers);
                name = sy->extname;
                hc = elfhash((uchar*)name);
                b = hc % nbucket;
                chain[sy->dynid] = buckets[b];
                buckets[b] = sy->dynid;
        }
        adduint32(ctxt, s, nbucket);
        adduint32(ctxt, s, nsym);
        for(i = 0; i<nbucket; i++)
                adduint32(ctxt, s, buckets[i]);
        for(i = 0; i<nsym; i++)
                adduint32(ctxt, s, chain[i]);
        free(chain);
        free(buckets);
        
        
        dynstr = linklookup(ctxt, ".dynstr", 0);
        s = linklookup(ctxt, ".gnu.version_r", 0);
        i = 2;
        nfile = 0;
        for(l=needlib; l; l=l->next) {
                nfile++;
                
                adduint16(ctxt, s, 1);  
                j = 0;
                for(x=l->aux; x; x=x->next)
                        j++;
                adduint16(ctxt, s, j);  
                adduint32(ctxt, s, addstring(dynstr, l->file));  
                adduint32(ctxt, s, 16);  
                if(l->next)
                        adduint32(ctxt, s, 16+j*16);  
                else
                        adduint32(ctxt, s, 0);
                
                for(x=l->aux; x; x=x->next) {
                        x->num = i++;
                        
                        adduint32(ctxt, s, elfhash((uchar*)x->vers));  
                        adduint16(ctxt, s, 0);  
                        adduint16(ctxt, s, x->num);  
                        adduint32(ctxt, s, addstring(dynstr, x->vers));  
                        if(x->next)
                                adduint32(ctxt, s, 16);  
                        else
                                adduint32(ctxt, s, 0);
                }
        }
        
        s = linklookup(ctxt, ".gnu.version", 0);
        for(i=0; i<nsym; i++) {
                if(i == 0)
                        adduint16(ctxt, s, 0); 
                else if(need[i] == nil)
                        adduint16(ctxt, s, 1); 
                else
                        adduint16(ctxt, s, need[i]->num);
        }
        free(need);
        s = linklookup(ctxt, ".dynamic", 0);
        elfverneed = nfile;
        if(elfverneed) {
                elfwritedynentsym(s, DT_VERNEED, linklookup(ctxt, ".gnu.version_r", 0));
                elfwritedynent(s, DT_VERNEEDNUM, nfile);
                elfwritedynentsym(s, DT_VERSYM, linklookup(ctxt, ".gnu.version", 0));
        }
        if(thechar == '6') {
                sy = linklookup(ctxt, ".rela.plt", 0);
                if(sy->size > 0) {
                        elfwritedynent(s, DT_PLTREL, DT_RELA);
                        elfwritedynentsymsize(s, DT_PLTRELSZ, sy);
                        elfwritedynentsym(s, DT_JMPREL, sy);
                }
        } else {
                sy = linklookup(ctxt, ".rel.plt", 0);
                if(sy->size > 0) {
                        elfwritedynent(s, DT_PLTREL, DT_REL);
                        elfwritedynentsymsize(s, DT_PLTRELSZ, sy);
                        elfwritedynentsym(s, DT_JMPREL, sy);
                }
        }
        elfwritedynent(s, DT_NULL, 0);
}
ElfPhdr*
elfphload(Segment *seg)
{
        ElfPhdr *ph;
        
        ph = newElfPhdr();
        ph->type = PT_LOAD;
        if(seg->rwx & 4)
                ph->flags |= PF_R;
        if(seg->rwx & 2)
                ph->flags |= PF_W;
        if(seg->rwx & 1)
                ph->flags |= PF_X;
        ph->vaddr = seg->vaddr;
        ph->paddr = seg->vaddr;
        ph->memsz = seg->len;
        ph->off = seg->fileoff;
        ph->filesz = seg->filelen;
        ph->align = INITRND;
        
        return ph;
}
ElfShdr*
elfshname(char *name)
{
        int i, off;
        ElfShdr *sh;
        
        for(i=0; i<nelfstr; i++) {
                if(strcmp(name, elfstr[i].s) == 0) {
                        off = elfstr[i].off;
                        goto found;
                }
        }
        diag("cannot find elf name %s", name);
        errorexit();
        return nil;
found:
        for(i=0; i<hdr.shnum; i++) {
                sh = shdr[i];
                if(sh->name == off)
                        return sh;
        }
        
        sh = newElfShdr(off);
        return sh;
}
ElfShdr*
elfshalloc(Section *sect)
{
        ElfShdr *sh;
        
        sh = elfshname(sect->name);
        sect->elfsect = sh;
        return sh;
}
ElfShdr*
elfshbits(Section *sect)
{
        ElfShdr *sh;
        
        sh = elfshalloc(sect);
        if(sh->type > 0)
                return sh;
        if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen)
                sh->type = SHT_PROGBITS;
        else
                sh->type = SHT_NOBITS;
        sh->flags = SHF_ALLOC;
        if(sect->rwx & 1)
                sh->flags |= SHF_EXECINSTR;
        if(sect->rwx & 2)
                sh->flags |= SHF_WRITE;
        if(strcmp(sect->name, ".tbss") == 0) {
                sh->flags |= SHF_TLS;
                sh->type = SHT_NOBITS;
        }
        if(linkmode != LinkExternal)
                sh->addr = sect->vaddr;
        sh->addralign = sect->align;
        sh->size = sect->len;
        sh->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr;
        return sh;
}
ElfShdr*
elfshreloc(Section *sect)
{
        int typ;
        ElfShdr *sh;
        char *prefix;
        char buf[100];
        
        
        
        if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen)
                return nil;
        if(strcmp(sect->name, ".shstrtab") == 0 || strcmp(sect->name, ".tbss") == 0)
                return nil;
        if(thechar == '6') {
                prefix = ".rela";
                typ = SHT_RELA;
        } else {
                prefix = ".rel";
                typ = SHT_REL;
        }
        snprint(buf, sizeof buf, "%s%s", prefix, sect->name);
        sh = elfshname(buf);
        sh->type = typ;
        sh->entsize = RegSize*(2+(typ==SHT_RELA));
        sh->link = elfshname(".symtab")->shnum;
        sh->info = sect->elfsect->shnum;
        sh->off = sect->reloff;
        sh->size = sect->rellen;
        sh->addralign = RegSize;
        return sh;
}
void
elfrelocsect(Section *sect, LSym *first)
{
        LSym *sym;
        int32 eaddr;
        Reloc *r;
        
        
        if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen)
                return;
        if(strcmp(sect->name, ".shstrtab") == 0)
                return;
        sect->reloff = cpos();
        for(sym = first; sym != nil; sym = sym->next) {
                if(!sym->reachable)
                        continue;
                if(sym->value >= sect->vaddr)
                        break;
        }
        
        eaddr = sect->vaddr + sect->len;
        for(; sym != nil; sym = sym->next) {
                if(!sym->reachable)
                        continue;
                if(sym->value >= eaddr)
                        break;
                ctxt->cursym = sym;
                
                for(r = sym->r; r < sym->r+sym->nr; r++) {
                        if(r->done)
                                continue;
                        if(r->xsym == nil) {
                                diag("missing xsym in relocation");
                                continue;
                        }
                        if(r->xsym->elfsym == 0)
                                diag("reloc %d to non-elf symbol %s (outer=%s) %d", r->type, r->sym->name, r->xsym->name, r->sym->type);
                        if(elfreloc1(r, sym->value+r->off - sect->vaddr) < 0)
                                diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
                }
        }
                
        sect->rellen = cpos() - sect->reloff;
}       
        
void
elfemitreloc(void)
{
        Section *sect;
        while(cpos()&7)
                cput(0);
        elfrelocsect(segtext.sect, ctxt->textp);
        for(sect=segtext.sect->next; sect!=nil; sect=sect->next)
                elfrelocsect(sect, datap);      
        for(sect=segrodata.sect; sect!=nil; sect=sect->next)
                elfrelocsect(sect, datap);      
        for(sect=segdata.sect; sect!=nil; sect=sect->next)
                elfrelocsect(sect, datap);      
}
void
doelf(void)
{
        LSym *s, *shstrtab, *dynstr;
        if(!iself)
                return;
        
        shstrtab = linklookup(ctxt, ".shstrtab", 0);
        shstrtab->type = SELFROSECT;
        shstrtab->reachable = 1;
        addstring(shstrtab, "");
        addstring(shstrtab, ".text");
        addstring(shstrtab, ".noptrdata");
        addstring(shstrtab, ".data");
        addstring(shstrtab, ".bss");
        addstring(shstrtab, ".noptrbss");
        
        
        
        
        if(HEADTYPE != Hopenbsd)
        if(!debug['d'] || linkmode == LinkExternal)
                addstring(shstrtab, ".tbss");
        if(HEADTYPE == Hnetbsd)
                addstring(shstrtab, ".note.netbsd.ident");
        if(HEADTYPE == Hopenbsd)
                addstring(shstrtab, ".note.openbsd.ident");
        if(buildinfolen > 0)
                addstring(shstrtab, ".note.gnu.build-id");
        addstring(shstrtab, ".elfdata");
        addstring(shstrtab, ".rodata");
        addstring(shstrtab, ".typelink");
        addstring(shstrtab, ".gosymtab");
        addstring(shstrtab, ".gopclntab");
        
        if(linkmode == LinkExternal) {
                debug_s = debug['s'];
                debug['s'] = 0;
                debug['d'] = 1;
                if(thechar == '6') {
                        addstring(shstrtab, ".rela.text");
                        addstring(shstrtab, ".rela.rodata");
                        addstring(shstrtab, ".rela.typelink");
                        addstring(shstrtab, ".rela.gosymtab");
                        addstring(shstrtab, ".rela.gopclntab");
                        addstring(shstrtab, ".rela.noptrdata");
                        addstring(shstrtab, ".rela.data");
                } else {
                        addstring(shstrtab, ".rel.text");
                        addstring(shstrtab, ".rel.rodata");
                        addstring(shstrtab, ".rel.typelink");
                        addstring(shstrtab, ".rel.gosymtab");
                        addstring(shstrtab, ".rel.gopclntab");
                        addstring(shstrtab, ".rel.noptrdata");
                        addstring(shstrtab, ".rel.data");
                }
                
                addstring(shstrtab, ".note.GNU-stack");
        }
        if(flag_shared) {
                addstring(shstrtab, ".init_array");
                if(thechar == '6')
                        addstring(shstrtab, ".rela.init_array");
                else
                        addstring(shstrtab, ".rel.init_array");
        }
        if(!debug['s']) {
                addstring(shstrtab, ".symtab");
                addstring(shstrtab, ".strtab");
                dwarfaddshstrings(shstrtab);
        }
        addstring(shstrtab, ".shstrtab");
        if(!debug['d']) {       
                addstring(shstrtab, ".interp");
                addstring(shstrtab, ".hash");
                addstring(shstrtab, ".got");
                addstring(shstrtab, ".got.plt");
                addstring(shstrtab, ".dynamic");
                addstring(shstrtab, ".dynsym");
                addstring(shstrtab, ".dynstr");
                if(thechar == '6') {
                        addstring(shstrtab, ".rela");
                        addstring(shstrtab, ".rela.plt");
                } else {
                        addstring(shstrtab, ".rel");
                        addstring(shstrtab, ".rel.plt");
                }
                addstring(shstrtab, ".plt");
                addstring(shstrtab, ".gnu.version");
                addstring(shstrtab, ".gnu.version_r");
                
                s = linklookup(ctxt, ".dynsym", 0);
                s->type = SELFROSECT;
                s->reachable = 1;
                if(thechar == '6')
                        s->size += ELF64SYMSIZE;
                else
                        s->size += ELF32SYMSIZE;
                
                s = linklookup(ctxt, ".dynstr", 0);
                s->type = SELFROSECT;
                s->reachable = 1;
                if(s->size == 0)
                        addstring(s, "");
                dynstr = s;
                
                if(thechar == '6')
                        s = linklookup(ctxt, ".rela", 0);
                else
                        s = linklookup(ctxt, ".rel", 0);
                s->reachable = 1;
                s->type = SELFROSECT;
                
                s = linklookup(ctxt, ".got", 0);
                s->reachable = 1;
                s->type = SELFSECT; 
                
                s = linklookup(ctxt, ".hash", 0);
                s->reachable = 1;
                s->type = SELFROSECT;
                s = linklookup(ctxt, ".got.plt", 0);
                s->reachable = 1;
                s->type = SELFSECT; 
                s = linklookup(ctxt, ".plt", 0);
                s->reachable = 1;
                s->type = SELFRXSECT;
                
                elfsetupplt();
                
                if(thechar == '6')
                        s = linklookup(ctxt, ".rela.plt", 0);
                else
                        s = linklookup(ctxt, ".rel.plt", 0);
                s->reachable = 1;
                s->type = SELFROSECT;
                
                s = linklookup(ctxt, ".gnu.version", 0);
                s->reachable = 1;
                s->type = SELFROSECT;
                
                s = linklookup(ctxt, ".gnu.version_r", 0);
                s->reachable = 1;
                s->type = SELFROSECT;
                
                s = linklookup(ctxt, ".dynamic", 0);
                s->reachable = 1;
                s->type = SELFSECT; 
                
                elfwritedynentsym(s, DT_HASH, linklookup(ctxt, ".hash", 0));
                elfwritedynentsym(s, DT_SYMTAB, linklookup(ctxt, ".dynsym", 0));
                if(thechar == '6')
                        elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE);
                else
                        elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
                elfwritedynentsym(s, DT_STRTAB, linklookup(ctxt, ".dynstr", 0));
                elfwritedynentsymsize(s, DT_STRSZ, linklookup(ctxt, ".dynstr", 0));
                if(thechar == '6') {
                        elfwritedynentsym(s, DT_RELA, linklookup(ctxt, ".rela", 0));
                        elfwritedynentsymsize(s, DT_RELASZ, linklookup(ctxt, ".rela", 0));
                        elfwritedynent(s, DT_RELAENT, ELF64RELASIZE);
                } else {
                        elfwritedynentsym(s, DT_REL, linklookup(ctxt, ".rel", 0));
                        elfwritedynentsymsize(s, DT_RELSZ, linklookup(ctxt, ".rel", 0));
                        elfwritedynent(s, DT_RELENT, ELF32RELSIZE);
                }
                if(rpath)
                        elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
                
                elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".got.plt", 0));
                
                
                
                
                elfwritedynent(s, DT_DEBUG, 0);
                
        }
}
void
shsym(ElfShdr *sh, LSym *s)
{
        vlong addr;
        addr = symaddr(s);
        if(sh->flags&SHF_ALLOC)
                sh->addr = addr;
        sh->off = datoff(addr);
        sh->size = s->size;
}
void
phsh(ElfPhdr *ph, ElfShdr *sh)
{
        ph->vaddr = sh->addr;
        ph->paddr = ph->vaddr;
        ph->off = sh->off;
        ph->filesz = sh->size;
        ph->memsz = sh->size;
        ph->align = sh->addralign;
}
void
asmbelfsetup(void)
{
        Section *sect;
        
        elfshname("");
        
        for(sect=segtext.sect; sect!=nil; sect=sect->next)
                elfshalloc(sect);
        for(sect=segrodata.sect; sect!=nil; sect=sect->next)
                elfshalloc(sect);
        for(sect=segdata.sect; sect!=nil; sect=sect->next)
                elfshalloc(sect);
}
void
asmbelf(vlong symo)
{
        vlong a, o;
        vlong startva, resoff;
        ElfEhdr *eh;
        ElfPhdr *ph, *pph, *pnote;
        ElfShdr *sh;
        Section *sect;
        eh = getElfEhdr();
        switch(thechar) {
        default:
                diag("unknown architecture in asmbelf");
                errorexit();
        case '5':
                eh->machine = EM_ARM;
                break;
        case '6':
                eh->machine = EM_X86_64;
                break;
        case '8':
                eh->machine = EM_386;
                break;
        }
        startva = INITTEXT - HEADR;
        resoff = ELFRESERVE;
        
        pph = nil;
        if(linkmode == LinkExternal) {
                
                eh->phoff = 0;
                eh->phentsize = 0;
                goto elfobj;
        }
        
        pph = newElfPhdr();
        pph->type = PT_PHDR;
        pph->flags = PF_R;
        pph->off = eh->ehsize;
        pph->vaddr = INITTEXT - HEADR + pph->off;
        pph->paddr = INITTEXT - HEADR + pph->off;
        pph->align = INITRND;
        
        if(HEADTYPE != Hnacl) {
                o = segtext.vaddr - pph->vaddr;
                segtext.vaddr -= o;
                segtext.len += o;
                o = segtext.fileoff - pph->off;
                segtext.fileoff -= o;
                segtext.filelen += o;
        }
        if(!debug['d']) {
                
                sh = elfshname(".interp");
                sh->type = SHT_PROGBITS;
                sh->flags = SHF_ALLOC;
                sh->addralign = 1;
                if(interpreter == nil) {
                        switch(HEADTYPE) {
                        case Hlinux:
                                interpreter = linuxdynld;
                                break;
                        case Hfreebsd:
                                interpreter = freebsddynld;
                                break;
                        case Hnetbsd:
                                interpreter = netbsddynld;
                                break;
                        case Hopenbsd:
                                interpreter = openbsddynld;
                                break;
                        case Hdragonfly:
                                interpreter = dragonflydynld;
                                break;
                        case Hsolaris:
                                interpreter = solarisdynld;
                                break;
                        }
                }
                resoff -= elfinterp(sh, startva, resoff, interpreter);
                ph = newElfPhdr();
                ph->type = PT_INTERP;
                ph->flags = PF_R;
                phsh(ph, sh);
        }
        pnote = nil;
        if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) {
                sh = nil;
                switch(HEADTYPE) {
                case Hnetbsd:
                        sh = elfshname(".note.netbsd.ident");
                        resoff -= elfnetbsdsig(sh, startva, resoff);
                        break;
                case Hopenbsd:
                        sh = elfshname(".note.openbsd.ident");
                        resoff -= elfopenbsdsig(sh, startva, resoff);
                        break;
                }
                pnote = newElfPhdr();
                pnote->type = PT_NOTE;
                pnote->flags = PF_R;
                phsh(pnote, sh);
        }
        if(buildinfolen > 0) {
                sh = elfshname(".note.gnu.build-id");
                resoff -= elfbuildinfo(sh, startva, resoff);
                if(pnote == nil) {
                        pnote = newElfPhdr();
                        pnote->type = PT_NOTE;
                        pnote->flags = PF_R;
                }
                phsh(pnote, sh);
        }
        
        USED(resoff);
        elfphload(&segtext);
        if(segrodata.sect != nil)
                elfphload(&segrodata);
        elfphload(&segdata);
        
        if(!debug['d']) {       
                sh = elfshname(".dynsym");
                sh->type = SHT_DYNSYM;
                sh->flags = SHF_ALLOC;
                if(elf64)
                        sh->entsize = ELF64SYMSIZE;
                else
                        sh->entsize = ELF32SYMSIZE;
                sh->addralign = RegSize;
                sh->link = elfshname(".dynstr")->shnum;
                
                shsym(sh, linklookup(ctxt, ".dynsym", 0));
                sh = elfshname(".dynstr");
                sh->type = SHT_STRTAB;
                sh->flags = SHF_ALLOC;
                sh->addralign = 1;
                shsym(sh, linklookup(ctxt, ".dynstr", 0));
                if(elfverneed) {
                        sh = elfshname(".gnu.version");
                        sh->type = SHT_GNU_VERSYM;
                        sh->flags = SHF_ALLOC;
                        sh->addralign = 2;
                        sh->link = elfshname(".dynsym")->shnum;
                        sh->entsize = 2;
                        shsym(sh, linklookup(ctxt, ".gnu.version", 0));
                        
                        sh = elfshname(".gnu.version_r");
                        sh->type = SHT_GNU_VERNEED;
                        sh->flags = SHF_ALLOC;
                        sh->addralign = RegSize;
                        sh->info = elfverneed;
                        sh->link = elfshname(".dynstr")->shnum;
                        shsym(sh, linklookup(ctxt, ".gnu.version_r", 0));
                }
                switch(eh->machine) {
                case EM_X86_64:
                        sh = elfshname(".rela.plt");
                        sh->type = SHT_RELA;
                        sh->flags = SHF_ALLOC;
                        sh->entsize = ELF64RELASIZE;
                        sh->addralign = RegSize;
                        sh->link = elfshname(".dynsym")->shnum;
                        sh->info = elfshname(".plt")->shnum;
                        shsym(sh, linklookup(ctxt, ".rela.plt", 0));
                        sh = elfshname(".rela");
                        sh->type = SHT_RELA;
                        sh->flags = SHF_ALLOC;
                        sh->entsize = ELF64RELASIZE;
                        sh->addralign = 8;
                        sh->link = elfshname(".dynsym")->shnum;
                        shsym(sh, linklookup(ctxt, ".rela", 0));
                        break;
                
                default:
                        sh = elfshname(".rel.plt");
                        sh->type = SHT_REL;
                        sh->flags = SHF_ALLOC;
                        sh->entsize = ELF32RELSIZE;
                        sh->link = elfshname(".dynsym")->shnum;
                        shsym(sh, linklookup(ctxt, ".rel.plt", 0));
                        sh = elfshname(".rel");
                        sh->type = SHT_REL;
                        sh->flags = SHF_ALLOC;
                        sh->entsize = ELF32RELSIZE;
                        sh->addralign = 4;
                        sh->link = elfshname(".dynsym")->shnum;
                        shsym(sh, linklookup(ctxt, ".rel", 0));
                        break;
                }
                sh = elfshname(".plt");
                sh->type = SHT_PROGBITS;
                sh->flags = SHF_ALLOC+SHF_EXECINSTR;
                if(eh->machine == EM_X86_64)
                        sh->entsize = 16;
                else
                        sh->entsize = 4;
                sh->addralign = 4;
                shsym(sh, linklookup(ctxt, ".plt", 0));
                sh = elfshname(".got");
                sh->type = SHT_PROGBITS;
                sh->flags = SHF_ALLOC+SHF_WRITE;
                sh->entsize = RegSize;
                sh->addralign = RegSize;
                shsym(sh, linklookup(ctxt, ".got", 0));
                sh = elfshname(".got.plt");
                sh->type = SHT_PROGBITS;
                sh->flags = SHF_ALLOC+SHF_WRITE;
                sh->entsize = RegSize;
                sh->addralign = RegSize;
                shsym(sh, linklookup(ctxt, ".got.plt", 0));
                
                sh = elfshname(".hash");
                sh->type = SHT_HASH;
                sh->flags = SHF_ALLOC;
                sh->entsize = 4;
                sh->addralign = RegSize;
                sh->link = elfshname(".dynsym")->shnum;
                shsym(sh, linklookup(ctxt, ".hash", 0));
                
                sh = elfshname(".dynamic");
                sh->type = SHT_DYNAMIC;
                sh->flags = SHF_ALLOC+SHF_WRITE;
                sh->entsize = 2*RegSize;
                sh->addralign = RegSize;
                sh->link = elfshname(".dynstr")->shnum;
                shsym(sh, linklookup(ctxt, ".dynamic", 0));
                ph = newElfPhdr();
                ph->type = PT_DYNAMIC;
                ph->flags = PF_R + PF_W;
                phsh(ph, sh);
                
                
                
                
                
                if(ctxt->tlsoffset != 0 && HEADTYPE != Hopenbsd) {
                        ph = newElfPhdr();
                        ph->type = PT_TLS;
                        ph->flags = PF_R;
                        ph->memsz = -ctxt->tlsoffset;
                        ph->align = RegSize;
                }
        }
        if(HEADTYPE == Hlinux) {
                ph = newElfPhdr();
                ph->type = PT_GNU_STACK;
                ph->flags = PF_W+PF_R;
                ph->align = RegSize;
                
                ph = newElfPhdr();
                ph->type = PT_PAX_FLAGS;
                ph->flags = 0x2a00; 
                ph->align = RegSize;
        }
elfobj:
        sh = elfshname(".shstrtab");
        sh->type = SHT_STRTAB;
        sh->addralign = 1;
        shsym(sh, linklookup(ctxt, ".shstrtab", 0));
        eh->shstrndx = sh->shnum;
        
        if(!debug['s']) {
                elfshname(".symtab");
                elfshname(".strtab");
        }
        for(sect=segtext.sect; sect!=nil; sect=sect->next)
                elfshbits(sect);
        for(sect=segrodata.sect; sect!=nil; sect=sect->next)
                elfshbits(sect);
        for(sect=segdata.sect; sect!=nil; sect=sect->next)
                elfshbits(sect);
        if(linkmode == LinkExternal) {
                for(sect=segtext.sect; sect!=nil; sect=sect->next)
                        elfshreloc(sect);
                for(sect=segrodata.sect; sect!=nil; sect=sect->next)
                        elfshreloc(sect);
                for(sect=segdata.sect; sect!=nil; sect=sect->next)
                        elfshreloc(sect);
                
                sh = elfshname(".note.GNU-stack");
                sh->type = SHT_PROGBITS;
                sh->addralign = 1;
                sh->flags = 0;
        }
        
        
        if(linkmode == LinkInternal && !debug['d'] && HEADTYPE != Hopenbsd) {
                sh = elfshname(".tbss");
                sh->type = SHT_NOBITS;
                sh->addralign = RegSize;
                sh->size = -ctxt->tlsoffset;
                sh->flags = SHF_ALLOC | SHF_TLS | SHF_WRITE;
        }
        if(!debug['s']) {
                sh = elfshname(".symtab");
                sh->type = SHT_SYMTAB;
                sh->off = symo;
                sh->size = symsize;
                sh->addralign = RegSize;
                sh->entsize = 8+2*RegSize;
                sh->link = elfshname(".strtab")->shnum;
                sh->info = elfglobalsymndx;
                sh = elfshname(".strtab");
                sh->type = SHT_STRTAB;
                sh->off = symo+symsize;
                sh->size = elfstrsize;
                sh->addralign = 1;
                dwarfaddelfheaders();
        }
        
        eh->ident[EI_MAG0] = '\177';
        eh->ident[EI_MAG1] = 'E';
        eh->ident[EI_MAG2] = 'L';
        eh->ident[EI_MAG3] = 'F';
        if(HEADTYPE == Hfreebsd)
                eh->ident[EI_OSABI] = ELFOSABI_FREEBSD;
        else if(HEADTYPE == Hnetbsd)
                eh->ident[EI_OSABI] = ELFOSABI_NETBSD;
        else if(HEADTYPE == Hopenbsd)
                eh->ident[EI_OSABI] = ELFOSABI_OPENBSD;
        else if(HEADTYPE == Hdragonfly)
                eh->ident[EI_OSABI] = ELFOSABI_NONE;
        if(elf64)
                eh->ident[EI_CLASS] = ELFCLASS64;
        else
                eh->ident[EI_CLASS] = ELFCLASS32;
        eh->ident[EI_DATA] = ELFDATA2LSB;
        eh->ident[EI_VERSION] = EV_CURRENT;
        if(linkmode == LinkExternal)
                eh->type = ET_REL;
        else
                eh->type = ET_EXEC;
        if(linkmode != LinkExternal)
                eh->entry = entryvalue();
        eh->version = EV_CURRENT;
        if(pph != nil) {
                pph->filesz = eh->phnum * eh->phentsize;
                pph->memsz = pph->filesz;
        }
        cseek(0);
        a = 0;
        a += elfwritehdr();
        a += elfwritephdrs();
        a += elfwriteshdrs();
        if(!debug['d'])
                a += elfwriteinterp();
        if(linkmode != LinkExternal) {
                if(HEADTYPE == Hnetbsd)
                        a += elfwritenetbsdsig();
                if(HEADTYPE == Hopenbsd)
                        a += elfwriteopenbsdsig();
                if(buildinfolen > 0)
                        a += elfwritebuildinfo();
        }
        if(a > ELFRESERVE)      
                diag("ELFRESERVE too small: %lld > %d", a, ELFRESERVE);
}