github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/cmd/gc/obj.c (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include <u.h>
     6  #include <libc.h>
     7  #include "go.h"
     8  
     9  /*
    10   * architecture-independent object file output
    11   */
    12  
    13  static	void	dumpglobls(void);
    14  
    15  enum
    16  {
    17  	ArhdrSize = 60
    18  };
    19  
    20  static void
    21  formathdr(char *arhdr, char *name, vlong size)
    22  {
    23  	snprint(arhdr, ArhdrSize, "%-16s%-12d%-6d%-6d%-8o%-10lld`",
    24  		name, 0, 0, 0, 0644, size);
    25  	arhdr[ArhdrSize-1] = '\n'; // overwrite \0 written by snprint
    26  }
    27  
    28  void
    29  dumpobj(void)
    30  {
    31  	NodeList *externs, *tmp;
    32  	char arhdr[ArhdrSize];
    33  	vlong startobj, size;
    34  	Sym *zero;
    35  
    36  	bout = Bopen(outfile, OWRITE);
    37  	if(bout == nil) {
    38  		flusherrors();
    39  		print("can't create %s: %r\n", outfile);
    40  		errorexit();
    41  	}
    42  
    43  	startobj = 0;
    44  	if(writearchive) {
    45  		Bwrite(bout, "!<arch>\n", 8);
    46  		memset(arhdr, 0, sizeof arhdr);
    47  		Bwrite(bout, arhdr, sizeof arhdr);
    48  		startobj = Boffset(bout);
    49  	}
    50  	Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring());
    51  	dumpexport();
    52  	
    53  	if(writearchive) {
    54  		Bflush(bout);
    55  		size = Boffset(bout) - startobj;
    56  		if(size&1)
    57  			Bputc(bout, 0);
    58  		Bseek(bout, startobj - ArhdrSize, 0);
    59  		formathdr(arhdr, "__.PKGDEF", size);
    60  		Bwrite(bout, arhdr, ArhdrSize);
    61  		Bflush(bout);
    62  
    63  		Bseek(bout, startobj + size + (size&1), 0);
    64  		memset(arhdr, 0, ArhdrSize);
    65  		Bwrite(bout, arhdr, ArhdrSize);
    66  		startobj = Boffset(bout);
    67  		Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring());
    68  	}
    69  
    70  	Bprint(bout, "\n!\n");
    71  
    72  	externs = nil;
    73  	if(externdcl != nil)
    74  		externs = externdcl->end;
    75  
    76  	dumpglobls();
    77  	dumptypestructs();
    78  
    79  	// Dump extra globals.
    80  	tmp = externdcl;
    81  	if(externs != nil)
    82  		externdcl = externs->next;
    83  	dumpglobls();
    84  	externdcl = tmp;
    85  
    86  	zero = pkglookup("zerovalue", runtimepkg);
    87  	ggloblsym(zero, zerosize, 1, 1);
    88  
    89  	dumpdata();
    90  	writeobj(ctxt, bout);
    91  
    92  	if(writearchive) {
    93  		Bflush(bout);
    94  		size = Boffset(bout) - startobj;
    95  		if(size&1)
    96  			Bputc(bout, 0);
    97  		Bseek(bout, startobj - ArhdrSize, 0);
    98  		snprint(namebuf, sizeof namebuf, "_go_.%c", thechar);
    99  		formathdr(arhdr, namebuf, size);
   100  		Bwrite(bout, arhdr, ArhdrSize);
   101  	}
   102  	Bterm(bout);
   103  }
   104  
   105  static void
   106  dumpglobls(void)
   107  {
   108  	Node *n;
   109  	NodeList *l;
   110  
   111  	// add globals
   112  	for(l=externdcl; l; l=l->next) {
   113  		n = l->n;
   114  		if(n->op != ONAME)
   115  			continue;
   116  
   117  		if(n->type == T)
   118  			fatal("external %N nil type\n", n);
   119  		if(n->class == PFUNC)
   120  			continue;
   121  		if(n->sym->pkg != localpkg)
   122  			continue;
   123  		dowidth(n->type);
   124  
   125  		ggloblnod(n);
   126  	}
   127  	
   128  	for(l=funcsyms; l; l=l->next) {
   129  		n = l->n;
   130  		dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0);
   131  		ggloblsym(n->sym, widthptr, 1, 1);
   132  	}
   133  	
   134  	// Do not reprocess funcsyms on next dumpglobls call.
   135  	funcsyms = nil;
   136  }
   137  
   138  void
   139  Bputname(Biobuf *b, LSym *s)
   140  {
   141  	Bwrite(b, s->name, strlen(s->name)+1);
   142  }
   143  
   144  LSym*
   145  linksym(Sym *s)
   146  {
   147  	char *p;
   148  
   149  	if(s == nil)
   150  		return nil;
   151  	if(s->lsym != nil)
   152  		return s->lsym;
   153  	if(isblanksym(s))
   154  		s->lsym = linklookup(ctxt, "_", 0);
   155  	else {
   156  		p = smprint("%s.%s", s->pkg->prefix, s->name);
   157  		s->lsym = linklookup(ctxt, p, 0);
   158  		free(p);
   159  	}
   160  	return s->lsym;	
   161  }
   162  
   163  int
   164  duintxx(Sym *s, int off, uint64 v, int wid)
   165  {
   166  	// Update symbol data directly instead of generating a
   167  	// DATA instruction that liblink will have to interpret later.
   168  	// This reduces compilation time and memory usage.
   169  	off = rnd(off, wid);
   170  	return setuintxx(ctxt, linksym(s), off, v, wid);
   171  }
   172  
   173  int
   174  duint8(Sym *s, int off, uint8 v)
   175  {
   176  	return duintxx(s, off, v, 1);
   177  }
   178  
   179  int
   180  duint16(Sym *s, int off, uint16 v)
   181  {
   182  	return duintxx(s, off, v, 2);
   183  }
   184  
   185  int
   186  duint32(Sym *s, int off, uint32 v)
   187  {
   188  	return duintxx(s, off, v, 4);
   189  }
   190  
   191  int
   192  duint64(Sym *s, int off, uint64 v)
   193  {
   194  	return duintxx(s, off, v, 8);
   195  }
   196  
   197  int
   198  duintptr(Sym *s, int off, uint64 v)
   199  {
   200  	return duintxx(s, off, v, widthptr);
   201  }
   202  
   203  Sym*
   204  stringsym(char *s, int len)
   205  {
   206  	static int gen;
   207  	Sym *sym;
   208  	int off, n, m;
   209  	struct {
   210  		Strlit lit;
   211  		char buf[110];
   212  	} tmp;
   213  	Pkg *pkg;
   214  
   215  	if(len > 100) {
   216  		// huge strings are made static to avoid long names
   217  		snprint(namebuf, sizeof(namebuf), ".gostring.%d", ++gen);
   218  		pkg = localpkg;
   219  	} else {
   220  		// small strings get named by their contents,
   221  		// so that multiple modules using the same string
   222  		// can share it.
   223  		tmp.lit.len = len;
   224  		memmove(tmp.lit.s, s, len);
   225  		tmp.lit.s[len] = '\0';
   226  		snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp.lit);
   227  		pkg = gostringpkg;
   228  	}
   229  	sym = pkglookup(namebuf, pkg);
   230  	
   231  	// SymUniq flag indicates that data is generated already
   232  	if(sym->flags & SymUniq)
   233  		return sym;
   234  	sym->flags |= SymUniq;
   235  	sym->def = newname(sym);
   236  
   237  	off = 0;
   238  	
   239  	// string header
   240  	off = dsymptr(sym, off, sym, widthptr+widthint);
   241  	off = duintxx(sym, off, len, widthint);
   242  	
   243  	// string data
   244  	for(n=0; n<len; n+=m) {
   245  		m = 8;
   246  		if(m > len-n)
   247  			m = len-n;
   248  		off = dsname(sym, off, s+n, m);
   249  	}
   250  	off = duint8(sym, off, 0);  // terminating NUL for runtime
   251  	off = (off+widthptr-1)&~(widthptr-1);  // round to pointer alignment
   252  	ggloblsym(sym, off, 1, 1);
   253  
   254  	return sym;	
   255  }
   256  
   257  void
   258  slicebytes(Node *nam, char *s, int len)
   259  {
   260  	int off, n, m;
   261  	static int gen;
   262  	Sym *sym;
   263  
   264  	snprint(namebuf, sizeof(namebuf), ".gobytes.%d", ++gen);
   265  	sym = pkglookup(namebuf, localpkg);
   266  	sym->def = newname(sym);
   267  
   268  	off = 0;
   269  	for(n=0; n<len; n+=m) {
   270  		m = 8;
   271  		if(m > len-n)
   272  			m = len-n;
   273  		off = dsname(sym, off, s+n, m);
   274  	}
   275  	ggloblsym(sym, off, 0, 0);
   276  	
   277  	if(nam->op != ONAME)
   278  		fatal("slicebytes %N", nam);
   279  	off = nam->xoffset;
   280  	off = dsymptr(nam->sym, off, sym, 0);
   281  	off = duintxx(nam->sym, off, len, widthint);
   282  	duintxx(nam->sym, off, len, widthint);
   283  }