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 }