summaryrefslogtreecommitdiff
path: root/src/cmd/gc/obj.c
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-09-13 13:13:40 +0200
committerOndřej Surý <ondrej@sury.org>2011-09-13 13:13:40 +0200
commit5ff4c17907d5b19510a62e08fd8d3b11e62b431d (patch)
treec0650497e988f47be9c6f2324fa692a52dea82e1 /src/cmd/gc/obj.c
parent80f18fc933cf3f3e829c5455a1023d69f7b86e52 (diff)
downloadgolang-upstream/60.tar.gz
Imported Upstream version 60upstream/60
Diffstat (limited to 'src/cmd/gc/obj.c')
-rw-r--r--src/cmd/gc/obj.c301
1 files changed, 301 insertions, 0 deletions
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
new file mode 100644
index 000000000..456aabb88
--- /dev/null
+++ b/src/cmd/gc/obj.c
@@ -0,0 +1,301 @@
+// 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 "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\n", getgoos(), thestring, getgoversion());
+ 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);
+
+ // add nil plist w AEND to catch
+ // auto-generated trampolines, data
+ newplist();
+
+ 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;
+ int i, depth = 0;
+ 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);
+ }
+ }
+ if(h->offset > 0) {
+ //line directive
+ depth++;
+ }
+ } else if(depth > 0) {
+ for(i = 0; i < depth; i++)
+ zhist(b, h->line, h->offset);
+ depth = 0;
+ }
+ 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);
+ pkg = gostringpkg;
+ }
+ sym = pkglookup(namebuf, pkg);
+
+ // SymUniq flag indicates that data is generated already
+ if(sym->flags & SymUniq)
+ return sym;
+ sym->flags |= SymUniq;
+
+ data();
+ 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);
+ text();
+
+ return sym;
+}