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 "go.h"
6
7 /*
8 * architecture-independent object file output
9 */
10
11 static void outhist(Biobuf *b);
12 static void dumpglobls(void);
13
14 void
15 dumpobj(void)
16 {
17 bout = Bopen(outfile, OWRITE);
18 if(bout == nil) {
19 flusherrors();
20 print("can't create %s: %r\n", outfile);
21 errorexit();
22 }
23
24 Bprint(bout, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
25 Bprint(bout, " exports automatically generated from\n");
26 Bprint(bout, " %s in package \"%s\"\n", curio.infile, localpkg->name);
27 dumpexport();
28 Bprint(bout, "\n!\n");
29
30 outhist(bout);
31
32 // add nil plist w AEND to catch
33 // auto-generated trampolines, data
34 newplist();
35
36 dumpglobls();
37 dumptypestructs();
38 dumpdata();
39 dumpfuncs();
40
41 Bterm(bout);
42 }
43
44 static void
45 dumpglobls(void)
46 {
47 Node *n;
48 NodeList *l;
49
50 // add globals
51 for(l=externdcl; l; l=l->next) {
52 n = l->n;
53 if(n->op != ONAME)
54 continue;
55
56 if(n->type == T)
57 fatal("external %#N nil type\n", n);
58 if(n->class == PFUNC)
59 continue;
60 if(n->sym->pkg != localpkg)
61 continue;
62 dowidth(n->type);
63
64 ggloblnod(n, n->type->width);
65 }
66 }
67
68 void
69 Bputname(Biobuf *b, Sym *s)
70 {
71 Bprint(b, "%s", s->pkg->prefix);
72 Bputc(b, '.');
73 Bwrite(b, s->name, strlen(s->name)+1);
74 }
75
76 static void
77 outzfile(Biobuf *b, char *p)
78 {
79 char *q, *q2;
80
81 while(p) {
82 q = utfrune(p, '/');
83 if(windows) {
84 q2 = utfrune(p, '\\');
85 if(q2 && (!q || q2 < q))
86 q = q2;
87 }
88 if(!q) {
89 zfile(b, p, strlen(p));
90 return;
91 }
92 if(q > p)
93 zfile(b, p, q-p);
94 p = q + 1;
95 }
96 }
97
98 #define isdelim(c) (c == '/' || c == '\\')
99
100 static void
101 outwinname(Biobuf *b, Hist *h, char *ds, char *p)
102 {
103 if(isdelim(p[0])) {
104 // full rooted name
105 zfile(b, ds, 3); // leading "c:/"
106 outzfile(b, p+1);
107 } else {
108 // relative name
109 if(h->offset == 0 && pathname && pathname[1] == ':') {
110 if(tolowerrune(ds[0]) == tolowerrune(pathname[0])) {
111 // using current drive
112 zfile(b, pathname, 3); // leading "c:/"
113 outzfile(b, pathname+3);
114 } else {
115 // using drive other then current,
116 // we don't have any simple way to
117 // determine current working directory
118 // there, therefore will output name as is
119 zfile(b, ds, 2); // leading "c:"
120 }
121 }
122 outzfile(b, p);
123 }
124 }
125
126 static void
127 outhist(Biobuf *b)
128 {
129 Hist *h;
130 char *p, ds[] = {'c', ':', '/', 0};
131
132 for(h = hist; h != H; h = h->link) {
133 p = h->name;
134 if(p) {
135 if(windows) {
136 // if windows variable is set, then, we know already,
137 // pathname is started with windows drive specifier
138 // and all '\' were replaced with '/' (see lex.c)
139 if(isdelim(p[0]) && isdelim(p[1])) {
140 // file name has network name in it,
141 // like \\server\share\dir\file.go
142 zfile(b, "//", 2); // leading "//"
143 outzfile(b, p+2);
144 } else if(p[1] == ':') {
145 // file name has drive letter in it
146 ds[0] = p[0];
147 outwinname(b, h, ds, p+2);
148 } else {
149 // no drive letter in file name
150 outwinname(b, h, pathname, p);
151 }
152 } else {
153 if(p[0] == '/') {
154 // full rooted name, like /home/rsc/dir/file.go
155 zfile(b, "/", 1); // leading "/"
156 outzfile(b, p+1);
157 } else {
158 // relative name, like dir/file.go
159 if(h->offset >= 0 && pathname && pathname[0] == '/') {
160 zfile(b, "/", 1); // leading "/"
161 outzfile(b, pathname+1);
162 }
163 outzfile(b, p);
164 }
165 }
166
167 }
168 zhist(b, h->line, h->offset);
169 }
170 }
171
172 void
173 ieeedtod(uint64 *ieee, double native)
174 {
175 double fr, ho, f;
176 int exp;
177 uint32 h, l;
178 uint64 bits;
179
180 if(native < 0) {
181 ieeedtod(ieee, -native);
182 *ieee |= 1ULL<<63;
183 return;
184 }
185 if(native == 0) {
186 *ieee = 0;
187 return;
188 }
189 fr = frexp(native, &exp);
190 f = 2097152L; /* shouldnt use fp constants here */
191 fr = modf(fr*f, &ho);
192 h = ho;
193 h &= 0xfffffL;
194 f = 65536L;
195 fr = modf(fr*f, &ho);
196 l = ho;
197 l <<= 16;
198 l |= (int32)(fr*f);
199 bits = ((uint64)h<<32) | l;
200 if(exp < -1021) {
201 // gradual underflow
202 bits |= 1LL<<52;
203 bits >>= -1021 - exp;
204 exp = -1022;
205 }
206 bits |= (uint64)(exp+1022L) << 52;
207 *ieee = bits;
208 }
209
210 int
211 duint8(Sym *s, int off, uint8 v)
212 {
213 return duintxx(s, off, v, 1);
214 }
215
216 int
217 duint16(Sym *s, int off, uint16 v)
218 {
219 return duintxx(s, off, v, 2);
220 }
221
222 int
223 duint32(Sym *s, int off, uint32 v)
224 {
225 return duintxx(s, off, v, 4);
226 }
227
228 int
229 duint64(Sym *s, int off, uint64 v)
230 {
231 return duintxx(s, off, v, 8);
232 }
233
234 int
235 duintptr(Sym *s, int off, uint64 v)
236 {
237 return duintxx(s, off, v, widthptr);
238 }
239
240 Sym*
241 stringsym(char *s, int len)
242 {
243 static int gen;
244 Sym *sym;
245 int off, n, m;
246 struct {
247 Strlit lit;
248 char buf[110];
249 } tmp;
250 Pkg *pkg;
251
252 if(len > 100) {
253 // huge strings are made static to avoid long names
254 snprint(namebuf, sizeof(namebuf), ".gostring.%d", ++gen);
255 pkg = localpkg;
256 } else {
257 // small strings get named by their contents,
258 // so that multiple modules using the same string
259 // can share it.
260 tmp.lit.len = len;
261 memmove(tmp.lit.s, s, len);
262 tmp.lit.s[len] = '\0';
263 snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp);
264 pkg = gostringpkg;
265 }
266 sym = pkglookup(namebuf, pkg);
267
268 // SymUniq flag indicates that data is generated already
269 if(sym->flags & SymUniq)
270 return sym;
271 sym->flags |= SymUniq;
272
273 data();
274 off = 0;
275
276 // string header
277 off = dsymptr(sym, off, sym, widthptr+4);
278 off = duint32(sym, off, len);
279
280 // string data
281 for(n=0; n<len; n+=m) {
282 m = 8;
283 if(m > len-n)
284 m = len-n;
285 off = dsname(sym, off, s+n, m);
286 }
287 off = duint8(sym, off, 0); // terminating NUL for runtime
288 off = (off+widthptr-1)&~(widthptr-1); // round to pointer alignment
289 ggloblsym(sym, off, 1);
290 text();
291
292 return sym;
293 }