github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/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 + objabi.RelocType(elf.R_390_12),
   117  		256 + objabi.RelocType(elf.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 + objabi.RelocType(elf.R_390_8),
   122  		256 + objabi.RelocType(elf.R_390_16),
   123  		256 + objabi.RelocType(elf.R_390_32),
   124  		256 + objabi.RelocType(elf.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 + objabi.RelocType(elf.R_390_PC16),
   132  		256 + objabi.RelocType(elf.R_390_PC32),
   133  		256 + objabi.RelocType(elf.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  		// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
   138  		// sense and should be removed when someone has thought about it properly.
   139  		if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
   140  			ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
   141  		}
   142  		r.Type = objabi.R_PCREL
   143  		r.Add += int64(r.Siz)
   144  		return true
   145  
   146  	case 256 + objabi.RelocType(elf.R_390_GOT16),
   147  		256 + objabi.RelocType(elf.R_390_GOT32),
   148  		256 + objabi.RelocType(elf.R_390_GOT64):
   149  		ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-256)
   150  		return true
   151  
   152  	case 256 + objabi.RelocType(elf.R_390_PLT16DBL),
   153  		256 + objabi.RelocType(elf.R_390_PLT32DBL):
   154  		r.Type = objabi.R_PCREL
   155  		r.Variant = sym.RV_390_DBL
   156  		r.Add += int64(r.Siz)
   157  		if targ.Type == sym.SDYNIMPORT {
   158  			addpltsym(ctxt, targ)
   159  			r.Sym = ctxt.Syms.Lookup(".plt", 0)
   160  			r.Add += int64(targ.Plt)
   161  		}
   162  		return true
   163  
   164  	case 256 + objabi.RelocType(elf.R_390_PLT32),
   165  		256 + objabi.RelocType(elf.R_390_PLT64):
   166  		r.Type = objabi.R_PCREL
   167  		r.Add += int64(r.Siz)
   168  		if targ.Type == sym.SDYNIMPORT {
   169  			addpltsym(ctxt, targ)
   170  			r.Sym = ctxt.Syms.Lookup(".plt", 0)
   171  			r.Add += int64(targ.Plt)
   172  		}
   173  		return true
   174  
   175  	case 256 + objabi.RelocType(elf.R_390_COPY):
   176  		ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-256)
   177  		return false
   178  
   179  	case 256 + objabi.RelocType(elf.R_390_GLOB_DAT):
   180  		ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-256)
   181  		return false
   182  
   183  	case 256 + objabi.RelocType(elf.R_390_JMP_SLOT):
   184  		ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-256)
   185  		return false
   186  
   187  	case 256 + objabi.RelocType(elf.R_390_RELATIVE):
   188  		ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-256)
   189  		return false
   190  
   191  	case 256 + objabi.RelocType(elf.R_390_GOTOFF):
   192  		if targ.Type == sym.SDYNIMPORT {
   193  			ld.Errorf(s, "unexpected R_390_GOTOFF relocation for dynamic symbol %s", targ.Name)
   194  		}
   195  		r.Type = objabi.R_GOTOFF
   196  		return true
   197  
   198  	case 256 + objabi.RelocType(elf.R_390_GOTPC):
   199  		r.Type = objabi.R_PCREL
   200  		r.Sym = ctxt.Syms.Lookup(".got", 0)
   201  		r.Add += int64(r.Siz)
   202  		return true
   203  
   204  	case 256 + objabi.RelocType(elf.R_390_PC16DBL),
   205  		256 + objabi.RelocType(elf.R_390_PC32DBL):
   206  		r.Type = objabi.R_PCREL
   207  		r.Variant = sym.RV_390_DBL
   208  		r.Add += int64(r.Siz)
   209  		if targ.Type == sym.SDYNIMPORT {
   210  			ld.Errorf(s, "unexpected R_390_PCnnDBL relocation for dynamic symbol %s", targ.Name)
   211  		}
   212  		return true
   213  
   214  	case 256 + objabi.RelocType(elf.R_390_GOTPCDBL):
   215  		r.Type = objabi.R_PCREL
   216  		r.Variant = sym.RV_390_DBL
   217  		r.Sym = ctxt.Syms.Lookup(".got", 0)
   218  		r.Add += int64(r.Siz)
   219  		return true
   220  
   221  	case 256 + objabi.RelocType(elf.R_390_GOTENT):
   222  		addgotsym(ctxt, targ)
   223  
   224  		r.Type = objabi.R_PCREL
   225  		r.Variant = sym.RV_390_DBL
   226  		r.Sym = ctxt.Syms.Lookup(".got", 0)
   227  		r.Add += int64(targ.Got)
   228  		r.Add += int64(r.Siz)
   229  		return true
   230  	}
   231  	// Handle references to ELF symbols from our own object files.
   232  	if targ.Type != sym.SDYNIMPORT {
   233  		return true
   234  	}
   235  
   236  	return false
   237  }
   238  
   239  func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
   240  	ctxt.Out.Write64(uint64(sectoff))
   241  
   242  	elfsym := r.Xsym.ElfsymForReloc()
   243  	switch r.Type {
   244  	default:
   245  		return false
   246  	case objabi.R_TLS_LE:
   247  		switch r.Siz {
   248  		default:
   249  			return false
   250  		case 4:
   251  			// WARNING - silently ignored by linker in ELF64
   252  			ctxt.Out.Write64(uint64(elf.R_390_TLS_LE32) | uint64(elfsym)<<32)
   253  		case 8:
   254  			// WARNING - silently ignored by linker in ELF32
   255  			ctxt.Out.Write64(uint64(elf.R_390_TLS_LE64) | uint64(elfsym)<<32)
   256  		}
   257  	case objabi.R_TLS_IE:
   258  		switch r.Siz {
   259  		default:
   260  			return false
   261  		case 4:
   262  			ctxt.Out.Write64(uint64(elf.R_390_TLS_IEENT) | uint64(elfsym)<<32)
   263  		}
   264  	case objabi.R_ADDR:
   265  		switch r.Siz {
   266  		default:
   267  			return false
   268  		case 4:
   269  			ctxt.Out.Write64(uint64(elf.R_390_32) | uint64(elfsym)<<32)
   270  		case 8:
   271  			ctxt.Out.Write64(uint64(elf.R_390_64) | uint64(elfsym)<<32)
   272  		}
   273  	case objabi.R_GOTPCREL:
   274  		if r.Siz == 4 {
   275  			ctxt.Out.Write64(uint64(elf.R_390_GOTENT) | uint64(elfsym)<<32)
   276  		} else {
   277  			return false
   278  		}
   279  	case objabi.R_PCREL, objabi.R_PCRELDBL, objabi.R_CALL:
   280  		elfrel := elf.R_390_NONE
   281  		isdbl := r.Variant&sym.RV_TYPE_MASK == sym.RV_390_DBL
   282  		// TODO(mundaym): all DBL style relocations should be
   283  		// signalled using the variant - see issue 14218.
   284  		switch r.Type {
   285  		case objabi.R_PCRELDBL, objabi.R_CALL:
   286  			isdbl = true
   287  		}
   288  		if r.Xsym.Type == sym.SDYNIMPORT && (r.Xsym.ElfType == elf.STT_FUNC || r.Type == objabi.R_CALL) {
   289  			if isdbl {
   290  				switch r.Siz {
   291  				case 2:
   292  					elfrel = elf.R_390_PLT16DBL
   293  				case 4:
   294  					elfrel = elf.R_390_PLT32DBL
   295  				}
   296  			} else {
   297  				switch r.Siz {
   298  				case 4:
   299  					elfrel = elf.R_390_PLT32
   300  				case 8:
   301  					elfrel = elf.R_390_PLT64
   302  				}
   303  			}
   304  		} else {
   305  			if isdbl {
   306  				switch r.Siz {
   307  				case 2:
   308  					elfrel = elf.R_390_PC16DBL
   309  				case 4:
   310  					elfrel = elf.R_390_PC32DBL
   311  				}
   312  			} else {
   313  				switch r.Siz {
   314  				case 2:
   315  					elfrel = elf.R_390_PC16
   316  				case 4:
   317  					elfrel = elf.R_390_PC32
   318  				case 8:
   319  					elfrel = elf.R_390_PC64
   320  				}
   321  			}
   322  		}
   323  		if elfrel == elf.R_390_NONE {
   324  			return false // unsupported size/dbl combination
   325  		}
   326  		ctxt.Out.Write64(uint64(elfrel) | uint64(elfsym)<<32)
   327  	}
   328  
   329  	ctxt.Out.Write64(uint64(r.Xadd))
   330  	return true
   331  }
   332  
   333  func elfsetupplt(ctxt *ld.Link) {
   334  	plt := ctxt.Syms.Lookup(".plt", 0)
   335  	got := ctxt.Syms.Lookup(".got", 0)
   336  	if plt.Size == 0 {
   337  		// stg     %r1,56(%r15)
   338  		plt.AddUint8(0xe3)
   339  		plt.AddUint8(0x10)
   340  		plt.AddUint8(0xf0)
   341  		plt.AddUint8(0x38)
   342  		plt.AddUint8(0x00)
   343  		plt.AddUint8(0x24)
   344  		// larl    %r1,_GLOBAL_OFFSET_TABLE_
   345  		plt.AddUint8(0xc0)
   346  		plt.AddUint8(0x10)
   347  		plt.AddPCRelPlus(ctxt.Arch, got, 6)
   348  		// mvc     48(8,%r15),8(%r1)
   349  		plt.AddUint8(0xd2)
   350  		plt.AddUint8(0x07)
   351  		plt.AddUint8(0xf0)
   352  		plt.AddUint8(0x30)
   353  		plt.AddUint8(0x10)
   354  		plt.AddUint8(0x08)
   355  		// lg      %r1,16(%r1)
   356  		plt.AddUint8(0xe3)
   357  		plt.AddUint8(0x10)
   358  		plt.AddUint8(0x10)
   359  		plt.AddUint8(0x10)
   360  		plt.AddUint8(0x00)
   361  		plt.AddUint8(0x04)
   362  		// br      %r1
   363  		plt.AddUint8(0x07)
   364  		plt.AddUint8(0xf1)
   365  		// nopr    %r0
   366  		plt.AddUint8(0x07)
   367  		plt.AddUint8(0x00)
   368  		// nopr    %r0
   369  		plt.AddUint8(0x07)
   370  		plt.AddUint8(0x00)
   371  		// nopr    %r0
   372  		plt.AddUint8(0x07)
   373  		plt.AddUint8(0x00)
   374  
   375  		// assume got->size == 0 too
   376  		got.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".dynamic", 0), 0)
   377  
   378  		got.AddUint64(ctxt.Arch, 0)
   379  		got.AddUint64(ctxt.Arch, 0)
   380  	}
   381  }
   382  
   383  func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
   384  	return false
   385  }
   386  
   387  func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool {
   388  	if ctxt.LinkMode == ld.LinkExternal {
   389  		return false
   390  	}
   391  
   392  	switch r.Type {
   393  	case objabi.R_CONST:
   394  		*val = r.Add
   395  		return true
   396  	case objabi.R_GOTOFF:
   397  		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
   398  		return true
   399  	}
   400  
   401  	return false
   402  }
   403  
   404  func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
   405  	switch r.Variant & sym.RV_TYPE_MASK {
   406  	default:
   407  		ld.Errorf(s, "unexpected relocation variant %d", r.Variant)
   408  		return t
   409  
   410  	case sym.RV_NONE:
   411  		return t
   412  
   413  	case sym.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 *sym.Symbol) {
   422  	if s.Plt >= 0 {
   423  		return
   424  	}
   425  
   426  	ld.Adddynsym(ctxt, s)
   427  
   428  	if ctxt.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  		plt.AddUint8(0xc0)
   438  		plt.AddUint8(0x10)
   439  		plt.AddPCRelPlus(ctxt.Arch, got, got.Size+6) // need variant?
   440  
   441  		// add to got: pointer to current pos in plt
   442  		got.AddAddrPlus(ctxt.Arch, plt, plt.Size+8) // weird but correct
   443  		// lg      %r1,0(%r1)
   444  		plt.AddUint8(0xe3)
   445  		plt.AddUint8(0x10)
   446  		plt.AddUint8(0x10)
   447  		plt.AddUint8(0x00)
   448  		plt.AddUint8(0x00)
   449  		plt.AddUint8(0x04)
   450  		// br      %r1
   451  		plt.AddUint8(0x07)
   452  		plt.AddUint8(0xf1)
   453  		// basr    %r1,%r0
   454  		plt.AddUint8(0x0d)
   455  		plt.AddUint8(0x10)
   456  		// lgf     %r1,12(%r1)
   457  		plt.AddUint8(0xe3)
   458  		plt.AddUint8(0x10)
   459  		plt.AddUint8(0x10)
   460  		plt.AddUint8(0x0c)
   461  		plt.AddUint8(0x00)
   462  		plt.AddUint8(0x14)
   463  		// jg .plt
   464  		plt.AddUint8(0xc0)
   465  		plt.AddUint8(0xf4)
   466  
   467  		plt.AddUint32(ctxt.Arch, uint32(-((plt.Size - 2) >> 1))) // roll-your-own relocation
   468  		//.plt index
   469  		plt.AddUint32(ctxt.Arch, uint32(rela.Size)) // rela size before current entry
   470  
   471  		// rela
   472  		rela.AddAddrPlus(ctxt.Arch, got, got.Size-8)
   473  
   474  		rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_390_JMP_SLOT)))
   475  		rela.AddUint64(ctxt.Arch, 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 *sym.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  	got.AddUint64(ctxt.Arch, 0)
   493  
   494  	if ctxt.IsELF {
   495  		rela := ctxt.Syms.Lookup(".rela", 0)
   496  		rela.AddAddrPlus(ctxt.Arch, got, int64(s.Got))
   497  		rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_390_GLOB_DAT)))
   498  		rela.AddUint64(ctxt.Arch, 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", ld.Cputime())
   507  	}
   508  
   509  	if ctxt.IsELF {
   510  		ld.Asmbelfsetup()
   511  	}
   512  
   513  	sect := ld.Segtext.Sections[0]
   514  	ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
   515  	ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
   516  	for _, sect = range ld.Segtext.Sections[1:] {
   517  		ctxt.Out.SeekSet(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", ld.Cputime())
   524  		}
   525  		ctxt.Out.SeekSet(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", ld.Cputime())
   531  		}
   532  		ctxt.Out.SeekSet(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", ld.Cputime())
   538  	}
   539  
   540  	ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
   541  	ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
   542  
   543  	ctxt.Out.SeekSet(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 !ctxt.IsELF {
   553  			ld.Errorf(nil, "unsupported executable format")
   554  		}
   555  		if ctxt.Debugvlog != 0 {
   556  			ctxt.Logf("%5.2f sym\n", ld.Cputime())
   557  		}
   558  		symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
   559  		symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
   560  
   561  		ctxt.Out.SeekSet(int64(symo))
   562  		if ctxt.Debugvlog != 0 {
   563  			ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
   564  		}
   565  		ld.Asmelfsym(ctxt)
   566  		ctxt.Out.Flush()
   567  		ctxt.Out.Write(ld.Elfstrdat)
   568  
   569  		if ctxt.Debugvlog != 0 {
   570  			ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
   571  		}
   572  
   573  		if ctxt.LinkMode == ld.LinkExternal {
   574  			ld.Elfemitreloc(ctxt)
   575  		}
   576  	}
   577  
   578  	if ctxt.Debugvlog != 0 {
   579  		ctxt.Logf("%5.2f header\n", ld.Cputime())
   580  	}
   581  	ctxt.Out.SeekSet(0)
   582  	switch ctxt.HeadType {
   583  	default:
   584  		ld.Errorf(nil, "unsupported operating system")
   585  	case objabi.Hlinux:
   586  		ld.Asmbelf(ctxt, int64(symo))
   587  	}
   588  
   589  	ctxt.Out.Flush()
   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  }