rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/cmd/7l/asm.go (about)

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