1// Inferno utils/5l/asm.c
2// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
3//
4//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
5//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6//	Portions Copyright © 1997-1999 Vita Nuova Limited
7//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8//	Portions Copyright © 2004,2006 Bruce Ellis
9//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11//	Portions Copyright © 2009 The Go Authors. All rights reserved.
12//
13// Permission is hereby granted, free of charge, to any person obtaining a copy
14// of this software and associated documentation files (the "Software"), to deal
15// in the Software without restriction, including without limitation the rights
16// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17// copies of the Software, and to permit persons to whom the Software is
18// furnished to do so, subject to the following conditions:
19//
20// The above copyright notice and this permission notice shall be included in
21// all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
26// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29// THE SOFTWARE.
30
31package mips64
32
33import (
34	"cmd/internal/objabi"
35	"cmd/internal/sys"
36	"cmd/link/internal/ld"
37	"fmt"
38	"log"
39)
40
41func gentext(ctxt *ld.Link) {}
42
43func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
44	log.Fatalf("adddynrel not implemented")
45	return false
46}
47
48func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
49	// mips64 ELF relocation (endian neutral)
50	//		offset	uint64
51	//		sym		uint32
52	//		ssym	uint8
53	//		type3	uint8
54	//		type2	uint8
55	//		type	uint8
56	//		addend	int64
57
58	ld.Thearch.Vput(uint64(sectoff))
59
60	elfsym := r.Xsym.ElfsymForReloc()
61	ld.Thearch.Lput(uint32(elfsym))
62	ld.Cput(0)
63	ld.Cput(0)
64	ld.Cput(0)
65	switch r.Type {
66	default:
67		return -1
68
69	case objabi.R_ADDR:
70		switch r.Siz {
71		case 4:
72			ld.Cput(ld.R_MIPS_32)
73		case 8:
74			ld.Cput(ld.R_MIPS_64)
75		default:
76			return -1
77		}
78
79	case objabi.R_ADDRMIPS:
80		ld.Cput(ld.R_MIPS_LO16)
81
82	case objabi.R_ADDRMIPSU:
83		ld.Cput(ld.R_MIPS_HI16)
84
85	case objabi.R_ADDRMIPSTLS:
86		ld.Cput(ld.R_MIPS_TLS_TPREL_LO16)
87
88	case objabi.R_CALLMIPS,
89		objabi.R_JMPMIPS:
90		ld.Cput(ld.R_MIPS_26)
91	}
92	ld.Thearch.Vput(uint64(r.Xadd))
93
94	return 0
95}
96
97func elfsetupplt(ctxt *ld.Link) {
98	return
99}
100
101func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
102	return -1
103}
104
105func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
106	if ld.Linkmode == ld.LinkExternal {
107		switch r.Type {
108		default:
109			return -1
110
111		case objabi.R_ADDRMIPS,
112			objabi.R_ADDRMIPSU:
113			r.Done = 0
114
115			// set up addend for eventual relocation via outer symbol.
116			rs := r.Sym
117			r.Xadd = r.Add
118			for rs.Outer != nil {
119				r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
120				rs = rs.Outer
121			}
122
123			if rs.Type != ld.SHOSTOBJ && rs.Type != ld.SDYNIMPORT && rs.Sect == nil {
124				ld.Errorf(s, "missing section for %s", rs.Name)
125			}
126			r.Xsym = rs
127
128			return 0
129
130		case objabi.R_ADDRMIPSTLS,
131			objabi.R_CALLMIPS,
132			objabi.R_JMPMIPS:
133			r.Done = 0
134			r.Xsym = r.Sym
135			r.Xadd = r.Add
136			return 0
137		}
138	}
139
140	switch r.Type {
141	case objabi.R_CONST:
142		*val = r.Add
143		return 0
144
145	case objabi.R_GOTOFF:
146		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
147		return 0
148
149	case objabi.R_ADDRMIPS,
150		objabi.R_ADDRMIPSU:
151		t := ld.Symaddr(r.Sym) + r.Add
152		o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
153		if r.Type == objabi.R_ADDRMIPS {
154			*val = int64(o1&0xffff0000 | uint32(t)&0xffff)
155		} else {
156			*val = int64(o1&0xffff0000 | uint32((t+1<<15)>>16)&0xffff)
157		}
158		return 0
159
160	case objabi.R_ADDRMIPSTLS:
161		// thread pointer is at 0x7000 offset from the start of TLS data area
162		t := ld.Symaddr(r.Sym) + r.Add - 0x7000
163		if t < -32768 || t >= 32678 {
164			ld.Errorf(s, "TLS offset out of range %d", t)
165		}
166		o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
167		*val = int64(o1&0xffff0000 | uint32(t)&0xffff)
168		return 0
169
170	case objabi.R_CALLMIPS,
171		objabi.R_JMPMIPS:
172		// Low 26 bits = (S + A) >> 2
173		t := ld.Symaddr(r.Sym) + r.Add
174		o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
175		*val = int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000)
176		return 0
177	}
178
179	return -1
180}
181
182func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 {
183	return -1
184}
185
186func asmb(ctxt *ld.Link) {
187	if ctxt.Debugvlog != 0 {
188		ctxt.Logf("%5.2f asmb\n", ld.Cputime())
189	}
190
191	if ld.Iself {
192		ld.Asmbelfsetup()
193	}
194
195	sect := ld.Segtext.Sections[0]
196	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
197	ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
198	for _, sect = range ld.Segtext.Sections[1:] {
199		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
200		ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
201	}
202
203	if ld.Segrodata.Filelen > 0 {
204		if ctxt.Debugvlog != 0 {
205			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
206		}
207		ld.Cseek(int64(ld.Segrodata.Fileoff))
208		ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
209	}
210	if ld.Segrelrodata.Filelen > 0 {
211		if ctxt.Debugvlog != 0 {
212			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
213		}
214		ld.Cseek(int64(ld.Segrelrodata.Fileoff))
215		ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
216	}
217
218	if ctxt.Debugvlog != 0 {
219		ctxt.Logf("%5.2f datblk\n", ld.Cputime())
220	}
221
222	ld.Cseek(int64(ld.Segdata.Fileoff))
223	ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
224
225	ld.Cseek(int64(ld.Segdwarf.Fileoff))
226	ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
227
228	/* output symbol table */
229	ld.Symsize = 0
230
231	ld.Lcsize = 0
232	symo := uint32(0)
233	if !*ld.FlagS {
234		// TODO: rationalize
235		if ctxt.Debugvlog != 0 {
236			ctxt.Logf("%5.2f sym\n", ld.Cputime())
237		}
238		switch ld.Headtype {
239		default:
240			if ld.Iself {
241				symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
242				symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
243			}
244
245		case objabi.Hplan9:
246			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
247		}
248
249		ld.Cseek(int64(symo))
250		switch ld.Headtype {
251		default:
252			if ld.Iself {
253				if ctxt.Debugvlog != 0 {
254					ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
255				}
256				ld.Asmelfsym(ctxt)
257				ld.Cflush()
258				ld.Cwrite(ld.Elfstrdat)
259
260				if ld.Linkmode == ld.LinkExternal {
261					ld.Elfemitreloc(ctxt)
262				}
263			}
264
265		case objabi.Hplan9:
266			ld.Asmplan9sym(ctxt)
267			ld.Cflush()
268
269			sym := ctxt.Syms.Lookup("pclntab", 0)
270			if sym != nil {
271				ld.Lcsize = int32(len(sym.P))
272				for i := 0; int32(i) < ld.Lcsize; i++ {
273					ld.Cput(sym.P[i])
274				}
275
276				ld.Cflush()
277			}
278		}
279	}
280
281	if ctxt.Debugvlog != 0 {
282		ctxt.Logf("%5.2f header\n", ld.Cputime())
283	}
284	ld.Cseek(0)
285	switch ld.Headtype {
286	default:
287	case objabi.Hplan9: /* plan 9 */
288		magic := uint32(4*18*18 + 7)
289		if ld.SysArch == sys.ArchMIPS64LE {
290			magic = uint32(4*26*26 + 7)
291		}
292		ld.Thearch.Lput(magic)                      /* magic */
293		ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
294		ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
295		ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
296		ld.Thearch.Lput(uint32(ld.Symsize))          /* nsyms */
297		ld.Thearch.Lput(uint32(ld.Entryvalue(ctxt))) /* va of entry */
298		ld.Thearch.Lput(0)
299		ld.Thearch.Lput(uint32(ld.Lcsize))
300
301	case objabi.Hlinux,
302		objabi.Hfreebsd,
303		objabi.Hnetbsd,
304		objabi.Hopenbsd,
305		objabi.Hnacl:
306		ld.Asmbelf(ctxt, int64(symo))
307	}
308
309	ld.Cflush()
310	if *ld.FlagC {
311		fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
312		fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
313		fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
314		fmt.Printf("symsize=%d\n", ld.Symsize)
315		fmt.Printf("lcsize=%d\n", ld.Lcsize)
316		fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
317	}
318}
319