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