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