Beispiel #1
0
void
asmbelf(vlong symo)
{
	int 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(isobj) {
		/* skip program headers */
		eh->phoff = 0;
		eh->phentsize = 0;
		goto elfobj;
	}

	/* program header info */
	pph = newElfPhdr();
	pph->type = PT_PHDR;
	pph->flags = PF_R + PF_X;
	pph->off = eh->ehsize;
	pph->vaddr = INITTEXT - HEADR + pph->off;
	pph->paddr = INITTEXT - HEADR + pph->off;
	pph->align = INITRND;

	/*
	 * PHDR must be in a loaded segment. Adjust the text
	 * segment boundaries downwards to include it.
	 */
	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']) {
		/* interpreter */
		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;
			}
		}
		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);
	}

	// Additions to the reserved area must be above this line.
	USED(resoff);

	elfphload(&segtext);
	elfphload(&segdata);

	/* Dynamic linking sections */
	if(!debug['d']) {	/* -d suppresses dynamic loader format */
		sh = elfshname(".dynsym");
		sh->type = SHT_DYNSYM;
		sh->flags = SHF_ALLOC;
		if(PtrSize == 8)
			sh->entsize = ELF64SYMSIZE;
		else
			sh->entsize = ELF32SYMSIZE;
		sh->addralign = PtrSize;
		sh->link = elfshname(".dynstr")->shnum;
		// sh->info = index of first non-local symbol (number of local symbols)
		shsym(sh, lookup(".dynsym", 0));

		sh = elfshname(".dynstr");
		sh->type = SHT_STRTAB;
		sh->flags = SHF_ALLOC;
		sh->addralign = 1;
		shsym(sh, lookup(".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, lookup(".gnu.version", 0));
			
			sh = elfshname(".gnu.version_r");
			sh->type = SHT_GNU_VERNEED;
			sh->flags = SHF_ALLOC;
			sh->addralign = PtrSize;
			sh->info = elfverneed;
			sh->link = elfshname(".dynstr")->shnum;
			shsym(sh, lookup(".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 = PtrSize;
			sh->link = elfshname(".dynsym")->shnum;
			sh->info = elfshname(".plt")->shnum;
			shsym(sh, lookup(".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, lookup(".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, lookup(".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, lookup(".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, lookup(".plt", 0));

		sh = elfshname(".got");
		sh->type = SHT_PROGBITS;
		sh->flags = SHF_ALLOC+SHF_WRITE;
		sh->entsize = PtrSize;
		sh->addralign = PtrSize;
		shsym(sh, lookup(".got", 0));

		sh = elfshname(".got.plt");
		sh->type = SHT_PROGBITS;
		sh->flags = SHF_ALLOC+SHF_WRITE;
		sh->entsize = PtrSize;
		sh->addralign = PtrSize;
		shsym(sh, lookup(".got.plt", 0));
		
		sh = elfshname(".hash");
		sh->type = SHT_HASH;
		sh->flags = SHF_ALLOC;
		sh->entsize = 4;
		sh->addralign = PtrSize;
		sh->link = elfshname(".dynsym")->shnum;
		shsym(sh, lookup(".hash", 0));

		/* sh and PT_DYNAMIC for .dynamic section */
		sh = elfshname(".dynamic");
		sh->type = SHT_DYNAMIC;
		sh->flags = SHF_ALLOC+SHF_WRITE;
		sh->entsize = 2*PtrSize;
		sh->addralign = PtrSize;
		sh->link = elfshname(".dynstr")->shnum;
		shsym(sh, lookup(".dynamic", 0));
		ph = newElfPhdr();
		ph->type = PT_DYNAMIC;
		ph->flags = PF_R + PF_W;
		phsh(ph, sh);
		
		/*
		 * Thread-local storage segment (really just size).
		 */
		// Do not emit PT_TLS for OpenBSD since ld.so(1) does
		// not currently support it. This is handled
		// appropriately in runtime/cgo.
		if(tlsoffset != 0 && HEADTYPE != Hopenbsd) {
			ph = newElfPhdr();
			ph->type = PT_TLS;
			ph->flags = PF_R;
			ph->memsz = -tlsoffset;
			ph->align = PtrSize;
		}
	}

	if(HEADTYPE == Hlinux) {
		ph = newElfPhdr();
		ph->type = PT_GNU_STACK;
		ph->flags = PF_W+PF_R;
		ph->align = PtrSize;
		
		ph = newElfPhdr();
		ph->type = PT_PAX_FLAGS;
		ph->flags = 0x2a00; // mprotect, randexec, emutramp disabled
		ph->align = PtrSize;
	}

elfobj:
	sh = elfshname(".shstrtab");
	sh->type = SHT_STRTAB;
	sh->addralign = 1;
	shsym(sh, lookup(".shstrtab", 0));
	eh->shstrndx = sh->shnum;

	// put these sections early in the list
	if(!debug['s']) {
		elfshname(".symtab");
		elfshname(".strtab");
	}

	for(sect=segtext.sect; sect!=nil; sect=sect->next)
		elfshbits(sect);
	for(sect=segdata.sect; sect!=nil; sect=sect->next)
		elfshbits(sect);

	if(isobj) {
		for(sect=segtext.sect; sect!=nil; sect=sect->next)
			elfshreloc(sect);
		for(sect=segdata.sect; sect!=nil; sect=sect->next)
			elfshreloc(sect);
	}
		
	if(!debug['s']) {
		sh = elfshname(".symtab");
		sh->type = SHT_SYMTAB;
		sh->off = symo;
		sh->size = symsize;
		sh->addralign = PtrSize;
		sh->entsize = 8+2*PtrSize;
		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;

		// TODO(rsc): Enable for isobj too, once we know it works.
		if(!isobj)
			dwarfaddelfheaders();
	}

	/* Main header */
	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;
	if(PtrSize == 8)
		eh->ident[EI_CLASS] = ELFCLASS64;
	else
		eh->ident[EI_CLASS] = ELFCLASS32;
	eh->ident[EI_DATA] = ELFDATA2LSB;
	eh->ident[EI_VERSION] = EV_CURRENT;

	if(flag_shared)
		eh->type = ET_DYN;
	else if(isobj)
		eh->type = ET_REL;
	else
		eh->type = ET_EXEC;

	if(!isobj)
		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(!isobj) {
		if(HEADTYPE == Hnetbsd)
			a += elfwritenetbsdsig();
		if(HEADTYPE == Hopenbsd)
			a += elfwriteopenbsdsig();
		if(buildinfolen > 0)
			a += elfwritebuildinfo();
	}
	if(a > ELFRESERVE)	
		diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
}
Beispiel #2
0
void
asmb(void)
{
    int32 v, magic;
    int a, dynsym;
    uint32 symo, startva, dwarfoff, machlink, resoff;
    ElfEhdr *eh;
    ElfPhdr *ph, *pph, *pnote;
    ElfShdr *sh;
    Section *sect;
    Sym *sym;
    int o;
    int i;

    if(debug['v'])
        Bprint(&bso, "%5.2f asmb\n", cputime());
    Bflush(&bso);

    sect = segtext.sect;
    cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
    codeblk(sect->vaddr, sect->len);

    /* output read-only data in text segment (rodata, gosymtab, pclntab, ...) */
    for(sect = sect->next; sect != nil; sect = sect->next) {
        cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
        datblk(sect->vaddr, sect->len);
    }

    if(debug['v'])
        Bprint(&bso, "%5.2f datblk\n", cputime());
    Bflush(&bso);

    cseek(segdata.fileoff);
    datblk(segdata.vaddr, segdata.filelen);

    machlink = 0;
    if(HEADTYPE == Hdarwin) {
        if(debug['v'])
            Bprint(&bso, "%5.2f dwarf\n", cputime());

        dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
        cseek(dwarfoff);

        segdwarf.fileoff = cpos();
        dwarfemitdebugsections();
        segdwarf.filelen = cpos() - segdwarf.fileoff;

        machlink = domacholink();
    }

    if(iself) {
        /* index of elf text section; needed by asmelfsym, double-checked below */
        /* !debug['d'] causes extra sections before the .text section */
        elftextsh = 2;
        if(!debug['d']) {
            elftextsh += 10;
            if(elfverneed)
                elftextsh += 2;
        }
        if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd)
            elftextsh += 1;
        if(buildinfolen > 0)
            elftextsh += 1;
    }

    symsize = 0;
    spsize = 0;
    lcsize = 0;
    symo = 0;
    if(!debug['s']) {
        // TODO: rationalize
        if(debug['v'])
            Bprint(&bso, "%5.2f sym\n", cputime());
        Bflush(&bso);
        switch(HEADTYPE) {
        default:
            if(iself)
                goto Elfsym;
        case Hgarbunix:
            symo = rnd(HEADR+segtext.filelen, 8192)+segdata.filelen;
            break;
        case Hunixcoff:
            symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
            break;
        case Hplan9x32:
            symo = HEADR+segtext.filelen+segdata.filelen;
            break;
        case Hmsdoscom:
        case Hmsdosexe:
            debug['s'] = 1;
            symo = HEADR+segtext.filelen+segdata.filelen;
            break;
        case Hdarwin:
            symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
            break;
Elfsym:
            symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
            symo = rnd(symo, INITRND);
            break;
        case Hwindows:
            symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
            symo = rnd(symo, PEFILEALIGN);
            break;
        }
        cseek(symo);
        switch(HEADTYPE) {
        default:
            if(iself) {
                if(debug['v'])
                    Bprint(&bso, "%5.2f elfsym\n", cputime());
                asmelfsym();
                cflush();
                cwrite(elfstrdat, elfstrsize);

                if(debug['v'])
                    Bprint(&bso, "%5.2f dwarf\n", cputime());
                dwarfemitdebugsections();
            }
            break;
        case Hplan9x32:
            asmplan9sym();
            cflush();

            sym = lookup("pclntab", 0);
            if(sym != nil) {
                lcsize = sym->np;
                for(i=0; i < lcsize; i++)
                    cput(sym->p[i]);

                cflush();
            }
            break;
        case Hwindows:
            if(debug['v'])
                Bprint(&bso, "%5.2f dwarf\n", cputime());
            dwarfemitdebugsections();
            break;
        }
    }
    if(debug['v'])
        Bprint(&bso, "%5.2f headr\n", cputime());
    Bflush(&bso);
    cseek(0L);
    switch(HEADTYPE) {
    default:
        if(iself)
            goto Elfput;
    case Hgarbunix:	/* garbage */
        lputb(0x160L<<16);		/* magic and sections */
        lputb(0L);			/* time and date */
        lputb(rnd(HEADR+segtext.filelen, 4096)+segdata.filelen);
        lputb(symsize);			/* nsyms */
        lputb((0x38L<<16)|7L);		/* size of optional hdr and flags */
        lputb((0413<<16)|0437L);		/* magic and version */
        lputb(rnd(HEADR+segtext.filelen, 4096));	/* sizes */
        lputb(segdata.filelen);
        lputb(segdata.len - segdata.filelen);
        lputb(entryvalue());		/* va of entry */
        lputb(INITTEXT-HEADR);		/* va of base of text */
        lputb(segdata.vaddr);			/* va of base of data */
        lputb(segdata.vaddr+segdata.filelen);		/* va of base of bss */
        lputb(~0L);			/* gp reg mask */
        lputb(0L);
        lputb(0L);
        lputb(0L);
        lputb(0L);
        lputb(~0L);			/* gp value ?? */
        break;
    case Hunixcoff:	/* unix coff */
        /*
         * file header
         */
        lputl(0x0004014c);		/* 4 sections, magic */
        lputl(0);			/* unix time stamp */
        lputl(0);			/* symbol table */
        lputl(0);			/* nsyms */
        lputl(0x0003001c);		/* flags, sizeof a.out header */
        /*
         * a.out header
         */
        lputl(0x10b);			/* magic, version stamp */
        lputl(rnd(segtext.filelen, INITRND));	/* text sizes */
        lputl(segdata.filelen);			/* data sizes */
        lputl(segdata.len - segdata.filelen);			/* bss sizes */
        lputb(entryvalue());		/* va of entry */
        lputl(INITTEXT);		/* text start */
        lputl(segdata.vaddr);			/* data start */
        /*
         * text section header
         */
        s8put(".text");
        lputl(HEADR);			/* pa */
        lputl(HEADR);			/* va */
        lputl(segtext.filelen);		/* text size */
        lputl(HEADR);			/* file offset */
        lputl(0);			/* relocation */
        lputl(0);			/* line numbers */
        lputl(0);			/* relocation, line numbers */
        lputl(0x20);			/* flags text only */
        /*
         * data section header
         */
        s8put(".data");
        lputl(segdata.vaddr);			/* pa */
        lputl(segdata.vaddr);			/* va */
        lputl(segdata.filelen);			/* data size */
        lputl(HEADR+segtext.filelen);		/* file offset */
        lputl(0);			/* relocation */
        lputl(0);			/* line numbers */
        lputl(0);			/* relocation, line numbers */
        lputl(0x40);			/* flags data only */
        /*
         * bss section header
         */
        s8put(".bss");
        lputl(segdata.vaddr+segdata.filelen);		/* pa */
        lputl(segdata.vaddr+segdata.filelen);		/* va */
        lputl(segdata.len - segdata.filelen);			/* bss size */
        lputl(0);			/* file offset */
        lputl(0);			/* relocation */
        lputl(0);			/* line numbers */
        lputl(0);			/* relocation, line numbers */
        lputl(0x80);			/* flags bss only */
        /*
         * comment section header
         */
        s8put(".comment");
        lputl(0);			/* pa */
        lputl(0);			/* va */
        lputl(symsize+lcsize);		/* comment size */
        lputl(HEADR+segtext.filelen+segdata.filelen);	/* file offset */
        lputl(HEADR+segtext.filelen+segdata.filelen);	/* offset of syms */
        lputl(HEADR+segtext.filelen+segdata.filelen+symsize);/* offset of line numbers */
        lputl(0);			/* relocation, line numbers */
        lputl(0x200);			/* flags comment only */
        break;
    case Hplan9x32:	/* plan9 */
        magic = 4*11*11+7;
        lputb(magic);		/* magic */
        lputb(segtext.filelen);			/* sizes */
        lputb(segdata.filelen);
        lputb(segdata.len - segdata.filelen);
        lputb(symsize);			/* nsyms */
        lputb(entryvalue());		/* va of entry */
        lputb(spsize);			/* sp offsets */
        lputb(lcsize);			/* line offsets */
        break;
    case Hmsdoscom:
        /* MS-DOS .COM */
        break;
    case Hmsdosexe:
        /* fake MS-DOS .EXE */
        v = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
        wputl(0x5A4D);			/* 'MZ' */
        wputl(v % 512);			/* bytes in last page */
        wputl(rnd(v, 512)/512);		/* total number of pages */
        wputl(0x0000);			/* number of reloc items */
        v = rnd(HEADR-(INITTEXT & 0xFFFF), 16);
        wputl(v/16);			/* size of header */
        wputl(0x0000);			/* minimum allocation */
        wputl(0xFFFF);			/* maximum allocation */
        wputl(0x0000);			/* initial ss value */
        wputl(0x0100);			/* initial sp value */
        wputl(0x0000);			/* complemented checksum */
        v = entryvalue();
        wputl(v);			/* initial ip value (!) */
        wputl(0x0000);			/* initial cs value */
        wputl(0x0000);
        wputl(0x0000);
        wputl(0x003E);			/* reloc table offset */
        wputl(0x0000);			/* overlay number */
        break;

    case Hdarwin:
        asmbmacho();
        break;

Elfput:
        eh = getElfEhdr();
        startva = INITTEXT - HEADR;
        resoff = ELFRESERVE;

        /* This null SHdr must appear before all others */
        newElfShdr(elfstr[ElfStrEmpty]);

        /* program header info */
        pph = newElfPhdr();
        pph->type = PT_PHDR;
        pph->flags = PF_R + PF_X;
        pph->off = eh->ehsize;
        pph->vaddr = INITTEXT - HEADR + pph->off;
        pph->paddr = INITTEXT - HEADR + pph->off;
        pph->align = INITRND;

        /*
         * PHDR must be in a loaded segment. Adjust the text
         * segment boundaries downwards to include it.
         */
        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']) {
            /* interpreter */
            sh = newElfShdr(elfstr[ElfStrInterp]);
            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;
                }
            }
            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 = newElfShdr(elfstr[ElfStrNoteNetbsdIdent]);
                resoff -= elfnetbsdsig(sh, startva, resoff);
                break;
            case Hopenbsd:
                sh = newElfShdr(elfstr[ElfStrNoteOpenbsdIdent]);
                resoff -= elfopenbsdsig(sh, startva, resoff);
                break;
            }

            pnote = newElfPhdr();
            pnote->type = PT_NOTE;
            pnote->flags = PF_R;
            phsh(pnote, sh);
        }

        if(buildinfolen > 0) {
            sh = newElfShdr(elfstr[ElfStrNoteBuildInfo]);
            resoff -= elfbuildinfo(sh, startva, resoff);

            if(pnote == nil) {
                pnote = newElfPhdr();
                pnote->type = PT_NOTE;
                pnote->flags = PF_R;
            }
            phsh(pnote, sh);
        }

        // Additions to the reserved area must be above this line.
        USED(resoff);

        elfphload(&segtext);
        elfphload(&segdata);

        /* Dynamic linking sections */
        if(!debug['d']) {	/* -d suppresses dynamic loader format */
            /* S headers for dynamic linking */
            sh = newElfShdr(elfstr[ElfStrGot]);
            sh->type = SHT_PROGBITS;
            sh->flags = SHF_ALLOC+SHF_WRITE;
            sh->entsize = 4;
            sh->addralign = 4;
            shsym(sh, lookup(".got", 0));

            sh = newElfShdr(elfstr[ElfStrGotPlt]);
            sh->type = SHT_PROGBITS;
            sh->flags = SHF_ALLOC+SHF_WRITE;
            sh->entsize = 4;
            sh->addralign = 4;
            shsym(sh, lookup(".got.plt", 0));

            dynsym = eh->shnum;
            sh = newElfShdr(elfstr[ElfStrDynsym]);
            sh->type = SHT_DYNSYM;
            sh->flags = SHF_ALLOC;
            sh->entsize = ELF32SYMSIZE;
            sh->addralign = 4;
            sh->link = dynsym+1;	// dynstr
            // sh->info = index of first non-local symbol (number of local symbols)
            shsym(sh, lookup(".dynsym", 0));

            sh = newElfShdr(elfstr[ElfStrDynstr]);
            sh->type = SHT_STRTAB;
            sh->flags = SHF_ALLOC;
            sh->addralign = 1;
            shsym(sh, lookup(".dynstr", 0));

            if(elfverneed) {
                sh = newElfShdr(elfstr[ElfStrGnuVersion]);
                sh->type = SHT_GNU_VERSYM;
                sh->flags = SHF_ALLOC;
                sh->addralign = 2;
                sh->link = dynsym;
                sh->entsize = 2;
                shsym(sh, lookup(".gnu.version", 0));

                sh = newElfShdr(elfstr[ElfStrGnuVersionR]);
                sh->type = SHT_GNU_VERNEED;
                sh->flags = SHF_ALLOC;
                sh->addralign = 4;
                sh->info = elfverneed;
                sh->link = dynsym+1;  // dynstr
                shsym(sh, lookup(".gnu.version_r", 0));
            }

            sh = newElfShdr(elfstr[ElfStrRelPlt]);
            sh->type = SHT_REL;
            sh->flags = SHF_ALLOC;
            sh->entsize = ELF32RELSIZE;
            sh->addralign = 4;
            sh->link = dynsym;
            sh->info = eh->shnum;	// .plt
            shsym(sh, lookup(".rel.plt", 0));

            sh = newElfShdr(elfstr[ElfStrPlt]);
            sh->type = SHT_PROGBITS;
            sh->flags = SHF_ALLOC+SHF_EXECINSTR;
            sh->entsize = 4;
            sh->addralign = 4;
            shsym(sh, lookup(".plt", 0));

            sh = newElfShdr(elfstr[ElfStrHash]);
            sh->type = SHT_HASH;
            sh->flags = SHF_ALLOC;
            sh->entsize = 4;
            sh->addralign = 4;
            sh->link = dynsym;
            shsym(sh, lookup(".hash", 0));

            sh = newElfShdr(elfstr[ElfStrRel]);
            sh->type = SHT_REL;
            sh->flags = SHF_ALLOC;
            sh->entsize = ELF32RELSIZE;
            sh->addralign = 4;
            sh->link = dynsym;
            shsym(sh, lookup(".rel", 0));

            /* sh and PT_DYNAMIC for .dynamic section */
            sh = newElfShdr(elfstr[ElfStrDynamic]);
            sh->type = SHT_DYNAMIC;
            sh->flags = SHF_ALLOC+SHF_WRITE;
            sh->entsize = 8;
            sh->addralign = 4;
            sh->link = dynsym+1;	// dynstr
            shsym(sh, lookup(".dynamic", 0));
            ph = newElfPhdr();
            ph->type = PT_DYNAMIC;
            ph->flags = PF_R + PF_W;
            phsh(ph, sh);

            /*
             * Thread-local storage segment (really just size).
             */
            // Do not emit PT_TLS for OpenBSD since ld.so(1) does
            // not currently support it. This is handled
            // appropriately in runtime/cgo.
            if(tlsoffset != 0 && HEADTYPE != Hopenbsd) {
                ph = newElfPhdr();
                ph->type = PT_TLS;
                ph->flags = PF_R;
                ph->memsz = -tlsoffset;
                ph->align = 4;
            }
        }

        ph = newElfPhdr();
        ph->type = PT_GNU_STACK;
        ph->flags = PF_W+PF_R;
        ph->align = 4;

        ph = newElfPhdr();
        ph->type = PT_PAX_FLAGS;
        ph->flags = 0x2a00; // mprotect, randexec, emutramp disabled
        ph->align = 4;

        sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
        sh->type = SHT_STRTAB;
        sh->addralign = 1;
        shsym(sh, lookup(".shstrtab", 0));

        if(elftextsh != eh->shnum)
            diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
        for(sect=segtext.sect; sect!=nil; sect=sect->next)
            elfshbits(sect);
        for(sect=segdata.sect; sect!=nil; sect=sect->next)
            elfshbits(sect);

        if(!debug['s']) {
            sh = newElfShdr(elfstr[ElfStrSymtab]);
            sh->type = SHT_SYMTAB;
            sh->off = symo;
            sh->size = symsize;
            sh->addralign = 4;
            sh->entsize = 16;
            sh->link = eh->shnum;	// link to strtab

            sh = newElfShdr(elfstr[ElfStrStrtab]);
            sh->type = SHT_STRTAB;
            sh->off = symo+symsize;
            sh->size = elfstrsize;
            sh->addralign = 1;

            dwarfaddelfheaders();
        }

        /* Main header */
        eh->ident[EI_MAG0] = '\177';
        eh->ident[EI_MAG1] = 'E';
        eh->ident[EI_MAG2] = 'L';
        eh->ident[EI_MAG3] = 'F';
        eh->ident[EI_CLASS] = ELFCLASS32;
        eh->ident[EI_DATA] = ELFDATA2LSB;
        eh->ident[EI_VERSION] = EV_CURRENT;
        switch(HEADTYPE) {
        case Hfreebsd:
            eh->ident[EI_OSABI] = ELFOSABI_FREEBSD;
            break;
        case Hnetbsd:
            eh->ident[EI_OSABI] = ELFOSABI_NETBSD;
            break;
        case Hopenbsd:
            eh->ident[EI_OSABI] = ELFOSABI_OPENBSD;
            break;
        }

        eh->type = ET_EXEC;
        eh->machine = EM_386;
        eh->version = EV_CURRENT;
        eh->entry = entryvalue();

        if(pph != nil) {
            pph->filesz = eh->phnum * eh->phentsize;
            pph->memsz = pph->filesz;
        }

        cseek(0);
        a = 0;
        a += elfwritehdr();
        a += elfwritephdrs();
        a += elfwriteshdrs();
        a += elfwriteinterp(elfstr[ElfStrInterp]);
        if(HEADTYPE == Hnetbsd)
            a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]);
        if(HEADTYPE == Hopenbsd)
            a += elfwriteopenbsdsig(elfstr[ElfStrNoteOpenbsdIdent]);
        if(buildinfolen > 0)
            a += elfwritebuildinfo(elfstr[ElfStrNoteBuildInfo]);
        if(a > ELFRESERVE)
            diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
        break;

    case Hwindows:
        asmbpe();
        break;
    }
    cflush();
}