github.com/panjjo/go@v0.0.0-20161104043856-d62b31386338/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/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  }