Home | History | Annotate | Download | only in s390x
      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 s390x
     32 
     33 import (
     34 	"cmd/internal/obj"
     35 	"cmd/link/internal/ld"
     36 	"debug/elf"
     37 	"fmt"
     38 )
     39 
     40 // gentext generates assembly to append the local moduledata to the global
     41 // moduledata linked list at initialization time. This is only done if the runtime
     42 // is in a different module.
     43 //
     44 // <go.link.addmoduledata>:
     45 // 	larl  %r2, <local.moduledata>
     46 // 	jg    <runtime.addmoduledata@plt>
     47 //	undef
     48 //
     49 // The job of appending the moduledata is delegated to runtime.addmoduledata.
     50 func gentext(ctxt *ld.Link) {
     51 	if !ctxt.DynlinkingGo() {
     52 		return
     53 	}
     54 	addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
     55 	if addmoduledata.Type == obj.STEXT {
     56 		// we're linking a module containing the runtime -> no need for
     57 		// an init function
     58 		return
     59 	}
     60 	addmoduledata.Attr |= ld.AttrReachable
     61 	initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
     62 	initfunc.Type = obj.STEXT
     63 	initfunc.Attr |= ld.AttrLocal
     64 	initfunc.Attr |= ld.AttrReachable
     65 
     66 	// larl %r2, <local.moduledata>
     67 	ld.Adduint8(ctxt, initfunc, 0xc0)
     68 	ld.Adduint8(ctxt, initfunc, 0x20)
     69 	lmd := ld.Addrel(initfunc)
     70 	lmd.Off = int32(initfunc.Size)
     71 	lmd.Siz = 4
     72 	lmd.Sym = ctxt.Moduledata
     73 	lmd.Type = obj.R_PCREL
     74 	lmd.Variant = ld.RV_390_DBL
     75 	lmd.Add = 2 + int64(lmd.Siz)
     76 	ld.Adduint32(ctxt, initfunc, 0)
     77 
     78 	// jg <runtime.addmoduledata[@plt]>
     79 	ld.Adduint8(ctxt, initfunc, 0xc0)
     80 	ld.Adduint8(ctxt, initfunc, 0xf4)
     81 	rel := ld.Addrel(initfunc)
     82 	rel.Off = int32(initfunc.Size)
     83 	rel.Siz = 4
     84 	rel.Sym = ctxt.Syms.Lookup("runtime.addmoduledata", 0)
     85 	rel.Type = obj.R_CALL
     86 	rel.Variant = ld.RV_390_DBL
     87 	rel.Add = 2 + int64(rel.Siz)
     88 	ld.Adduint32(ctxt, initfunc, 0)
     89 
     90 	// undef (for debugging)
     91 	ld.Adduint32(ctxt, initfunc, 0)
     92 
     93 	ctxt.Textp = append(ctxt.Textp, initfunc)
     94 	initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
     95 	initarray_entry.Attr |= ld.AttrLocal
     96 	initarray_entry.Attr |= ld.AttrReachable
     97 	initarray_entry.Type = obj.SINITARR
     98 	ld.Addaddr(ctxt, initarray_entry, initfunc)
     99 }
    100 
    101 func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
    102 	targ := r.Sym
    103 
    104 	switch r.Type {
    105 	default:
    106 		if r.Type >= 256 {
    107 			ld.Errorf(s, "unexpected relocation type %d", r.Type)
    108 			return false
    109 		}
    110 
    111 		// Handle relocations found in ELF object files.
    112 	case 256 + ld.R_390_12,
    113 		256 + ld.R_390_GOT12:
    114 		ld.Errorf(s, "s390x 12-bit relocations have not been implemented (relocation type %d)", r.Type-256)
    115 		return false
    116 
    117 	case 256 + ld.R_390_8,
    118 		256 + ld.R_390_16,
    119 		256 + ld.R_390_32,
    120 		256 + ld.R_390_64:
    121 		if targ.Type == obj.SDYNIMPORT {
    122 			ld.Errorf(s, "unexpected R_390_nn relocation for dynamic symbol %s", targ.Name)
    123 		}
    124 		r.Type = obj.R_ADDR
    125 		return true
    126 
    127 	case 256 + ld.R_390_PC16,
    128 		256 + ld.R_390_PC32,
    129 		256 + ld.R_390_PC64:
    130 		if targ.Type == obj.SDYNIMPORT {
    131 			ld.Errorf(s, "unexpected R_390_PCnn relocation for dynamic symbol %s", targ.Name)
    132 		}
    133 		if targ.Type == 0 || targ.Type == obj.SXREF {
    134 			ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
    135 		}
    136 		r.Type = obj.R_PCREL
    137 		r.Add += int64(r.Siz)
    138 		return true
    139 
    140 	case 256 + ld.R_390_GOT16,
    141 		256 + ld.R_390_GOT32,
    142 		256 + ld.R_390_GOT64:
    143 		ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-256)
    144 		return true
    145 
    146 	case 256 + ld.R_390_PLT16DBL,
    147 		256 + ld.R_390_PLT32DBL:
    148 		r.Type = obj.R_PCREL
    149 		r.Variant = ld.RV_390_DBL
    150 		r.Add += int64(r.Siz)
    151 		if targ.Type == obj.SDYNIMPORT {
    152 			addpltsym(ctxt, targ)
    153 			r.Sym = ctxt.Syms.Lookup(".plt", 0)
    154 			r.Add += int64(targ.Plt)
    155 		}
    156 		return true
    157 
    158 	case 256 + ld.R_390_PLT32,
    159 		256 + ld.R_390_PLT64:
    160 		r.Type = obj.R_PCREL
    161 		r.Add += int64(r.Siz)
    162 		if targ.Type == obj.SDYNIMPORT {
    163 			addpltsym(ctxt, targ)
    164 			r.Sym = ctxt.Syms.Lookup(".plt", 0)
    165 			r.Add += int64(targ.Plt)
    166 		}
    167 		return true
    168 
    169 	case 256 + ld.R_390_COPY:
    170 		ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-256)
    171 		return false
    172 
    173 	case 256 + ld.R_390_GLOB_DAT:
    174 		ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-256)
    175 		return false
    176 
    177 	case 256 + ld.R_390_JMP_SLOT:
    178 		ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-256)
    179 		return false
    180 
    181 	case 256 + ld.R_390_RELATIVE:
    182 		ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-256)
    183 		return false
    184 
    185 	case 256 + ld.R_390_GOTOFF:
    186 		if targ.Type == obj.SDYNIMPORT {
    187 			ld.Errorf(s, "unexpected R_390_GOTOFF relocation for dynamic symbol %s", targ.Name)
    188 		}
    189 		r.Type = obj.R_GOTOFF
    190 		return true
    191 
    192 	case 256 + ld.R_390_GOTPC:
    193 		r.Type = obj.R_PCREL
    194 		r.Sym = ctxt.Syms.Lookup(".got", 0)
    195 		r.Add += int64(r.Siz)
    196 		return true
    197 
    198 	case 256 + ld.R_390_PC16DBL,
    199 		256 + ld.R_390_PC32DBL:
    200 		r.Type = obj.R_PCREL
    201 		r.Variant = ld.RV_390_DBL
    202 		r.Add += int64(r.Siz)
    203 		if targ.Type == obj.SDYNIMPORT {
    204 			ld.Errorf(s, "unexpected R_390_PCnnDBL relocation for dynamic symbol %s", targ.Name)
    205 		}
    206 		return true
    207 
    208 	case 256 + ld.R_390_GOTPCDBL:
    209 		r.Type = obj.R_PCREL
    210 		r.Variant = ld.RV_390_DBL
    211 		r.Sym = ctxt.Syms.Lookup(".got", 0)
    212 		r.Add += int64(r.Siz)
    213 		return true
    214 
    215 	case 256 + ld.R_390_GOTENT:
    216 		addgotsym(ctxt, targ)
    217 
    218 		r.Type = obj.R_PCREL
    219 		r.Variant = ld.RV_390_DBL
    220 		r.Sym = ctxt.Syms.Lookup(".got", 0)
    221 		r.Add += int64(targ.Got)
    222 		r.Add += int64(r.Siz)
    223 		return true
    224 	}
    225 	// Handle references to ELF symbols from our own object files.
    226 	if targ.Type != obj.SDYNIMPORT {
    227 		return true
    228 	}
    229 
    230 	return false
    231 }
    232 
    233 func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
    234 	ld.Thearch.Vput(uint64(sectoff))
    235 
    236 	elfsym := r.Xsym.ElfsymForReloc()
    237 	switch r.Type {
    238 	default:
    239 		return -1
    240 
    241 	case obj.R_TLS_LE:
    242 		switch r.Siz {
    243 		default:
    244 			return -1
    245 		case 4:
    246 			// WARNING - silently ignored by linker in ELF64
    247 			ld.Thearch.Vput(ld.R_390_TLS_LE32 | uint64(elfsym)<<32)
    248 		case 8:
    249 			// WARNING - silently ignored by linker in ELF32
    250 			ld.Thearch.Vput(ld.R_390_TLS_LE64 | uint64(elfsym)<<32)
    251 		}
    252 
    253 	case obj.R_TLS_IE:
    254 		switch r.Siz {
    255 		default:
    256 			return -1
    257 		case 4:
    258 			ld.Thearch.Vput(ld.R_390_TLS_IEENT | uint64(elfsym)<<32)
    259 		}
    260 
    261 	case obj.R_ADDR:
    262 		switch r.Siz {
    263 		default:
    264 			return -1
    265 		case 4:
    266 			ld.Thearch.Vput(ld.R_390_32 | uint64(elfsym)<<32)
    267 		case 8:
    268 			ld.Thearch.Vput(ld.R_390_64 | uint64(elfsym)<<32)
    269 		}
    270 
    271 	case obj.R_GOTPCREL:
    272 		if r.Siz == 4 {
    273 			ld.Thearch.Vput(ld.R_390_GOTENT | uint64(elfsym)<<32)
    274 		} else {
    275 			return -1
    276 		}
    277 
    278 	case obj.R_PCREL, obj.R_PCRELDBL, obj.R_CALL:
    279 		elfrel := ld.R_390_NONE
    280 		isdbl := r.Variant&ld.RV_TYPE_MASK == ld.RV_390_DBL
    281 		// TODO(mundaym): all DBL style relocations should be
    282 		// signalled using the variant - see issue 14218.
    283 		switch r.Type {
    284 		case obj.R_PCRELDBL, obj.R_CALL:
    285 			isdbl = true
    286 		}
    287 		if r.Xsym.Type == obj.SDYNIMPORT && (r.Xsym.ElfType == elf.STT_FUNC || r.Type == obj.R_CALL) {
    288 			if isdbl {
    289 				switch r.Siz {
    290 				case 2:
    291 					elfrel = ld.R_390_PLT16DBL
    292 				case 4:
    293 					elfrel = ld.R_390_PLT32DBL
    294 				}
    295 			} else {
    296 				switch r.Siz {
    297 				case 4:
    298 					elfrel = ld.R_390_PLT32
    299 				case 8:
    300 					elfrel = ld.R_390_PLT64
    301 				}
    302 			}
    303 		} else {
    304 			if isdbl {
    305 				switch r.Siz {
    306 				case 2:
    307 					elfrel = ld.R_390_PC16DBL
    308 				case 4:
    309 					elfrel = ld.R_390_PC32DBL
    310 				}
    311 			} else {
    312 				switch r.Siz {
    313 				case 2:
    314 					elfrel = ld.R_390_PC16
    315 				case 4:
    316 					elfrel = ld.R_390_PC32
    317 				case 8:
    318 					elfrel = ld.R_390_PC64
    319 				}
    320 			}
    321 		}
    322 		if elfrel == ld.R_390_NONE {
    323 			return -1 // unsupported size/dbl combination
    324 		}
    325 		ld.Thearch.Vput(uint64(elfrel) | uint64(elfsym)<<32)
    326 	}
    327 
    328 	ld.Thearch.Vput(uint64(r.Xadd))
    329 	return 0
    330 }
    331 
    332 func elfsetupplt(ctxt *ld.Link) {
    333 	plt := ctxt.Syms.Lookup(".plt", 0)
    334 	got := ctxt.Syms.Lookup(".got", 0)
    335 	if plt.Size == 0 {
    336 		// stg     %r1,56(%r15)
    337 		ld.Adduint8(ctxt, plt, 0xe3)
    338 		ld.Adduint8(ctxt, plt, 0x10)
    339 		ld.Adduint8(ctxt, plt, 0xf0)
    340 		ld.Adduint8(ctxt, plt, 0x38)
    341 		ld.Adduint8(ctxt, plt, 0x00)
    342 		ld.Adduint8(ctxt, plt, 0x24)
    343 		// larl    %r1,_GLOBAL_OFFSET_TABLE_
    344 		ld.Adduint8(ctxt, plt, 0xc0)
    345 		ld.Adduint8(ctxt, plt, 0x10)
    346 		ld.Addpcrelplus(ctxt, plt, got, 6)
    347 		// mvc     48(8,%r15),8(%r1)
    348 		ld.Adduint8(ctxt, plt, 0xd2)
    349 		ld.Adduint8(ctxt, plt, 0x07)
    350 		ld.Adduint8(ctxt, plt, 0xf0)
    351 		ld.Adduint8(ctxt, plt, 0x30)
    352 		ld.Adduint8(ctxt, plt, 0x10)
    353 		ld.Adduint8(ctxt, plt, 0x08)
    354 		// lg      %r1,16(%r1)
    355 		ld.Adduint8(ctxt, plt, 0xe3)
    356 		ld.Adduint8(ctxt, plt, 0x10)
    357 		ld.Adduint8(ctxt, plt, 0x10)
    358 		ld.Adduint8(ctxt, plt, 0x10)
    359 		ld.Adduint8(ctxt, plt, 0x00)
    360 		ld.Adduint8(ctxt, plt, 0x04)
    361 		// br      %r1
    362 		ld.Adduint8(ctxt, plt, 0x07)
    363 		ld.Adduint8(ctxt, plt, 0xf1)
    364 		// nopr    %r0
    365 		ld.Adduint8(ctxt, plt, 0x07)
    366 		ld.Adduint8(ctxt, plt, 0x00)
    367 		// nopr    %r0
    368 		ld.Adduint8(ctxt, plt, 0x07)
    369 		ld.Adduint8(ctxt, plt, 0x00)
    370 		// nopr    %r0
    371 		ld.Adduint8(ctxt, plt, 0x07)
    372 		ld.Adduint8(ctxt, plt, 0x00)
    373 
    374 		// assume got->size == 0 too
    375 		ld.Addaddrplus(ctxt, got, ctxt.Syms.Lookup(".dynamic", 0), 0)
    376 
    377 		ld.Adduint64(ctxt, got, 0)
    378 		ld.Adduint64(ctxt, got, 0)
    379 	}
    380 }
    381 
    382 func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
    383 	return -1
    384 }
    385 
    386 func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
    387 	if ld.Linkmode == ld.LinkExternal {
    388 		return -1
    389 	}
    390 
    391 	switch r.Type {
    392 	case obj.R_CONST:
    393 		*val = r.Add
    394 		return 0
    395 
    396 	case obj.R_GOTOFF:
    397 		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
    398 		return 0
    399 	}
    400 
    401 	return -1
    402 }
    403 
    404 func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 {
    405 	switch r.Variant & ld.RV_TYPE_MASK {
    406 	default:
    407 		ld.Errorf(s, "unexpected relocation variant %d", r.Variant)
    408 		return t
    409 
    410 	case ld.RV_NONE:
    411 		return t
    412 
    413 	case ld.RV_390_DBL:
    414 		if (t & 1) != 0 {
    415 			ld.Errorf(s, "%s+%v is not 2-byte aligned", r.Sym.Name, r.Sym.Value)
    416 		}
    417 		return t >> 1
    418 	}
    419 }
    420 
    421 func addpltsym(ctxt *ld.Link, s *ld.Symbol) {
    422 	if s.Plt >= 0 {
    423 		return
    424 	}
    425 
    426 	ld.Adddynsym(ctxt, s)
    427 
    428 	if ld.Iself {
    429 		plt := ctxt.Syms.Lookup(".plt", 0)
    430 		got := ctxt.Syms.Lookup(".got", 0)
    431 		rela := ctxt.Syms.Lookup(".rela.plt", 0)
    432 		if plt.Size == 0 {
    433 			elfsetupplt(ctxt)
    434 		}
    435 		// larl    %r1,_GLOBAL_OFFSET_TABLE_+index
    436 
    437 		ld.Adduint8(ctxt, plt, 0xc0)
    438 		ld.Adduint8(ctxt, plt, 0x10)
    439 		ld.Addpcrelplus(ctxt, plt, got, got.Size+6) // need variant?
    440 
    441 		// add to got: pointer to current pos in plt
    442 		ld.Addaddrplus(ctxt, got, plt, plt.Size+8) // weird but correct
    443 		// lg      %r1,0(%r1)
    444 		ld.Adduint8(ctxt, plt, 0xe3)
    445 		ld.Adduint8(ctxt, plt, 0x10)
    446 		ld.Adduint8(ctxt, plt, 0x10)
    447 		ld.Adduint8(ctxt, plt, 0x00)
    448 		ld.Adduint8(ctxt, plt, 0x00)
    449 		ld.Adduint8(ctxt, plt, 0x04)
    450 		// br      %r1
    451 		ld.Adduint8(ctxt, plt, 0x07)
    452 		ld.Adduint8(ctxt, plt, 0xf1)
    453 		// basr    %r1,%r0
    454 		ld.Adduint8(ctxt, plt, 0x0d)
    455 		ld.Adduint8(ctxt, plt, 0x10)
    456 		// lgf     %r1,12(%r1)
    457 		ld.Adduint8(ctxt, plt, 0xe3)
    458 		ld.Adduint8(ctxt, plt, 0x10)
    459 		ld.Adduint8(ctxt, plt, 0x10)
    460 		ld.Adduint8(ctxt, plt, 0x0c)
    461 		ld.Adduint8(ctxt, plt, 0x00)
    462 		ld.Adduint8(ctxt, plt, 0x14)
    463 		// jg .plt
    464 		ld.Adduint8(ctxt, plt, 0xc0)
    465 		ld.Adduint8(ctxt, plt, 0xf4)
    466 
    467 		ld.Adduint32(ctxt, plt, uint32(-((plt.Size - 2) >> 1))) // roll-your-own relocation
    468 		//.plt index
    469 		ld.Adduint32(ctxt, plt, uint32(rela.Size)) // rela size before current entry
    470 
    471 		// rela
    472 		ld.Addaddrplus(ctxt, rela, got, got.Size-8)
    473 
    474 		ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_390_JMP_SLOT))
    475 		ld.Adduint64(ctxt, rela, 0)
    476 
    477 		s.Plt = int32(plt.Size - 32)
    478 
    479 	} else {
    480 		ld.Errorf(s, "addpltsym: unsupported binary format")
    481 	}
    482 }
    483 
    484 func addgotsym(ctxt *ld.Link, s *ld.Symbol) {
    485 	if s.Got >= 0 {
    486 		return
    487 	}
    488 
    489 	ld.Adddynsym(ctxt, s)
    490 	got := ctxt.Syms.Lookup(".got", 0)
    491 	s.Got = int32(got.Size)
    492 	ld.Adduint64(ctxt, got, 0)
    493 
    494 	if ld.Iself {
    495 		rela := ctxt.Syms.Lookup(".rela", 0)
    496 		ld.Addaddrplus(ctxt, rela, got, int64(s.Got))
    497 		ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_390_GLOB_DAT))
    498 		ld.Adduint64(ctxt, rela, 0)
    499 	} else {
    500 		ld.Errorf(s, "addgotsym: unsupported binary format")
    501 	}
    502 }
    503 
    504 func asmb(ctxt *ld.Link) {
    505 	if ctxt.Debugvlog != 0 {
    506 		ctxt.Logf("%5.2f asmb\n", obj.Cputime())
    507 	}
    508 
    509 	if ld.Iself {
    510 		ld.Asmbelfsetup()
    511 	}
    512 
    513 	sect := ld.Segtext.Sect
    514 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
    515 	ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
    516 	for sect = sect.Next; sect != nil; sect = sect.Next {
    517 		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
    518 		ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
    519 	}
    520 
    521 	if ld.Segrodata.Filelen > 0 {
    522 		if ctxt.Debugvlog != 0 {
    523 			ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
    524 		}
    525 		ld.Cseek(int64(ld.Segrodata.Fileoff))
    526 		ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
    527 	}
    528 	if ld.Segrelrodata.Filelen > 0 {
    529 		if ctxt.Debugvlog != 0 {
    530 			ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
    531 		}
    532 		ld.Cseek(int64(ld.Segrelrodata.Fileoff))
    533 		ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
    534 	}
    535 
    536 	if ctxt.Debugvlog != 0 {
    537 		ctxt.Logf("%5.2f datblk\n", obj.Cputime())
    538 	}
    539 
    540 	ld.Cseek(int64(ld.Segdata.Fileoff))
    541 	ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
    542 
    543 	ld.Cseek(int64(ld.Segdwarf.Fileoff))
    544 	ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
    545 
    546 	/* output symbol table */
    547 	ld.Symsize = 0
    548 
    549 	ld.Lcsize = 0
    550 	symo := uint32(0)
    551 	if !*ld.FlagS {
    552 		if !ld.Iself {
    553 			ld.Errorf(nil, "unsupported executable format")
    554 		}
    555 		if ctxt.Debugvlog != 0 {
    556 			ctxt.Logf("%5.2f sym\n", obj.Cputime())
    557 		}
    558 		symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
    559 		symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
    560 
    561 		ld.Cseek(int64(symo))
    562 		if ctxt.Debugvlog != 0 {
    563 			ctxt.Logf("%5.2f elfsym\n", obj.Cputime())
    564 		}
    565 		ld.Asmelfsym(ctxt)
    566 		ld.Cflush()
    567 		ld.Cwrite(ld.Elfstrdat)
    568 
    569 		if ctxt.Debugvlog != 0 {
    570 			ctxt.Logf("%5.2f dwarf\n", obj.Cputime())
    571 		}
    572 
    573 		if ld.Linkmode == ld.LinkExternal {
    574 			ld.Elfemitreloc(ctxt)
    575 		}
    576 	}
    577 
    578 	if ctxt.Debugvlog != 0 {
    579 		ctxt.Logf("%5.2f header\n", obj.Cputime())
    580 	}
    581 	ld.Cseek(0)
    582 	switch ld.Headtype {
    583 	default:
    584 		ld.Errorf(nil, "unsupported operating system")
    585 	case obj.Hlinux:
    586 		ld.Asmbelf(ctxt, int64(symo))
    587 	}
    588 
    589 	ld.Cflush()
    590 	if *ld.FlagC {
    591 		fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
    592 		fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
    593 		fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
    594 		fmt.Printf("symsize=%d\n", ld.Symsize)
    595 		fmt.Printf("lcsize=%d\n", ld.Lcsize)
    596 		fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
    597 	}
    598 }
    599