The Go Programming Language

Text file src/cmd/6l/asm.c

     1	// Inferno utils/6l/asm.c
     2	// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.c
     3	//
     4	//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5	//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6	//	Portions Copyright © 1997-1999 Vita Nuova Limited
     7	//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8	//	Portions Copyright © 2004,2006 Bruce Ellis
     9	//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10	//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11	//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    12	//
    13	// Permission is hereby granted, free of charge, to any person obtaining a copy
    14	// of this software and associated documentation files (the "Software"), to deal
    15	// in the Software without restriction, including without limitation the rights
    16	// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17	// copies of the Software, and to permit persons to whom the Software is
    18	// furnished to do so, subject to the following conditions:
    19	//
    20	// The above copyright notice and this permission notice shall be included in
    21	// all copies or substantial portions of the Software.
    22	//
    23	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24	// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25	// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26	// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27	// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28	// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29	// THE SOFTWARE.
    30	
    31	// Writing object files.
    32	
    33	#include	"l.h"
    34	#include	"../ld/lib.h"
    35	#include	"../ld/elf.h"
    36	#include	"../ld/dwarf.h"
    37	#include	"../ld/macho.h"
    38	#include	"../ld/pe.h"
    39	
    40	#define	Dbufslop	100
    41	
    42	#define PADDR(a)	((uint32)(a) & ~0x80000000)
    43	
    44	char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2";
    45	char freebsddynld[] = "/libexec/ld-elf.so.1";
    46	char openbsddynld[] = "/usr/libexec/ld.so";
    47	
    48	char	zeroes[32];
    49	
    50	vlong
    51	entryvalue(void)
    52	{
    53		char *a;
    54		Sym *s;
    55	
    56		a = INITENTRY;
    57		if(*a >= '0' && *a <= '9')
    58			return atolwhex(a);
    59		s = lookup(a, 0);
    60		if(s->type == 0)
    61			return INITTEXT;
    62		if(s->type != STEXT)
    63			diag("entry not text: %s", s->name);
    64		return s->value;
    65	}
    66	
    67	vlong
    68	datoff(vlong addr)
    69	{
    70		if(addr >= segdata.vaddr)
    71			return addr - segdata.vaddr + segdata.fileoff;
    72		if(addr >= segtext.vaddr)
    73			return addr - segtext.vaddr + segtext.fileoff;
    74		diag("datoff %#llx", addr);
    75		return 0;
    76	}
    77	
    78	enum {
    79		ElfStrEmpty,
    80		ElfStrInterp,
    81		ElfStrHash,
    82		ElfStrGot,
    83		ElfStrGotPlt,
    84		ElfStrDynamic,
    85		ElfStrDynsym,
    86		ElfStrDynstr,
    87		ElfStrRela,
    88		ElfStrText,
    89		ElfStrData,
    90		ElfStrBss,
    91		ElfStrShstrtab,
    92		ElfStrSymtab,
    93		ElfStrStrtab,
    94		ElfStrRelaPlt,
    95		ElfStrPlt,
    96		ElfStrGnuVersion,
    97		ElfStrGnuVersionR,
    98		NElfStr
    99	};
   100	
   101	vlong elfstr[NElfStr];
   102	
   103	static int
   104	needlib(char *name)
   105	{
   106		char *p;
   107		Sym *s;
   108	
   109		if(*name == '\0')
   110			return 0;
   111	
   112		/* reuse hash code in symbol table */
   113		p = smprint(".elfload.%s", name);
   114		s = lookup(p, 0);
   115		if(s->type == 0) {
   116			s->type = 100;	// avoid SDATA, etc.
   117			return 1;
   118		}
   119		return 0;
   120	}
   121	
   122	int nelfsym = 1;
   123	
   124	static void addpltsym(Sym*);
   125	static void addgotsym(Sym*);
   126	
   127	void
   128	adddynrel(Sym *s, Reloc *r)
   129	{
   130		Sym *targ, *rela, *got;
   131		
   132		targ = r->sym;
   133		cursym = s;
   134	
   135		switch(r->type) {
   136		default:
   137			if(r->type >= 256) {
   138				diag("unexpected relocation type %d", r->type);
   139				return;
   140			}
   141			break;
   142	
   143		// Handle relocations found in ELF object files.
   144		case 256 + R_X86_64_PC32:
   145			if(targ->dynimpname != nil && !targ->dynexport)
   146				diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name);
   147			if(targ->type == 0 || targ->type == SXREF)
   148				diag("unknown symbol %s in pcrel", targ->name);
   149			r->type = D_PCREL;
   150			r->add += 4;
   151			return;
   152		
   153		case 256 + R_X86_64_PLT32:
   154			r->type = D_PCREL;
   155			r->add += 4;
   156			if(targ->dynimpname != nil && !targ->dynexport) {
   157				addpltsym(targ);
   158				r->sym = lookup(".plt", 0);
   159				r->add += targ->plt;
   160			}
   161			return;
   162		
   163		case 256 + R_X86_64_GOTPCREL:
   164			if(targ->dynimpname == nil || targ->dynexport) {
   165				// have symbol
   166				if(r->off >= 2 && s->p[r->off-2] == 0x8b) {
   167					// turn MOVQ of GOT entry into LEAQ of symbol itself
   168					s->p[r->off-2] = 0x8d;
   169					r->type = D_PCREL;
   170					r->add += 4;
   171					return;
   172				}
   173				// fall back to using GOT and hope for the best (CMOV*)
   174				// TODO: just needs relocation, no need to put in .dynsym
   175				targ->dynimpname = targ->name;
   176			}
   177			addgotsym(targ);
   178			r->type = D_PCREL;
   179			r->sym = lookup(".got", 0);
   180			r->add += 4;
   181			r->add += targ->got;
   182			return;
   183		
   184		case 256 + R_X86_64_64:
   185			if(targ->dynimpname != nil && !targ->dynexport)
   186				diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name);
   187			r->type = D_ADDR;
   188			return;
   189		
   190		// Handle relocations found in Mach-O object files.
   191		case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 0:
   192		case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 0:
   193		case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0:
   194			// TODO: What is the difference between all these?
   195			r->type = D_ADDR;
   196			if(targ->dynimpname != nil && !targ->dynexport)
   197				diag("unexpected reloc for dynamic symbol %s", targ->name);
   198			return;
   199	
   200		case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
   201			if(targ->dynimpname != nil && !targ->dynexport) {
   202				addpltsym(targ);
   203				r->sym = lookup(".plt", 0);
   204				r->add = targ->plt;
   205				r->type = D_PCREL;
   206				return;
   207			}
   208			// fall through
   209		case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 1:
   210		case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 1:
   211		case 512 + MACHO_X86_64_RELOC_SIGNED_1*2 + 1:
   212		case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1:
   213		case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
   214			r->type = D_PCREL;
   215			if(targ->dynimpname != nil && !targ->dynexport)
   216				diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
   217			return;
   218	
   219		case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
   220			if(targ->dynimpname == nil || targ->dynexport) {
   221				// have symbol
   222				// turn MOVQ of GOT entry into LEAQ of symbol itself
   223				if(r->off < 2 || s->p[r->off-2] != 0x8b) {
   224					diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name);
   225					return;
   226				}
   227				s->p[r->off-2] = 0x8d;
   228				r->type = D_PCREL;
   229				return;
   230			}
   231			// fall through
   232		case 512 + MACHO_X86_64_RELOC_GOT*2 + 1:
   233			if(targ->dynimpname == nil || targ->dynexport)
   234				diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
   235			addgotsym(targ);
   236			r->type = D_PCREL;
   237			r->sym = lookup(".got", 0);
   238			r->add += targ->got;
   239			return;
   240		}
   241		
   242		// Handle references to ELF symbols from our own object files.
   243		if(targ->dynimpname == nil || targ->dynexport)
   244			return;
   245	
   246		switch(r->type) {
   247		case D_PCREL:
   248			addpltsym(targ);
   249			r->sym = lookup(".plt", 0);
   250			r->add = targ->plt;
   251			return;
   252		
   253		case D_ADDR:
   254			if(s->type != SDATA)
   255				break;
   256			if(iself) {
   257				adddynsym(targ);
   258				rela = lookup(".rela", 0);
   259				addaddrplus(rela, s, r->off);
   260				if(r->siz == 8)
   261					adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
   262				else
   263					adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
   264				adduint64(rela, r->add);
   265				r->type = 256;	// ignore during relocsym
   266				return;
   267			}
   268			if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) {
   269				// Mach-O relocations are a royal pain to lay out.
   270				// They use a compact stateful bytecode representation
   271				// that is too much bother to deal with.
   272				// Instead, interpret the C declaration
   273				//	void *_Cvar_stderr = &stderr;
   274				// as making _Cvar_stderr the name of a GOT entry
   275				// for stderr.  This is separate from the usual GOT entry,
   276				// just in case the C code assigns to the variable,
   277				// and of course it only works for single pointers,
   278				// but we only need to support cgo and that's all it needs.
   279				adddynsym(targ);
   280				got = lookup(".got", 0);
   281				s->type = got->type | SSUB;
   282				s->outer = got;
   283				s->sub = got->sub;
   284				got->sub = s;
   285				s->value = got->size;
   286				adduint64(got, 0);
   287				adduint32(lookup(".linkedit.got", 0), targ->dynid);
   288				r->type = 256;	// ignore during relocsym
   289				return;
   290			}
   291			break;
   292		}
   293		
   294		cursym = s;
   295		diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
   296	}
   297	
   298	int
   299	archreloc(Reloc *r, Sym *s, vlong *val)
   300	{
   301		USED(r);
   302		USED(s);
   303		USED(val);
   304		return -1;
   305	}
   306	
   307	static void
   308	elfsetupplt(void)
   309	{
   310		Sym *plt, *got;
   311	
   312		plt = lookup(".plt", 0);
   313		got = lookup(".got.plt", 0);
   314		if(plt->size == 0) {
   315			// pushq got+8(IP)
   316			adduint8(plt, 0xff);
   317			adduint8(plt, 0x35);
   318			addpcrelplus(plt, got, 8);
   319			
   320			// jmpq got+16(IP)
   321			adduint8(plt, 0xff);
   322			adduint8(plt, 0x25);
   323			addpcrelplus(plt, got, 16);
   324			
   325			// nopl 0(AX)
   326			adduint32(plt, 0x00401f0f);
   327			
   328			// assume got->size == 0 too
   329			addaddrplus(got, lookup(".dynamic", 0), 0);
   330			adduint64(got, 0);
   331			adduint64(got, 0);
   332		}
   333	}
   334	
   335	static void
   336	addpltsym(Sym *s)
   337	{
   338		if(s->plt >= 0)
   339			return;
   340		
   341		adddynsym(s);
   342		
   343		if(iself) {
   344			Sym *plt, *got, *rela;
   345	
   346			plt = lookup(".plt", 0);
   347			got = lookup(".got.plt", 0);
   348			rela = lookup(".rela.plt", 0);
   349			if(plt->size == 0)
   350				elfsetupplt();
   351			
   352			// jmpq *got+size(IP)
   353			adduint8(plt, 0xff);
   354			adduint8(plt, 0x25);
   355			addpcrelplus(plt, got, got->size);
   356		
   357			// add to got: pointer to current pos in plt
   358			addaddrplus(got, plt, plt->size);
   359			
   360			// pushq $x
   361			adduint8(plt, 0x68);
   362			adduint32(plt, (got->size-24-8)/8);
   363			
   364			// jmpq .plt
   365			adduint8(plt, 0xe9);
   366			adduint32(plt, -(plt->size+4));
   367			
   368			// rela
   369			addaddrplus(rela, got, got->size-8);
   370			adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT));
   371			adduint64(rela, 0);
   372			
   373			s->plt = plt->size - 16;
   374		} else if(HEADTYPE == Hdarwin) {
   375			// To do lazy symbol lookup right, we're supposed
   376			// to tell the dynamic loader which library each 
   377			// symbol comes from and format the link info
   378			// section just so.  I'm too lazy (ha!) to do that
   379			// so for now we'll just use non-lazy pointers,
   380			// which don't need to be told which library to use.
   381			//
   382			// http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
   383			// has details about what we're avoiding.
   384	
   385			Sym *plt;
   386			
   387			addgotsym(s);
   388			plt = lookup(".plt", 0);
   389	
   390			adduint32(lookup(".linkedit.plt", 0), s->dynid);
   391	
   392			// jmpq *got+size(IP)
   393			s->plt = plt->size;
   394	
   395			adduint8(plt, 0xff);
   396			adduint8(plt, 0x25);
   397			addpcrelplus(plt, lookup(".got", 0), s->got);
   398		} else {
   399			diag("addpltsym: unsupported binary format");
   400		}
   401	}
   402	
   403	static void
   404	addgotsym(Sym *s)
   405	{
   406		Sym *got, *rela;
   407	
   408		if(s->got >= 0)
   409			return;
   410	
   411		adddynsym(s);
   412		got = lookup(".got", 0);
   413		s->got = got->size;
   414		adduint64(got, 0);
   415	
   416		if(iself) {
   417			rela = lookup(".rela", 0);
   418			addaddrplus(rela, got, s->got);
   419			adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT));
   420			adduint64(rela, 0);
   421		} else if(HEADTYPE == Hdarwin) {
   422			adduint32(lookup(".linkedit.got", 0), s->dynid);
   423		} else {
   424			diag("addgotsym: unsupported binary format");
   425		}
   426	}
   427	
   428	void
   429	adddynsym(Sym *s)
   430	{
   431		Sym *d, *str;
   432		int t;
   433		char *name;
   434	
   435		if(s->dynid >= 0)
   436			return;
   437	
   438		if(s->dynimpname == nil)
   439			diag("adddynsym: no dynamic name for %s", s->name);
   440	
   441		if(iself) {
   442			s->dynid = nelfsym++;
   443	
   444			d = lookup(".dynsym", 0);
   445	
   446			name = s->dynimpname;
   447			if(name == nil)
   448				name = s->name;
   449			adduint32(d, addstring(lookup(".dynstr", 0), name));
   450			/* type */
   451			t = STB_GLOBAL << 4;
   452			if(s->dynexport && s->type == STEXT)
   453				t |= STT_FUNC;
   454			else
   455				t |= STT_OBJECT;
   456			adduint8(d, t);
   457		
   458			/* reserved */
   459			adduint8(d, 0);
   460		
   461			/* section where symbol is defined */
   462			if(!s->dynexport && s->dynimpname != nil)
   463				adduint16(d, SHN_UNDEF);
   464			else {
   465				switch(s->type) {
   466				default:
   467				case STEXT:
   468					t = 11;
   469					break;
   470				case SRODATA:
   471					t = 12;
   472					break;
   473				case SDATA:
   474					t = 13;
   475					break;
   476				case SBSS:
   477					t = 14;
   478					break;
   479				}
   480				adduint16(d, t);
   481			}
   482		
   483			/* value */
   484			if(s->type == SDYNIMPORT)
   485				adduint64(d, 0);
   486			else
   487				addaddr(d, s);
   488		
   489			/* size of object */
   490			adduint64(d, 0);
   491		
   492			if(!s->dynexport && s->dynimplib && needlib(s->dynimplib)) {
   493				elfwritedynent(lookup(".dynamic", 0), DT_NEEDED,
   494					addstring(lookup(".dynstr", 0), s->dynimplib));
   495			}
   496		} else if(HEADTYPE == Hdarwin) {
   497			// Mach-o symbol nlist64
   498			d = lookup(".dynsym", 0);
   499			name = s->dynimpname;
   500			if(name == nil)
   501				name = s->name;
   502			s->dynid = d->size/16;
   503			// darwin still puts _ prefixes on all C symbols
   504			str = lookup(".dynstr", 0);
   505			adduint32(d, str->size);
   506			adduint8(str, '_');
   507			addstring(str, name);
   508			if(s->type == SDYNIMPORT) {
   509				adduint8(d, 0x01);	// type - N_EXT - external symbol
   510				adduint8(d, 0);	// section
   511			} else {
   512				adduint8(d, 0x0f);
   513				switch(s->type) {
   514				default:
   515				case STEXT:
   516					adduint8(d, 1);
   517					break;
   518				case SDATA:
   519					adduint8(d, 2);
   520					break;
   521				case SBSS:
   522					adduint8(d, 4);
   523					break;
   524				}
   525			}
   526			adduint16(d, 0);	// desc
   527			if(s->type == SDYNIMPORT)
   528				adduint64(d, 0);	// value
   529			else
   530				addaddr(d, s);
   531		} else if(HEADTYPE != Hwindows) {
   532			diag("adddynsym: unsupported binary format");
   533		}
   534	}
   535	
   536	void
   537	adddynlib(char *lib)
   538	{
   539		Sym *s;
   540		
   541		if(!needlib(lib))
   542			return;
   543		
   544		if(iself) {
   545			s = lookup(".dynstr", 0);
   546			if(s->size == 0)
   547				addstring(s, "");
   548			elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
   549		} else if(HEADTYPE == Hdarwin) {
   550			machoadddynlib(lib);
   551		} else {
   552			diag("adddynlib: unsupported binary format");
   553		}
   554	}
   555	
   556	void
   557	doelf(void)
   558	{
   559		Sym *s, *shstrtab, *dynstr;
   560	
   561		if(HEADTYPE != Hlinux && HEADTYPE != Hfreebsd && HEADTYPE != Hopenbsd)
   562			return;
   563	
   564		/* predefine strings we need for section headers */
   565		shstrtab = lookup(".shstrtab", 0);
   566		shstrtab->type = SELFROSECT;
   567		shstrtab->reachable = 1;
   568	
   569		elfstr[ElfStrEmpty] = addstring(shstrtab, "");
   570		elfstr[ElfStrText] = addstring(shstrtab, ".text");
   571		elfstr[ElfStrData] = addstring(shstrtab, ".data");
   572		elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
   573		addstring(shstrtab, ".elfdata");
   574		addstring(shstrtab, ".rodata");
   575		addstring(shstrtab, ".gosymtab");
   576		addstring(shstrtab, ".gopclntab");
   577		if(!debug['s']) {
   578			elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
   579			elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
   580			dwarfaddshstrings(shstrtab);
   581		}
   582		elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
   583	
   584		if(!debug['d']) {	/* -d suppresses dynamic loader format */
   585			elfstr[ElfStrInterp] = addstring(shstrtab, ".interp");
   586			elfstr[ElfStrHash] = addstring(shstrtab, ".hash");
   587			elfstr[ElfStrGot] = addstring(shstrtab, ".got");
   588			elfstr[ElfStrGotPlt] = addstring(shstrtab, ".got.plt");
   589			elfstr[ElfStrDynamic] = addstring(shstrtab, ".dynamic");
   590			elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
   591			elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
   592			elfstr[ElfStrRela] = addstring(shstrtab, ".rela");
   593			elfstr[ElfStrRelaPlt] = addstring(shstrtab, ".rela.plt");
   594			elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
   595			elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version");
   596			elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r");
   597	
   598			/* dynamic symbol table - first entry all zeros */
   599			s = lookup(".dynsym", 0);
   600			s->type = SELFROSECT;
   601			s->reachable = 1;
   602			s->size += ELF64SYMSIZE;
   603	
   604			/* dynamic string table */
   605			s = lookup(".dynstr", 0);
   606			s->type = SELFROSECT;
   607			s->reachable = 1;
   608			if(s->size == 0)
   609				addstring(s, "");
   610			dynstr = s;
   611	
   612			/* relocation table */
   613			s = lookup(".rela", 0);
   614			s->reachable = 1;
   615			s->type = SELFROSECT;
   616	
   617			/* global offset table */
   618			s = lookup(".got", 0);
   619			s->reachable = 1;
   620			s->type = SELFSECT; // writable
   621	
   622			/* hash */
   623			s = lookup(".hash", 0);
   624			s->reachable = 1;
   625			s->type = SELFROSECT;
   626	
   627			s = lookup(".got.plt", 0);
   628			s->reachable = 1;
   629			s->type = SELFSECT; // writable
   630	
   631			s = lookup(".plt", 0);
   632			s->reachable = 1;
   633			s->type = SELFROSECT;
   634			
   635			elfsetupplt();
   636			
   637			s = lookup(".rela.plt", 0);
   638			s->reachable = 1;
   639			s->type = SELFROSECT;
   640			
   641			s = lookup(".gnu.version", 0);
   642			s->reachable = 1;
   643			s->type = SELFROSECT;
   644			
   645			s = lookup(".gnu.version_r", 0);
   646			s->reachable = 1;
   647			s->type = SELFROSECT;
   648	
   649			/* define dynamic elf table */
   650			s = lookup(".dynamic", 0);
   651			s->reachable = 1;
   652			s->type = SELFROSECT;
   653	
   654			/*
   655			 * .dynamic table
   656			 */
   657			elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
   658			elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
   659			elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE);
   660			elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0));
   661			elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0));
   662			elfwritedynentsym(s, DT_RELA, lookup(".rela", 0));
   663			elfwritedynentsymsize(s, DT_RELASZ, lookup(".rela", 0));
   664			elfwritedynent(s, DT_RELAENT, ELF64RELASIZE);
   665			if(rpath)
   666				elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
   667			
   668			elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
   669			elfwritedynent(s, DT_PLTREL, DT_RELA);
   670			elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0));
   671			elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0));
   672			
   673			// Do not write DT_NULL.  elfdynhash will finish it.
   674		}
   675	}
   676	
   677	void
   678	shsym(ElfShdr *sh, Sym *s)
   679	{
   680		vlong addr;
   681		addr = symaddr(s);
   682		if(sh->flags&SHF_ALLOC)
   683			sh->addr = addr;
   684		sh->off = datoff(addr);
   685		sh->size = s->size;
   686	}
   687	
   688	void
   689	phsh(ElfPhdr *ph, ElfShdr *sh)
   690	{
   691		ph->vaddr = sh->addr;
   692		ph->paddr = ph->vaddr;
   693		ph->off = sh->off;
   694		ph->filesz = sh->size;
   695		ph->memsz = sh->size;
   696		ph->align = sh->addralign;
   697	}
   698	
   699	void
   700	asmb(void)
   701	{
   702		int32 magic;
   703		int a, dynsym;
   704		vlong vl, startva, symo, machlink;
   705		ElfEhdr *eh;
   706		ElfPhdr *ph, *pph;
   707		ElfShdr *sh;
   708		Section *sect;
   709		int o;
   710	
   711		if(debug['v'])
   712			Bprint(&bso, "%5.2f asmb\n", cputime());
   713		Bflush(&bso);
   714	
   715		elftextsh = 0;
   716		
   717		if(debug['v'])
   718			Bprint(&bso, "%5.2f codeblk\n", cputime());
   719		Bflush(&bso);
   720	
   721		sect = segtext.sect;
   722		cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
   723		codeblk(sect->vaddr, sect->len);
   724	
   725		/* output read-only data in text segment (rodata, gosymtab and pclntab) */
   726		for(sect = sect->next; sect != nil; sect = sect->next) {
   727			cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
   728			datblk(sect->vaddr, sect->len);
   729		}
   730	
   731		if(debug['v'])
   732			Bprint(&bso, "%5.2f datblk\n", cputime());
   733		Bflush(&bso);
   734	
   735		cseek(segdata.fileoff);
   736		datblk(segdata.vaddr, segdata.filelen);
   737	
   738		machlink = 0;
   739		if(HEADTYPE == Hdarwin)
   740			machlink = domacholink();
   741	
   742		switch(HEADTYPE) {
   743		default:
   744			diag("unknown header type %d", HEADTYPE);
   745		case Hplan9x32:
   746		case Helf:
   747			break;
   748		case Hdarwin:
   749			debug['8'] = 1;	/* 64-bit addresses */
   750			break;
   751		case Hlinux:
   752		case Hfreebsd:
   753		case Hopenbsd:
   754			debug['8'] = 1;	/* 64-bit addresses */
   755			/* index of elf text section; needed by asmelfsym, double-checked below */
   756			/* !debug['d'] causes extra sections before the .text section */
   757			elftextsh = 2;
   758			if(!debug['d']) {
   759				elftextsh += 10;
   760				if(elfverneed)
   761					elftextsh += 2;
   762			}
   763			break;
   764		case Hwindows:
   765			break;
   766		}
   767	
   768		symsize = 0;
   769		spsize = 0;
   770		lcsize = 0;
   771		symo = 0;
   772		if(!debug['s']) {
   773			if(debug['v'])
   774				Bprint(&bso, "%5.2f sym\n", cputime());
   775			Bflush(&bso);
   776			switch(HEADTYPE) {
   777			default:
   778			case Hplan9x32:
   779			case Helf:
   780				debug['s'] = 1;
   781				symo = HEADR+segtext.len+segdata.filelen;
   782				break;
   783			case Hdarwin:
   784				symo = rnd(HEADR+segtext.len, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
   785				break;
   786			case Hlinux:
   787			case Hfreebsd:
   788			case Hopenbsd:
   789				symo = rnd(HEADR+segtext.len, INITRND)+segdata.filelen;
   790				symo = rnd(symo, INITRND);
   791				break;
   792			case Hwindows:
   793				symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
   794				symo = rnd(symo, PEFILEALIGN);
   795				break;
   796			}
   797			cseek(symo);
   798			switch(HEADTYPE) {
   799			default:
   800				if(iself) {
   801					cseek(symo);
   802					asmelfsym();
   803					cflush();
   804					cwrite(elfstrdat, elfstrsize);
   805	
   806					if(debug['v'])
   807					       Bprint(&bso, "%5.2f dwarf\n", cputime());
   808	
   809					dwarfemitdebugsections();
   810				}
   811				break;
   812			case Hdarwin:
   813			case Hwindows:
   814				if(debug['v'])
   815				       Bprint(&bso, "%5.2f dwarf\n", cputime());
   816	
   817				dwarfemitdebugsections();
   818				break;
   819			}
   820		}
   821	
   822		if(debug['v'])
   823			Bprint(&bso, "%5.2f headr\n", cputime());
   824		Bflush(&bso);
   825		cseek(0L);
   826		switch(HEADTYPE) {
   827		default:
   828		case Hplan9x32:	/* plan9 */
   829			magic = 4*26*26+7;
   830			magic |= 0x00008000;		/* fat header */
   831			lputb(magic);			/* magic */
   832			lputb(segtext.filelen);			/* sizes */
   833			lputb(segdata.filelen);
   834			lputb(segdata.len - segdata.filelen);
   835			lputb(symsize);			/* nsyms */
   836			vl = entryvalue();
   837			lputb(PADDR(vl));		/* va of entry */
   838			lputb(spsize);			/* sp offsets */
   839			lputb(lcsize);			/* line offsets */
   840			vputb(vl);			/* va of entry */
   841			break;
   842		case Hplan9x64:	/* plan9 */
   843			magic = 4*26*26+7;
   844			lputb(magic);			/* magic */
   845			lputb(segtext.filelen);		/* sizes */
   846			lputb(segdata.filelen);
   847			lputb(segdata.len - segdata.filelen);
   848			lputb(symsize);			/* nsyms */
   849			lputb(entryvalue());		/* va of entry */
   850			lputb(spsize);			/* sp offsets */
   851			lputb(lcsize);			/* line offsets */
   852			break;
   853		case Hdarwin:
   854			asmbmacho();
   855			break;
   856		case Hlinux:
   857		case Hfreebsd:
   858		case Hopenbsd:
   859			/* elf amd-64 */
   860	
   861			eh = getElfEhdr();
   862			startva = INITTEXT - HEADR;
   863	
   864			/* This null SHdr must appear before all others */
   865			newElfShdr(elfstr[ElfStrEmpty]);
   866	
   867			/* program header info */
   868			pph = newElfPhdr();
   869			pph->type = PT_PHDR;
   870			pph->flags = PF_R + PF_X;
   871			pph->off = eh->ehsize;
   872			pph->vaddr = INITTEXT - HEADR + pph->off;
   873			pph->paddr = INITTEXT - HEADR + pph->off;
   874			pph->align = INITRND;
   875	
   876			/*
   877			 * PHDR must be in a loaded segment. Adjust the text
   878			 * segment boundaries downwards to include it.
   879			 */
   880			o = segtext.vaddr - pph->vaddr;
   881			segtext.vaddr -= o;
   882			segtext.len += o;
   883			o = segtext.fileoff - pph->off;
   884			segtext.fileoff -= o;
   885			segtext.filelen += o;
   886	
   887			if(!debug['d']) {
   888				/* interpreter */
   889				sh = newElfShdr(elfstr[ElfStrInterp]);
   890				sh->type = SHT_PROGBITS;
   891				sh->flags = SHF_ALLOC;
   892				sh->addralign = 1;
   893				if(interpreter == nil) {
   894					switch(HEADTYPE) {
   895					case Hlinux:
   896						interpreter = linuxdynld;
   897						break;
   898					case Hfreebsd:
   899						interpreter = freebsddynld;
   900						break;
   901					case Hopenbsd:
   902						interpreter = openbsddynld;
   903						break;
   904					}
   905				}
   906				elfinterp(sh, startva, interpreter);
   907	
   908				ph = newElfPhdr();
   909				ph->type = PT_INTERP;
   910				ph->flags = PF_R;
   911				phsh(ph, sh);
   912			}
   913	
   914			elfphload(&segtext);
   915			elfphload(&segdata);
   916	
   917			/* Dynamic linking sections */
   918			if (!debug['d']) {	/* -d suppresses dynamic loader format */
   919				/* S headers for dynamic linking */
   920				sh = newElfShdr(elfstr[ElfStrGot]);
   921				sh->type = SHT_PROGBITS;
   922				sh->flags = SHF_ALLOC+SHF_WRITE;
   923				sh->entsize = 8;
   924				sh->addralign = 8;
   925				shsym(sh, lookup(".got", 0));
   926	
   927				sh = newElfShdr(elfstr[ElfStrGotPlt]);
   928				sh->type = SHT_PROGBITS;
   929				sh->flags = SHF_ALLOC+SHF_WRITE;
   930				sh->entsize = 8;
   931				sh->addralign = 8;
   932				shsym(sh, lookup(".got.plt", 0));
   933				
   934				dynsym = eh->shnum;
   935				sh = newElfShdr(elfstr[ElfStrDynsym]);
   936				sh->type = SHT_DYNSYM;
   937				sh->flags = SHF_ALLOC;
   938				sh->entsize = ELF64SYMSIZE;
   939				sh->addralign = 8;
   940				sh->link = dynsym+1;	// dynstr
   941				// sh->info = index of first non-local symbol (number of local symbols)
   942				shsym(sh, lookup(".dynsym", 0));
   943	
   944				sh = newElfShdr(elfstr[ElfStrDynstr]);
   945				sh->type = SHT_STRTAB;
   946				sh->flags = SHF_ALLOC;
   947				sh->addralign = 1;
   948				shsym(sh, lookup(".dynstr", 0));
   949	
   950				if(elfverneed) {
   951					sh = newElfShdr(elfstr[ElfStrGnuVersion]);
   952					sh->type = SHT_GNU_VERSYM;
   953					sh->flags = SHF_ALLOC;
   954					sh->addralign = 2;
   955					sh->link = dynsym;
   956					sh->entsize = 2;
   957					shsym(sh, lookup(".gnu.version", 0));
   958					
   959					sh = newElfShdr(elfstr[ElfStrGnuVersionR]);
   960					sh->type = SHT_GNU_VERNEED;
   961					sh->flags = SHF_ALLOC;
   962					sh->addralign = 8;
   963					sh->info = elfverneed;
   964					sh->link = dynsym+1;  // dynstr
   965					shsym(sh, lookup(".gnu.version_r", 0));
   966				}
   967	
   968				sh = newElfShdr(elfstr[ElfStrRelaPlt]);
   969				sh->type = SHT_RELA;
   970				sh->flags = SHF_ALLOC;
   971				sh->entsize = ELF64RELASIZE;
   972				sh->addralign = 8;
   973				sh->link = dynsym;
   974				sh->info = eh->shnum;	// .plt
   975				shsym(sh, lookup(".rela.plt", 0));
   976	
   977				sh = newElfShdr(elfstr[ElfStrPlt]);
   978				sh->type = SHT_PROGBITS;
   979				sh->flags = SHF_ALLOC+SHF_EXECINSTR;
   980				sh->entsize = 16;
   981				sh->addralign = 4;
   982				shsym(sh, lookup(".plt", 0));
   983	
   984				sh = newElfShdr(elfstr[ElfStrHash]);
   985				sh->type = SHT_HASH;
   986				sh->flags = SHF_ALLOC;
   987				sh->entsize = 4;
   988				sh->addralign = 8;
   989				sh->link = dynsym;
   990				shsym(sh, lookup(".hash", 0));
   991	
   992				sh = newElfShdr(elfstr[ElfStrRela]);
   993				sh->type = SHT_RELA;
   994				sh->flags = SHF_ALLOC;
   995				sh->entsize = ELF64RELASIZE;
   996				sh->addralign = 8;
   997				sh->link = dynsym;
   998				shsym(sh, lookup(".rela", 0));
   999	
  1000				/* sh and PT_DYNAMIC for .dynamic section */
  1001				sh = newElfShdr(elfstr[ElfStrDynamic]);
  1002				sh->type = SHT_DYNAMIC;
  1003				sh->flags = SHF_ALLOC+SHF_WRITE;
  1004				sh->entsize = 16;
  1005				sh->addralign = 8;
  1006				sh->link = dynsym+1;	// dynstr
  1007				shsym(sh, lookup(".dynamic", 0));
  1008				ph = newElfPhdr();
  1009				ph->type = PT_DYNAMIC;
  1010				ph->flags = PF_R + PF_W;
  1011				phsh(ph, sh);
  1012				
  1013				/*
  1014				 * Thread-local storage segment (really just size).
  1015				 */
  1016				if(tlsoffset != 0) {
  1017					ph = newElfPhdr();
  1018					ph->type = PT_TLS;
  1019					ph->flags = PF_R;
  1020					ph->memsz = -tlsoffset;
  1021					ph->align = 8;
  1022				}
  1023			}
  1024	
  1025			ph = newElfPhdr();
  1026			ph->type = PT_GNU_STACK;
  1027			ph->flags = PF_W+PF_R;
  1028			ph->align = 8;
  1029	
  1030			sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
  1031			sh->type = SHT_STRTAB;
  1032			sh->addralign = 1;
  1033			shsym(sh, lookup(".shstrtab", 0));
  1034	
  1035			if(elftextsh != eh->shnum)
  1036				diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
  1037			for(sect=segtext.sect; sect!=nil; sect=sect->next)
  1038				elfshbits(sect);
  1039			for(sect=segdata.sect; sect!=nil; sect=sect->next)
  1040				elfshbits(sect);
  1041	
  1042			if (!debug['s']) {
  1043				sh = newElfShdr(elfstr[ElfStrSymtab]);
  1044				sh->type = SHT_SYMTAB;
  1045				sh->off = symo;
  1046				sh->size = symsize;
  1047				sh->addralign = 8;
  1048				sh->entsize = 24;
  1049				sh->link = eh->shnum;	// link to strtab
  1050	
  1051				sh = newElfShdr(elfstr[ElfStrStrtab]);
  1052				sh->type = SHT_STRTAB;
  1053				sh->off = symo+symsize;
  1054				sh->size = elfstrsize;
  1055				sh->addralign = 1;
  1056	
  1057				dwarfaddelfheaders();
  1058			}
  1059	
  1060			/* Main header */
  1061			eh->ident[EI_MAG0] = '\177';
  1062			eh->ident[EI_MAG1] = 'E';
  1063			eh->ident[EI_MAG2] = 'L';
  1064			eh->ident[EI_MAG3] = 'F';
  1065			if(HEADTYPE == Hfreebsd)
  1066				eh->ident[EI_OSABI] = ELFOSABI_FREEBSD;
  1067			else if(HEADTYPE == Hopenbsd)
  1068				eh->ident[EI_OSABI] = ELFOSABI_OPENBSD;
  1069			eh->ident[EI_CLASS] = ELFCLASS64;
  1070			eh->ident[EI_DATA] = ELFDATA2LSB;
  1071			eh->ident[EI_VERSION] = EV_CURRENT;
  1072	
  1073			eh->type = ET_EXEC;
  1074			eh->machine = EM_X86_64;
  1075			eh->version = EV_CURRENT;
  1076			eh->entry = entryvalue();
  1077	
  1078			pph->filesz = eh->phnum * eh->phentsize;
  1079			pph->memsz = pph->filesz;
  1080	
  1081			cseek(0);
  1082			a = 0;
  1083			a += elfwritehdr();
  1084			a += elfwritephdrs();
  1085			a += elfwriteshdrs();
  1086			cflush();
  1087			if(a+elfwriteinterp() > ELFRESERVE)	
  1088				diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
  1089			break;
  1090		case Hwindows:
  1091			asmbpe();
  1092			break;
  1093		}
  1094		cflush();
  1095	}
  1096	
  1097	vlong
  1098	rnd(vlong v, vlong r)
  1099	{
  1100		vlong c;
  1101	
  1102		if(r <= 0)
  1103			return v;
  1104		v += r - 1;
  1105		c = v % r;
  1106		if(c < 0)
  1107			c += r;
  1108		v -= c;
  1109		return v;
  1110	}
  1111	
  1112	void
  1113	genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
  1114	{
  1115		Auto *a;
  1116		Sym *s;
  1117	
  1118		s = lookup("etext", 0);
  1119		if(s->type == STEXT)
  1120			put(s, s->name, 'T', s->value, s->size, s->version, 0);
  1121	
  1122		for(s=allsym; s!=S; s=s->allsym) {
  1123			if(s->hide)
  1124				continue;
  1125			switch(s->type&~SSUB) {
  1126			case SCONST:
  1127			case SRODATA:
  1128			case SDATA:
  1129			case SELFROSECT:
  1130			case SMACHOGOT:
  1131			case STYPE:
  1132			case SSTRING:
  1133			case SGOSTRING:
  1134			case SWINDOWS:
  1135				if(!s->reachable)
  1136					continue;
  1137				put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
  1138				continue;
  1139	
  1140			case SBSS:
  1141				if(!s->reachable)
  1142					continue;
  1143				put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
  1144				continue;
  1145	
  1146			case SFILE:
  1147				put(nil, s->name, 'f', s->value, 0, s->version, 0);
  1148				continue;
  1149			}
  1150		}
  1151	
  1152		for(s = textp; s != nil; s = s->next) {
  1153			if(s->text == nil)
  1154				continue;
  1155	
  1156			/* filenames first */
  1157			for(a=s->autom; a; a=a->link)
  1158				if(a->type == D_FILE)
  1159					put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0);
  1160				else
  1161				if(a->type == D_FILE1)
  1162					put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0);
  1163	
  1164			put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
  1165	
  1166			/* frame, auto and param after */
  1167			put(nil, ".frame", 'm', s->text->to.offset+8, 0, 0, 0);
  1168	
  1169			for(a=s->autom; a; a=a->link)
  1170				if(a->type == D_AUTO)
  1171					put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
  1172				else
  1173				if(a->type == D_PARAM)
  1174					put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
  1175		}
  1176		if(debug['v'] || debug['n'])
  1177			Bprint(&bso, "symsize = %ud\n", symsize);
  1178		Bflush(&bso);
  1179	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.