github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/src/cmd/link/internal/arm64/asm.go (about)

     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  
    31  package arm64
    32  
    33  import (
    34  	"cmd/internal/objabi"
    35  	"cmd/link/internal/ld"
    36  	"encoding/binary"
    37  	"fmt"
    38  	"log"
    39  )
    40  
    41  func gentext(ctxt *ld.Link) {
    42  	if !ctxt.DynlinkingGo() {
    43  		return
    44  	}
    45  	addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
    46  	if addmoduledata.Type == ld.STEXT {
    47  		// we're linking a module containing the runtime -> no need for
    48  		// an init function
    49  		return
    50  	}
    51  	addmoduledata.Attr |= ld.AttrReachable
    52  	initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
    53  	initfunc.Type = ld.STEXT
    54  	initfunc.Attr |= ld.AttrLocal
    55  	initfunc.Attr |= ld.AttrReachable
    56  	o := func(op uint32) {
    57  		ld.Adduint32(ctxt, initfunc, op)
    58  	}
    59  	// 0000000000000000 <local.dso_init>:
    60  	// 0:	90000000 	adrp	x0, 0 <runtime.firstmoduledata>
    61  	// 	0: R_AARCH64_ADR_PREL_PG_HI21	local.moduledata
    62  	// 4:	91000000 	add	x0, x0, #0x0
    63  	// 	4: R_AARCH64_ADD_ABS_LO12_NC	local.moduledata
    64  	o(0x90000000)
    65  	o(0x91000000)
    66  	rel := ld.Addrel(initfunc)
    67  	rel.Off = 0
    68  	rel.Siz = 8
    69  	rel.Sym = ctxt.Moduledata
    70  	rel.Type = objabi.R_ADDRARM64
    71  
    72  	// 8:	14000000 	bl	0 <runtime.addmoduledata>
    73  	// 	8: R_AARCH64_CALL26	runtime.addmoduledata
    74  	o(0x14000000)
    75  	rel = ld.Addrel(initfunc)
    76  	rel.Off = 8
    77  	rel.Siz = 4
    78  	rel.Sym = ctxt.Syms.Lookup("runtime.addmoduledata", 0)
    79  	rel.Type = objabi.R_CALLARM64 // Really should be R_AARCH64_JUMP26 but doesn't seem to make any difference
    80  
    81  	ctxt.Textp = append(ctxt.Textp, initfunc)
    82  	initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
    83  	initarray_entry.Attr |= ld.AttrReachable
    84  	initarray_entry.Attr |= ld.AttrLocal
    85  	initarray_entry.Type = ld.SINITARR
    86  	ld.Addaddr(ctxt, initarray_entry, initfunc)
    87  }
    88  
    89  func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
    90  	log.Fatalf("adddynrel not implemented")
    91  	return false
    92  }
    93  
    94  func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) bool {
    95  	ld.Thearch.Vput(uint64(sectoff))
    96  
    97  	elfsym := r.Xsym.ElfsymForReloc()
    98  	switch r.Type {
    99  	default:
   100  		return false
   101  	case objabi.R_ADDR:
   102  		switch r.Siz {
   103  		case 4:
   104  			ld.Thearch.Vput(ld.R_AARCH64_ABS32 | uint64(elfsym)<<32)
   105  		case 8:
   106  			ld.Thearch.Vput(ld.R_AARCH64_ABS64 | uint64(elfsym)<<32)
   107  		default:
   108  			return false
   109  		}
   110  	case objabi.R_ADDRARM64:
   111  		// two relocations: R_AARCH64_ADR_PREL_PG_HI21 and R_AARCH64_ADD_ABS_LO12_NC
   112  		ld.Thearch.Vput(ld.R_AARCH64_ADR_PREL_PG_HI21 | uint64(elfsym)<<32)
   113  		ld.Thearch.Vput(uint64(r.Xadd))
   114  		ld.Thearch.Vput(uint64(sectoff + 4))
   115  		ld.Thearch.Vput(ld.R_AARCH64_ADD_ABS_LO12_NC | uint64(elfsym)<<32)
   116  	case objabi.R_ARM64_TLS_LE:
   117  		ld.Thearch.Vput(ld.R_AARCH64_TLSLE_MOVW_TPREL_G0 | uint64(elfsym)<<32)
   118  	case objabi.R_ARM64_TLS_IE:
   119  		ld.Thearch.Vput(ld.R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 | uint64(elfsym)<<32)
   120  		ld.Thearch.Vput(uint64(r.Xadd))
   121  		ld.Thearch.Vput(uint64(sectoff + 4))
   122  		ld.Thearch.Vput(ld.R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC | uint64(elfsym)<<32)
   123  	case objabi.R_ARM64_GOTPCREL:
   124  		ld.Thearch.Vput(ld.R_AARCH64_ADR_GOT_PAGE | uint64(elfsym)<<32)
   125  		ld.Thearch.Vput(uint64(r.Xadd))
   126  		ld.Thearch.Vput(uint64(sectoff + 4))
   127  		ld.Thearch.Vput(ld.R_AARCH64_LD64_GOT_LO12_NC | uint64(elfsym)<<32)
   128  	case objabi.R_CALLARM64:
   129  		if r.Siz != 4 {
   130  			return false
   131  		}
   132  		ld.Thearch.Vput(ld.R_AARCH64_CALL26 | uint64(elfsym)<<32)
   133  
   134  	}
   135  	ld.Thearch.Vput(uint64(r.Xadd))
   136  
   137  	return true
   138  }
   139  
   140  func elfsetupplt(ctxt *ld.Link) {
   141  	// TODO(aram)
   142  	return
   143  }
   144  
   145  func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) bool {
   146  	var v uint32
   147  
   148  	rs := r.Xsym
   149  
   150  	// ld64 has a bug handling MACHO_ARM64_RELOC_UNSIGNED with !extern relocation.
   151  	// see cmd/internal/ld/data.go for details. The workaround is that don't use !extern
   152  	// UNSIGNED relocation at all.
   153  	if rs.Type == ld.SHOSTOBJ || r.Type == objabi.R_CALLARM64 || r.Type == objabi.R_ADDRARM64 || r.Type == objabi.R_ADDR {
   154  		if rs.Dynid < 0 {
   155  			ld.Errorf(s, "reloc %d (%s) to non-macho symbol %s type=%d (%s)", r.Type, ld.RelocName(r.Type), rs.Name, rs.Type, rs.Type)
   156  			return false
   157  		}
   158  
   159  		v = uint32(rs.Dynid)
   160  		v |= 1 << 27 // external relocation
   161  	} else {
   162  		v = uint32(rs.Sect.Extnum)
   163  		if v == 0 {
   164  			ld.Errorf(s, "reloc %d (%s) to symbol %s in non-macho section %s type=%d (%s)", r.Type, ld.RelocName(r.Type), rs.Name, rs.Sect.Name, rs.Type, rs.Type)
   165  			return false
   166  		}
   167  	}
   168  
   169  	switch r.Type {
   170  	default:
   171  		return false
   172  	case objabi.R_ADDR:
   173  		v |= ld.MACHO_ARM64_RELOC_UNSIGNED << 28
   174  	case objabi.R_CALLARM64:
   175  		if r.Xadd != 0 {
   176  			ld.Errorf(s, "ld64 doesn't allow BR26 reloc with non-zero addend: %s+%d", rs.Name, r.Xadd)
   177  		}
   178  
   179  		v |= 1 << 24 // pc-relative bit
   180  		v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28
   181  	case objabi.R_ADDRARM64:
   182  		r.Siz = 4
   183  		// Two relocation entries: MACHO_ARM64_RELOC_PAGEOFF12 MACHO_ARM64_RELOC_PAGE21
   184  		// if r.Xadd is non-zero, add two MACHO_ARM64_RELOC_ADDEND.
   185  		if r.Xadd != 0 {
   186  			ld.Thearch.Lput(uint32(sectoff + 4))
   187  			ld.Thearch.Lput((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff))
   188  		}
   189  		ld.Thearch.Lput(uint32(sectoff + 4))
   190  		ld.Thearch.Lput(v | (ld.MACHO_ARM64_RELOC_PAGEOFF12 << 28) | (2 << 25))
   191  		if r.Xadd != 0 {
   192  			ld.Thearch.Lput(uint32(sectoff))
   193  			ld.Thearch.Lput((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff))
   194  		}
   195  		v |= 1 << 24 // pc-relative bit
   196  		v |= ld.MACHO_ARM64_RELOC_PAGE21 << 28
   197  	}
   198  
   199  	switch r.Siz {
   200  	default:
   201  		return false
   202  	case 1:
   203  		v |= 0 << 25
   204  	case 2:
   205  		v |= 1 << 25
   206  	case 4:
   207  		v |= 2 << 25
   208  	case 8:
   209  		v |= 3 << 25
   210  	}
   211  
   212  	ld.Thearch.Lput(uint32(sectoff))
   213  	ld.Thearch.Lput(v)
   214  	return true
   215  }
   216  
   217  func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) bool {
   218  	if ld.Linkmode == ld.LinkExternal {
   219  		switch r.Type {
   220  		default:
   221  			return false
   222  		case objabi.R_ARM64_GOTPCREL:
   223  			var o1, o2 uint32
   224  			if ctxt.Arch.ByteOrder == binary.BigEndian {
   225  				o1 = uint32(*val >> 32)
   226  				o2 = uint32(*val)
   227  			} else {
   228  				o1 = uint32(*val)
   229  				o2 = uint32(*val >> 32)
   230  			}
   231  			// Any relocation against a function symbol is redirected to
   232  			// be against a local symbol instead (see putelfsym in
   233  			// symtab.go) but unfortunately the system linker was buggy
   234  			// when confronted with a R_AARCH64_ADR_GOT_PAGE relocation
   235  			// against a local symbol until May 2015
   236  			// (https://sourceware.org/bugzilla/show_bug.cgi?id=18270). So
   237  			// we convert the adrp; ld64 + R_ARM64_GOTPCREL into adrp;
   238  			// add + R_ADDRARM64.
   239  			if !(r.Sym.Version != 0 || (r.Sym.Type&ld.SHIDDEN != 0) || r.Sym.Attr.Local()) && r.Sym.Type == ld.STEXT && ctxt.DynlinkingGo() {
   240  				if o2&0xffc00000 != 0xf9400000 {
   241  					ld.Errorf(s, "R_ARM64_GOTPCREL against unexpected instruction %x", o2)
   242  				}
   243  				o2 = 0x91000000 | (o2 & 0x000003ff)
   244  				r.Type = objabi.R_ADDRARM64
   245  			}
   246  			if ctxt.Arch.ByteOrder == binary.BigEndian {
   247  				*val = int64(o1)<<32 | int64(o2)
   248  			} else {
   249  				*val = int64(o2)<<32 | int64(o1)
   250  			}
   251  			fallthrough
   252  		case objabi.R_ADDRARM64:
   253  			r.Done = false
   254  
   255  			// set up addend for eventual relocation via outer symbol.
   256  			rs := r.Sym
   257  			r.Xadd = r.Add
   258  			for rs.Outer != nil {
   259  				r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
   260  				rs = rs.Outer
   261  			}
   262  
   263  			if rs.Type != ld.SHOSTOBJ && rs.Type != ld.SDYNIMPORT && rs.Sect == nil {
   264  				ld.Errorf(s, "missing section for %s", rs.Name)
   265  			}
   266  			r.Xsym = rs
   267  
   268  			// Note: ld64 currently has a bug that any non-zero addend for BR26 relocation
   269  			// will make the linking fail because it thinks the code is not PIC even though
   270  			// the BR26 relocation should be fully resolved at link time.
   271  			// That is the reason why the next if block is disabled. When the bug in ld64
   272  			// is fixed, we can enable this block and also enable duff's device in cmd/7g.
   273  			if false && ld.Headtype == objabi.Hdarwin {
   274  				var o0, o1 uint32
   275  
   276  				if ctxt.Arch.ByteOrder == binary.BigEndian {
   277  					o0 = uint32(*val >> 32)
   278  					o1 = uint32(*val)
   279  				} else {
   280  					o0 = uint32(*val)
   281  					o1 = uint32(*val >> 32)
   282  				}
   283  				// Mach-O wants the addend to be encoded in the instruction
   284  				// Note that although Mach-O supports ARM64_RELOC_ADDEND, it
   285  				// can only encode 24-bit of signed addend, but the instructions
   286  				// supports 33-bit of signed addend, so we always encode the
   287  				// addend in place.
   288  				o0 |= (uint32((r.Xadd>>12)&3) << 29) | (uint32((r.Xadd>>12>>2)&0x7ffff) << 5)
   289  				o1 |= uint32(r.Xadd&0xfff) << 10
   290  				r.Xadd = 0
   291  
   292  				// when laid out, the instruction order must always be o1, o2.
   293  				if ctxt.Arch.ByteOrder == binary.BigEndian {
   294  					*val = int64(o0)<<32 | int64(o1)
   295  				} else {
   296  					*val = int64(o1)<<32 | int64(o0)
   297  				}
   298  			}
   299  
   300  			return true
   301  		case objabi.R_CALLARM64,
   302  			objabi.R_ARM64_TLS_LE,
   303  			objabi.R_ARM64_TLS_IE:
   304  			r.Done = false
   305  			r.Xsym = r.Sym
   306  			r.Xadd = r.Add
   307  			return true
   308  		}
   309  	}
   310  
   311  	switch r.Type {
   312  	case objabi.R_CONST:
   313  		*val = r.Add
   314  		return true
   315  	case objabi.R_GOTOFF:
   316  		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
   317  		return true
   318  	case objabi.R_ADDRARM64:
   319  		t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
   320  		if t >= 1<<32 || t < -1<<32 {
   321  			ld.Errorf(s, "program too large, address relocation distance = %d", t)
   322  		}
   323  
   324  		var o0, o1 uint32
   325  
   326  		if ctxt.Arch.ByteOrder == binary.BigEndian {
   327  			o0 = uint32(*val >> 32)
   328  			o1 = uint32(*val)
   329  		} else {
   330  			o0 = uint32(*val)
   331  			o1 = uint32(*val >> 32)
   332  		}
   333  
   334  		o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
   335  		o1 |= uint32(t&0xfff) << 10
   336  
   337  		// when laid out, the instruction order must always be o1, o2.
   338  		if ctxt.Arch.ByteOrder == binary.BigEndian {
   339  			*val = int64(o0)<<32 | int64(o1)
   340  		} else {
   341  			*val = int64(o1)<<32 | int64(o0)
   342  		}
   343  		return true
   344  	case objabi.R_ARM64_TLS_LE:
   345  		r.Done = false
   346  		if ld.Headtype != objabi.Hlinux {
   347  			ld.Errorf(s, "TLS reloc on unsupported OS %v", ld.Headtype)
   348  		}
   349  		// The TCB is two pointers. This is not documented anywhere, but is
   350  		// de facto part of the ABI.
   351  		v := r.Sym.Value + int64(2*ld.SysArch.PtrSize)
   352  		if v < 0 || v >= 32678 {
   353  			ld.Errorf(s, "TLS offset out of range %d", v)
   354  		}
   355  		*val |= v << 5
   356  		return true
   357  	case objabi.R_CALLARM64:
   358  		t := (ld.Symaddr(r.Sym) + r.Add) - (s.Value + int64(r.Off))
   359  		if t >= 1<<27 || t < -1<<27 {
   360  			ld.Errorf(s, "program too large, call relocation distance = %d", t)
   361  		}
   362  		*val |= (t >> 2) & 0x03ffffff
   363  		return true
   364  	}
   365  
   366  	return false
   367  }
   368  
   369  func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 {
   370  	log.Fatalf("unexpected relocation variant")
   371  	return -1
   372  }
   373  
   374  func asmb(ctxt *ld.Link) {
   375  	if ctxt.Debugvlog != 0 {
   376  		ctxt.Logf("%5.2f asmb\n", ld.Cputime())
   377  	}
   378  
   379  	if ld.Iself {
   380  		ld.Asmbelfsetup()
   381  	}
   382  
   383  	sect := ld.Segtext.Sections[0]
   384  	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
   385  	ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
   386  	for _, sect = range ld.Segtext.Sections[1:] {
   387  		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
   388  		ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
   389  	}
   390  
   391  	if ld.Segrodata.Filelen > 0 {
   392  		if ctxt.Debugvlog != 0 {
   393  			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
   394  		}
   395  		ld.Cseek(int64(ld.Segrodata.Fileoff))
   396  		ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
   397  	}
   398  	if ld.Segrelrodata.Filelen > 0 {
   399  		if ctxt.Debugvlog != 0 {
   400  			ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
   401  		}
   402  		ld.Cseek(int64(ld.Segrelrodata.Fileoff))
   403  		ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
   404  	}
   405  
   406  	if ctxt.Debugvlog != 0 {
   407  		ctxt.Logf("%5.2f datblk\n", ld.Cputime())
   408  	}
   409  
   410  	ld.Cseek(int64(ld.Segdata.Fileoff))
   411  	ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
   412  
   413  	ld.Cseek(int64(ld.Segdwarf.Fileoff))
   414  	ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
   415  
   416  	machlink := uint32(0)
   417  	if ld.Headtype == objabi.Hdarwin {
   418  		machlink = uint32(ld.Domacholink(ctxt))
   419  	}
   420  
   421  	/* output symbol table */
   422  	ld.Symsize = 0
   423  
   424  	ld.Lcsize = 0
   425  	symo := uint32(0)
   426  	if !*ld.FlagS {
   427  		// TODO: rationalize
   428  		if ctxt.Debugvlog != 0 {
   429  			ctxt.Logf("%5.2f sym\n", ld.Cputime())
   430  		}
   431  		switch ld.Headtype {
   432  		default:
   433  			if ld.Iself {
   434  				symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
   435  				symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
   436  			}
   437  
   438  		case objabi.Hplan9:
   439  			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
   440  
   441  		case objabi.Hdarwin:
   442  			symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
   443  		}
   444  
   445  		ld.Cseek(int64(symo))
   446  		switch ld.Headtype {
   447  		default:
   448  			if ld.Iself {
   449  				if ctxt.Debugvlog != 0 {
   450  					ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
   451  				}
   452  				ld.Asmelfsym(ctxt)
   453  				ld.Cflush()
   454  				ld.Cwrite(ld.Elfstrdat)
   455  
   456  				if ld.Linkmode == ld.LinkExternal {
   457  					ld.Elfemitreloc(ctxt)
   458  				}
   459  			}
   460  
   461  		case objabi.Hplan9:
   462  			ld.Asmplan9sym(ctxt)
   463  			ld.Cflush()
   464  
   465  			sym := ctxt.Syms.Lookup("pclntab", 0)
   466  			if sym != nil {
   467  				ld.Lcsize = int32(len(sym.P))
   468  				for i := 0; int32(i) < ld.Lcsize; i++ {
   469  					ld.Cput(sym.P[i])
   470  				}
   471  
   472  				ld.Cflush()
   473  			}
   474  
   475  		case objabi.Hdarwin:
   476  			if ld.Linkmode == ld.LinkExternal {
   477  				ld.Machoemitreloc(ctxt)
   478  			}
   479  		}
   480  	}
   481  
   482  	if ctxt.Debugvlog != 0 {
   483  		ctxt.Logf("%5.2f header\n", ld.Cputime())
   484  	}
   485  	ld.Cseek(0)
   486  	switch ld.Headtype {
   487  	default:
   488  	case objabi.Hplan9: /* plan 9 */
   489  		ld.Thearch.Lput(0x647)                      /* magic */
   490  		ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
   491  		ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
   492  		ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
   493  		ld.Thearch.Lput(uint32(ld.Symsize))          /* nsyms */
   494  		ld.Thearch.Lput(uint32(ld.Entryvalue(ctxt))) /* va of entry */
   495  		ld.Thearch.Lput(0)
   496  		ld.Thearch.Lput(uint32(ld.Lcsize))
   497  
   498  	case objabi.Hlinux,
   499  		objabi.Hfreebsd,
   500  		objabi.Hnetbsd,
   501  		objabi.Hopenbsd,
   502  		objabi.Hnacl:
   503  		ld.Asmbelf(ctxt, int64(symo))
   504  
   505  	case objabi.Hdarwin:
   506  		ld.Asmbmacho(ctxt)
   507  	}
   508  
   509  	ld.Cflush()
   510  	if *ld.FlagC {
   511  		fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
   512  		fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
   513  		fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
   514  		fmt.Printf("symsize=%d\n", ld.Symsize)
   515  		fmt.Printf("lcsize=%d\n", ld.Lcsize)
   516  		fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
   517  	}
   518  }