mirror of https://github.com/golang/go.git
291 lines
5.5 KiB
C
291 lines
5.5 KiB
C
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
#include <u.h>
|
|
#include <libc.h>
|
|
#include "go.h"
|
|
|
|
/*
|
|
* architecture-independent object file output
|
|
*/
|
|
|
|
static void outhist(Biobuf *b);
|
|
static void dumpglobls(void);
|
|
|
|
void
|
|
dumpobj(void)
|
|
{
|
|
bout = Bopen(outfile, OWRITE);
|
|
if(bout == nil) {
|
|
flusherrors();
|
|
print("can't create %s: %r\n", outfile);
|
|
errorexit();
|
|
}
|
|
|
|
Bprint(bout, "go object %s %s %s %s\n", getgoos(), thestring, getgoversion(), expstring());
|
|
Bprint(bout, " exports automatically generated from\n");
|
|
Bprint(bout, " %s in package \"%s\"\n", curio.infile, localpkg->name);
|
|
dumpexport();
|
|
Bprint(bout, "\n!\n");
|
|
|
|
outhist(bout);
|
|
|
|
dumpglobls();
|
|
dumptypestructs();
|
|
dumpdata();
|
|
dumpfuncs();
|
|
|
|
Bterm(bout);
|
|
}
|
|
|
|
static void
|
|
dumpglobls(void)
|
|
{
|
|
Node *n;
|
|
NodeList *l;
|
|
|
|
// add globals
|
|
for(l=externdcl; l; l=l->next) {
|
|
n = l->n;
|
|
if(n->op != ONAME)
|
|
continue;
|
|
|
|
if(n->type == T)
|
|
fatal("external %N nil type\n", n);
|
|
if(n->class == PFUNC)
|
|
continue;
|
|
if(n->sym->pkg != localpkg)
|
|
continue;
|
|
dowidth(n->type);
|
|
|
|
ggloblnod(n, n->type->width);
|
|
}
|
|
}
|
|
|
|
void
|
|
Bputname(Biobuf *b, Sym *s)
|
|
{
|
|
Bprint(b, "%s", s->pkg->prefix);
|
|
Bputc(b, '.');
|
|
Bwrite(b, s->name, strlen(s->name)+1);
|
|
}
|
|
|
|
static void
|
|
outzfile(Biobuf *b, char *p)
|
|
{
|
|
char *q, *q2;
|
|
|
|
while(p) {
|
|
q = utfrune(p, '/');
|
|
if(windows) {
|
|
q2 = utfrune(p, '\\');
|
|
if(q2 && (!q || q2 < q))
|
|
q = q2;
|
|
}
|
|
if(!q) {
|
|
zfile(b, p, strlen(p));
|
|
return;
|
|
}
|
|
if(q > p)
|
|
zfile(b, p, q-p);
|
|
p = q + 1;
|
|
}
|
|
}
|
|
|
|
#define isdelim(c) (c == '/' || c == '\\')
|
|
|
|
static void
|
|
outwinname(Biobuf *b, Hist *h, char *ds, char *p)
|
|
{
|
|
if(isdelim(p[0])) {
|
|
// full rooted name
|
|
zfile(b, ds, 3); // leading "c:/"
|
|
outzfile(b, p+1);
|
|
} else {
|
|
// relative name
|
|
if(h->offset == 0 && pathname && pathname[1] == ':') {
|
|
if(tolowerrune(ds[0]) == tolowerrune(pathname[0])) {
|
|
// using current drive
|
|
zfile(b, pathname, 3); // leading "c:/"
|
|
outzfile(b, pathname+3);
|
|
} else {
|
|
// using drive other then current,
|
|
// we don't have any simple way to
|
|
// determine current working directory
|
|
// there, therefore will output name as is
|
|
zfile(b, ds, 2); // leading "c:"
|
|
}
|
|
}
|
|
outzfile(b, p);
|
|
}
|
|
}
|
|
|
|
static void
|
|
outhist(Biobuf *b)
|
|
{
|
|
Hist *h;
|
|
char *p, ds[] = {'c', ':', '/', 0};
|
|
|
|
for(h = hist; h != H; h = h->link) {
|
|
p = h->name;
|
|
if(p) {
|
|
if(windows) {
|
|
// if windows variable is set, then, we know already,
|
|
// pathname is started with windows drive specifier
|
|
// and all '\' were replaced with '/' (see lex.c)
|
|
if(isdelim(p[0]) && isdelim(p[1])) {
|
|
// file name has network name in it,
|
|
// like \\server\share\dir\file.go
|
|
zfile(b, "//", 2); // leading "//"
|
|
outzfile(b, p+2);
|
|
} else if(p[1] == ':') {
|
|
// file name has drive letter in it
|
|
ds[0] = p[0];
|
|
outwinname(b, h, ds, p+2);
|
|
} else {
|
|
// no drive letter in file name
|
|
outwinname(b, h, pathname, p);
|
|
}
|
|
} else {
|
|
if(p[0] == '/') {
|
|
// full rooted name, like /home/rsc/dir/file.go
|
|
zfile(b, "/", 1); // leading "/"
|
|
outzfile(b, p+1);
|
|
} else {
|
|
// relative name, like dir/file.go
|
|
if(h->offset >= 0 && pathname && pathname[0] == '/') {
|
|
zfile(b, "/", 1); // leading "/"
|
|
outzfile(b, pathname+1);
|
|
}
|
|
outzfile(b, p);
|
|
}
|
|
}
|
|
|
|
}
|
|
zhist(b, h->line, h->offset);
|
|
}
|
|
}
|
|
|
|
void
|
|
ieeedtod(uint64 *ieee, double native)
|
|
{
|
|
double fr, ho, f;
|
|
int exp;
|
|
uint32 h, l;
|
|
uint64 bits;
|
|
|
|
if(native < 0) {
|
|
ieeedtod(ieee, -native);
|
|
*ieee |= 1ULL<<63;
|
|
return;
|
|
}
|
|
if(native == 0) {
|
|
*ieee = 0;
|
|
return;
|
|
}
|
|
fr = frexp(native, &exp);
|
|
f = 2097152L; /* shouldnt use fp constants here */
|
|
fr = modf(fr*f, &ho);
|
|
h = ho;
|
|
h &= 0xfffffL;
|
|
f = 65536L;
|
|
fr = modf(fr*f, &ho);
|
|
l = ho;
|
|
l <<= 16;
|
|
l |= (int32)(fr*f);
|
|
bits = ((uint64)h<<32) | l;
|
|
if(exp < -1021) {
|
|
// gradual underflow
|
|
bits |= 1LL<<52;
|
|
bits >>= -1021 - exp;
|
|
exp = -1022;
|
|
}
|
|
bits |= (uint64)(exp+1022L) << 52;
|
|
*ieee = bits;
|
|
}
|
|
|
|
int
|
|
duint8(Sym *s, int off, uint8 v)
|
|
{
|
|
return duintxx(s, off, v, 1);
|
|
}
|
|
|
|
int
|
|
duint16(Sym *s, int off, uint16 v)
|
|
{
|
|
return duintxx(s, off, v, 2);
|
|
}
|
|
|
|
int
|
|
duint32(Sym *s, int off, uint32 v)
|
|
{
|
|
return duintxx(s, off, v, 4);
|
|
}
|
|
|
|
int
|
|
duint64(Sym *s, int off, uint64 v)
|
|
{
|
|
return duintxx(s, off, v, 8);
|
|
}
|
|
|
|
int
|
|
duintptr(Sym *s, int off, uint64 v)
|
|
{
|
|
return duintxx(s, off, v, widthptr);
|
|
}
|
|
|
|
Sym*
|
|
stringsym(char *s, int len)
|
|
{
|
|
static int gen;
|
|
Sym *sym;
|
|
int off, n, m;
|
|
struct {
|
|
Strlit lit;
|
|
char buf[110];
|
|
} tmp;
|
|
Pkg *pkg;
|
|
|
|
if(len > 100) {
|
|
// huge strings are made static to avoid long names
|
|
snprint(namebuf, sizeof(namebuf), ".gostring.%d", ++gen);
|
|
pkg = localpkg;
|
|
} else {
|
|
// small strings get named by their contents,
|
|
// so that multiple modules using the same string
|
|
// can share it.
|
|
tmp.lit.len = len;
|
|
memmove(tmp.lit.s, s, len);
|
|
tmp.lit.s[len] = '\0';
|
|
snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp.lit);
|
|
pkg = gostringpkg;
|
|
}
|
|
sym = pkglookup(namebuf, pkg);
|
|
|
|
// SymUniq flag indicates that data is generated already
|
|
if(sym->flags & SymUniq)
|
|
return sym;
|
|
sym->flags |= SymUniq;
|
|
sym->def = newname(sym);
|
|
|
|
off = 0;
|
|
|
|
// string header
|
|
off = dsymptr(sym, off, sym, widthptr+4);
|
|
off = duint32(sym, off, len);
|
|
|
|
// string data
|
|
for(n=0; n<len; n+=m) {
|
|
m = 8;
|
|
if(m > len-n)
|
|
m = len-n;
|
|
off = dsname(sym, off, s+n, m);
|
|
}
|
|
off = duint8(sym, off, 0); // terminating NUL for runtime
|
|
off = (off+widthptr-1)&~(widthptr-1); // round to pointer alignment
|
|
ggloblsym(sym, off, 1);
|
|
|
|
return sym;
|
|
}
|