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