Home | History | Annotate | Download | only in arm64
      1 // Inferno utils/5l/asm.c
      2 // http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
      3 //
      4 //	Copyright  1994-1999 Lucent Technologies Inc.  All rights reserved.
      5 //	Portions Copyright  1995-1997 C H Forsyth (forsyth (a] 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 (a] 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 
     31 package arm64
     32 
     33 import (
     34 	"cmd/internal/obj"
     35 	"cmd/link/internal/ld"
     36 	"encoding/binary"
     37 	"fmt"
     38 	"log"
     39 )
     40 
     41 func gentext() {}
     42 
     43 func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
     44 	log.Fatalf("adddynrela not implemented")
     45 }
     46 
     47 func adddynrel(s *ld.LSym, r *ld.Reloc) {
     48 	log.Fatalf("adddynrel not implemented")
     49 }
     50 
     51 func elfreloc1(r *ld.Reloc, sectoff int64) int {
     52 	ld.Thearch.Vput(uint64(sectoff))
     53 
     54 	elfsym := r.Xsym.Elfsym
     55 	switch r.Type {
     56 	default:
     57 		return -1
     58 
     59 	case obj.R_ADDR:
     60 		switch r.Siz {
     61 		case 4:
     62 			ld.Thearch.Vput(ld.R_AARCH64_ABS32 | uint64(elfsym)<<32)
     63 		case 8:
     64 			ld.Thearch.Vput(ld.R_AARCH64_ABS64 | uint64(elfsym)<<32)
     65 		default:
     66 			return -1
     67 		}
     68 
     69 	case obj.R_ADDRARM64:
     70 		// two relocations: R_AARCH64_ADR_PREL_PG_HI21 and R_AARCH64_ADD_ABS_LO12_NC
     71 		ld.Thearch.Vput(ld.R_AARCH64_ADR_PREL_PG_HI21 | uint64(elfsym)<<32)
     72 		ld.Thearch.Vput(uint64(r.Xadd))
     73 		ld.Thearch.Vput(uint64(sectoff + 4))
     74 		ld.Thearch.Vput(ld.R_AARCH64_ADD_ABS_LO12_NC | uint64(elfsym)<<32)
     75 
     76 	case obj.R_CALLARM64:
     77 		if r.Siz != 4 {
     78 			return -1
     79 		}
     80 		ld.Thearch.Vput(ld.R_AARCH64_CALL26 | uint64(elfsym)<<32)
     81 
     82 	}
     83 	ld.Thearch.Vput(uint64(r.Xadd))
     84 
     85 	return 0
     86 }
     87 
     88 func elfsetupplt() {
     89 	// TODO(aram)
     90 	return
     91 }
     92 
     93 func machoreloc1(r *ld.Reloc, sectoff int64) int {
     94 	var v uint32
     95 
     96 	rs := r.Xsym
     97 
     98 	// ld64 has a bug handling MACHO_ARM64_RELOC_UNSIGNED with !extern relocation.
     99 	// see cmd/internal/ld/data.go for details. The workarond is that don't use !extern
    100 	// UNSIGNED relocation at all.
    101 	if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_CALLARM64 || r.Type == obj.R_ADDRARM64 || r.Type == obj.R_ADDR {
    102 		if rs.Dynid < 0 {
    103 			ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
    104 			return -1
    105 		}
    106 
    107 		v = uint32(rs.Dynid)
    108 		v |= 1 << 27 // external relocation
    109 	} else {
    110 		v = uint32(rs.Sect.Extnum)
    111 		if v == 0 {
    112 			ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
    113 			return -1
    114 		}
    115 	}
    116 
    117 	switch r.Type {
    118 	default:
    119 		return -1
    120 
    121 	case obj.R_ADDR:
    122 		v |= ld.MACHO_ARM64_RELOC_UNSIGNED << 28
    123 
    124 	case obj.R_CALLARM64:
    125 		if r.Xadd != 0 {
    126 			ld.Diag("ld64 doesn't allow BR26 reloc with non-zero addend: %s+%d", rs.Name, r.Xadd)
    127 		}
    128 
    129 		v |= 1 << 24 // pc-relative bit
    130 		v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28
    131 
    132 	case obj.R_ADDRARM64:
    133 		r.Siz = 4
    134 		// Two relocation entries: MACHO_ARM64_RELOC_PAGEOFF12 MACHO_ARM64_RELOC_PAGE21
    135 		// if r.Xadd is non-zero, add two MACHO_ARM64_RELOC_ADDEND.
    136 		if r.Xadd != 0 {
    137 			ld.Thearch.Lput(uint32(sectoff + 4))
    138 			ld.Thearch.Lput((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff))
    139 		}
    140 		ld.Thearch.Lput(uint32(sectoff + 4))
    141 		ld.Thearch.Lput(v | (ld.MACHO_ARM64_RELOC_PAGEOFF12 << 28) | (2 << 25))
    142 		if r.Xadd != 0 {
    143 			ld.Thearch.Lput(uint32(sectoff))
    144 			ld.Thearch.Lput((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff))
    145 		}
    146 		v |= 1 << 24 // pc-relative bit
    147 		v |= ld.MACHO_ARM64_RELOC_PAGE21 << 28
    148 	}
    149 
    150 	switch r.Siz {
    151 	default:
    152 		return -1
    153 
    154 	case 1:
    155 		v |= 0 << 25
    156 
    157 	case 2:
    158 		v |= 1 << 25
    159 
    160 	case 4:
    161 		v |= 2 << 25
    162 
    163 	case 8:
    164 		v |= 3 << 25
    165 	}
    166 
    167 	ld.Thearch.Lput(uint32(sectoff))
    168 	ld.Thearch.Lput(v)
    169 	return 0
    170 }
    171 
    172 func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
    173 	if ld.Linkmode == ld.LinkExternal {
    174 		switch r.Type {
    175 		default:
    176 			return -1
    177 
    178 		case obj.R_ADDRARM64:
    179 			r.Done = 0
    180 
    181 			// set up addend for eventual relocation via outer symbol.
    182 			rs := r.Sym
    183 			r.Xadd = r.Add
    184 			for rs.Outer != nil {
    185 				r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
    186 				rs = rs.Outer
    187 			}
    188 
    189 			if rs.Type != obj.SHOSTOBJ && rs.Sect == nil {
    190 				ld.Diag("missing section for %s", rs.Name)
    191 			}
    192 			r.Xsym = rs
    193 
    194 			// the first instruction is always at the lower address, this is endian neutral;
    195 			// but note that o0 and o1 should still use the target endian.
    196 			o0 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off : r.Off+4])
    197 			o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4 : r.Off+8])
    198 
    199 			// Note: ld64 currently has a bug that any non-zero addend for BR26 relocation
    200 			// will make the linking fail because it thinks the code is not PIC even though
    201 			// the BR26 relocation should be fully resolved at link time.
    202 			// That is the reason why the next if block is disabled. When the bug in ld64
    203 			// is fixed, we can enable this block and also enable duff's device in cmd/7g.
    204 			if false && ld.HEADTYPE == obj.Hdarwin {
    205 				// Mach-O wants the addend to be encoded in the instruction
    206 				// Note that although Mach-O supports ARM64_RELOC_ADDEND, it
    207 				// can only encode 24-bit of signed addend, but the instructions
    208 				// supports 33-bit of signed addend, so we always encode the
    209 				// addend in place.
    210 				o0 |= (uint32((r.Xadd>>12)&3) << 29) | (uint32((r.Xadd>>12>>2)&0x7ffff) << 5)
    211 				o1 |= uint32(r.Xadd&0xfff) << 10
    212 				r.Xadd = 0
    213 			}
    214 
    215 			// when laid out, the instruction order must always be o1, o2.
    216 			if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
    217 				*val = int64(o0)<<32 | int64(o1)
    218 			} else {
    219 				*val = int64(o1)<<32 | int64(o0)
    220 			}
    221 
    222 			return 0
    223 
    224 		case obj.R_CALLARM64:
    225 			r.Done = 0
    226 			r.Xsym = r.Sym
    227 			*val = int64(0xfc000000 & uint32(r.Add))
    228 			r.Xadd = int64((uint32(r.Add) &^ 0xfc000000) * 4)
    229 			r.Add = 0
    230 			return 0
    231 		}
    232 	}
    233 
    234 	switch r.Type {
    235 	case obj.R_CONST:
    236 		*val = r.Add
    237 		return 0
    238 
    239 	case obj.R_GOTOFF:
    240 		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
    241 		return 0
    242 
    243 	case obj.R_ADDRARM64:
    244 		t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
    245 		if t >= 1<<32 || t < -1<<32 {
    246 			ld.Diag("program too large, address relocation distance = %d", t)
    247 		}
    248 
    249 		// the first instruction is always at the lower address, this is endian neutral;
    250 		// but note that o0 and o1 should still use the target endian.
    251 		o0 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off : r.Off+4])
    252 		o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4 : r.Off+8])
    253 
    254 		o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
    255 		o1 |= uint32(t&0xfff) << 10
    256 
    257 		// when laid out, the instruction order must always be o1, o2.
    258 		if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
    259 			*val = int64(o0)<<32 | int64(o1)
    260 		} else {
    261 			*val = int64(o1)<<32 | int64(o0)
    262 		}
    263 		return 0
    264 
    265 	case obj.R_CALLARM64:
    266 		*val = int64((0xfc000000 & uint32(r.Add)) | uint32((ld.Symaddr(r.Sym)+r.Add*4-(s.Value+int64(r.Off)))/4))
    267 		return 0
    268 	}
    269 
    270 	return -1
    271 }
    272 
    273 func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
    274 	log.Fatalf("unexpected relocation variant")
    275 	return -1
    276 }
    277 
    278 func asmb() {
    279 	if ld.Debug['v'] != 0 {
    280 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
    281 	}
    282 	ld.Bso.Flush()
    283 
    284 	if ld.Iself {
    285 		ld.Asmbelfsetup()
    286 	}
    287 
    288 	sect := ld.Segtext.Sect
    289 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
    290 	ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
    291 	for sect = sect.Next; sect != nil; sect = sect.Next {
    292 		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
    293 		ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
    294 	}
    295 
    296 	if ld.Segrodata.Filelen > 0 {
    297 		if ld.Debug['v'] != 0 {
    298 			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
    299 		}
    300 		ld.Bso.Flush()
    301 
    302 		ld.Cseek(int64(ld.Segrodata.Fileoff))
    303 		ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
    304 	}
    305 
    306 	if ld.Debug['v'] != 0 {
    307 		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
    308 	}
    309 	ld.Bso.Flush()
    310 
    311 	ld.Cseek(int64(ld.Segdata.Fileoff))
    312 	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
    313 
    314 	machlink := uint32(0)
    315 	if ld.HEADTYPE == obj.Hdarwin {
    316 		if ld.Debug['v'] != 0 {
    317 			fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
    318 		}
    319 
    320 		dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
    321 		ld.Cseek(int64(dwarfoff))
    322 
    323 		ld.Segdwarf.Fileoff = uint64(ld.Cpos())
    324 		ld.Dwarfemitdebugsections()
    325 		ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
    326 
    327 		machlink = uint32(ld.Domacholink())
    328 	}
    329 
    330 	/* output symbol table */
    331 	ld.Symsize = 0
    332 
    333 	ld.Lcsize = 0
    334 	symo := uint32(0)
    335 	if ld.Debug['s'] == 0 {
    336 		// TODO: rationalize
    337 		if ld.Debug['v'] != 0 {
    338 			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
    339 		}
    340 		ld.Bso.Flush()
    341 		switch ld.HEADTYPE {
    342 		default:
    343 			if ld.Iself {
    344 				symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
    345 				symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
    346 			}
    347 
    348 		case obj.Hplan9:
    349 			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
    350 
    351 		case obj.Hdarwin:
    352 			symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
    353 		}
    354 
    355 		ld.Cseek(int64(symo))
    356 		switch ld.HEADTYPE {
    357 		default:
    358 			if ld.Iself {
    359 				if ld.Debug['v'] != 0 {
    360 					fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
    361 				}
    362 				ld.Asmelfsym()
    363 				ld.Cflush()
    364 				ld.Cwrite(ld.Elfstrdat)
    365 
    366 				if ld.Debug['v'] != 0 {
    367 					fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
    368 				}
    369 				ld.Dwarfemitdebugsections()
    370 
    371 				if ld.Linkmode == ld.LinkExternal {
    372 					ld.Elfemitreloc()
    373 				}
    374 			}
    375 
    376 		case obj.Hplan9:
    377 			ld.Asmplan9sym()
    378 			ld.Cflush()
    379 
    380 			sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
    381 			if sym != nil {
    382 				ld.Lcsize = int32(len(sym.P))
    383 				for i := 0; int32(i) < ld.Lcsize; i++ {
    384 					ld.Cput(uint8(sym.P[i]))
    385 				}
    386 
    387 				ld.Cflush()
    388 			}
    389 
    390 		case obj.Hdarwin:
    391 			if ld.Linkmode == ld.LinkExternal {
    392 				ld.Machoemitreloc()
    393 			}
    394 		}
    395 	}
    396 
    397 	ld.Ctxt.Cursym = nil
    398 	if ld.Debug['v'] != 0 {
    399 		fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
    400 	}
    401 	ld.Bso.Flush()
    402 	ld.Cseek(0)
    403 	switch ld.HEADTYPE {
    404 	default:
    405 	case obj.Hplan9: /* plan 9 */
    406 		ld.Thearch.Lput(0x647)                      /* magic */
    407 		ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
    408 		ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
    409 		ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
    410 		ld.Thearch.Lput(uint32(ld.Symsize))      /* nsyms */
    411 		ld.Thearch.Lput(uint32(ld.Entryvalue())) /* va of entry */
    412 		ld.Thearch.Lput(0)
    413 		ld.Thearch.Lput(uint32(ld.Lcsize))
    414 
    415 	case obj.Hlinux,
    416 		obj.Hfreebsd,
    417 		obj.Hnetbsd,
    418 		obj.Hopenbsd,
    419 		obj.Hnacl:
    420 		ld.Asmbelf(int64(symo))
    421 
    422 	case obj.Hdarwin:
    423 		ld.Asmbmacho()
    424 	}
    425 
    426 	ld.Cflush()
    427 	if ld.Debug['c'] != 0 {
    428 		fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
    429 		fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
    430 		fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
    431 		fmt.Printf("symsize=%d\n", ld.Symsize)
    432 		fmt.Printf("lcsize=%d\n", ld.Lcsize)
    433 		fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
    434 	}
    435 }
    436