root/src/cmd/gc/obj.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. formathdr
  2. dumpobj
  3. dumpglobls
  4. Bputname
  5. linksym
  6. duintxx
  7. duint8
  8. duint16
  9. duint32
  10. duint64
  11. duintptr
  12. stringsym
  13. slicebytes

// 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    dumpglobls(void);

enum
{
        ArhdrSize = 60
};

static void
formathdr(char *arhdr, char *name, vlong size)
{
        snprint(arhdr, ArhdrSize, "%-16s%-12d%-6d%-6d%-8o%-10lld`",
                name, 0, 0, 0, 0644, size);
        arhdr[ArhdrSize-1] = '\n'; // overwrite \0 written by snprint
}

void
dumpobj(void)
{
        NodeList *externs, *tmp;
        char arhdr[ArhdrSize];
        vlong startobj, size;
        Sym *zero;

        bout = Bopen(outfile, OWRITE);
        if(bout == nil) {
                flusherrors();
                print("can't create %s: %r\n", outfile);
                errorexit();
        }

        startobj = 0;
        if(writearchive) {
                Bwrite(bout, "!<arch>\n", 8);
                memset(arhdr, 0, sizeof arhdr);
                Bwrite(bout, arhdr, sizeof arhdr);
                startobj = Boffset(bout);
        }
        Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring());
        dumpexport();
        
        if(writearchive) {
                Bflush(bout);
                size = Boffset(bout) - startobj;
                if(size&1)
                        Bputc(bout, 0);
                Bseek(bout, startobj - ArhdrSize, 0);
                formathdr(arhdr, "__.PKGDEF", size);
                Bwrite(bout, arhdr, ArhdrSize);
                Bflush(bout);

                Bseek(bout, startobj + size + (size&1), 0);
                memset(arhdr, 0, ArhdrSize);
                Bwrite(bout, arhdr, ArhdrSize);
                startobj = Boffset(bout);
                Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring());
        }

        Bprint(bout, "\n!\n");

        externs = nil;
        if(externdcl != nil)
                externs = externdcl->end;

        dumpglobls();
        dumptypestructs();

        // Dump extra globals.
        tmp = externdcl;
        if(externs != nil)
                externdcl = externs->next;
        dumpglobls();
        externdcl = tmp;

        zero = pkglookup("zerovalue", runtimepkg);
        ggloblsym(zero, zerosize, 1, 1);

        dumpdata();
        writeobj(ctxt, bout);

        if(writearchive) {
                Bflush(bout);
                size = Boffset(bout) - startobj;
                if(size&1)
                        Bputc(bout, 0);
                Bseek(bout, startobj - ArhdrSize, 0);
                snprint(namebuf, sizeof namebuf, "_go_.%c", thechar);
                formathdr(arhdr, namebuf, size);
                Bwrite(bout, arhdr, ArhdrSize);
        }
        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);
        }
        
        for(l=funcsyms; l; l=l->next) {
                n = l->n;
                dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0);
                ggloblsym(n->sym, widthptr, 1, 1);
        }
        
        // Do not reprocess funcsyms on next dumpglobls call.
        funcsyms = nil;
}

void
Bputname(Biobuf *b, LSym *s)
{
        Bwrite(b, s->name, strlen(s->name)+1);
}

LSym*
linksym(Sym *s)
{
        char *p;

        if(s == nil)
                return nil;
        if(s->lsym != nil)
                return s->lsym;
        if(isblanksym(s))
                s->lsym = linklookup(ctxt, "_", 0);
        else {
                p = smprint("%s.%s", s->pkg->prefix, s->name);
                s->lsym = linklookup(ctxt, p, 0);
                free(p);
        }
        return s->lsym; 
}

int
duintxx(Sym *s, int off, uint64 v, int wid)
{
        // Update symbol data directly instead of generating a
        // DATA instruction that liblink will have to interpret later.
        // This reduces compilation time and memory usage.
        off = rnd(off, wid);
        return setuintxx(ctxt, linksym(s), off, v, wid);
}

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+widthint);
        off = duintxx(sym, off, len, widthint);
        
        // 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, 1);

        return sym;     
}

void
slicebytes(Node *nam, char *s, int len)
{
        int off, n, m;
        static int gen;
        Sym *sym;

        snprint(namebuf, sizeof(namebuf), ".gobytes.%d", ++gen);
        sym = pkglookup(namebuf, localpkg);
        sym->def = newname(sym);

        off = 0;
        for(n=0; n<len; n+=m) {
                m = 8;
                if(m > len-n)
                        m = len-n;
                off = dsname(sym, off, s+n, m);
        }
        ggloblsym(sym, off, 0, 0);
        
        if(nam->op != ONAME)
                fatal("slicebytes %N", nam);
        off = nam->xoffset;
        off = dsymptr(nam->sym, off, sym, 0);
        off = duintxx(nam->sym, off, len, widthint);
        duintxx(nam->sym, off, len, widthint);
}

/* [<][>][^][v][top][bottom][index][help] */