github.com/sbinet/go@v0.0.0-20160827155028-54d7de7dd62b/src/cmd/link/internal/s390x/asm.go (about)

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