1// Copyright (c) 2017, Google Inc. 2// 3// Permission to use, copy, modify, and/or distribute this software for any 4// purpose with or without fee is hereby granted, provided that the above 5// copyright notice and this permission notice appear in all copies. 6// 7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14 15//go:generate peg delocate.peg 16 17// delocate performs several transformations of textual assembly code. See 18// crypto/fipsmodule/FIPS.md for an overview. 19package main 20 21import ( 22 "errors" 23 "flag" 24 "fmt" 25 "io/ioutil" 26 "os" 27 "sort" 28 "strconv" 29 "strings" 30) 31 32// inputFile represents a textual assembly file. 33type inputFile struct { 34 path string 35 // index is a unique identifer given to this file. It's used for 36 // mapping local symbols. 37 index int 38 // isArchive indicates that the input should be processed as an ar 39 // file. 40 isArchive bool 41 // contents contains the contents of the file. 42 contents string 43 // ast points to the head of the syntax tree. 44 ast *node32 45} 46 47type stringWriter interface { 48 WriteString(string) (int, error) 49} 50 51type processorType int 52 53const ( 54 ppc64le processorType = iota + 1 55 x86_64 56) 57 58// delocation holds the state needed during a delocation operation. 59type delocation struct { 60 processor processorType 61 output stringWriter 62 63 // symbols is the set of symbols defined in the module. 64 symbols map[string]struct{} 65 // localEntrySymbols is the set of symbols with .localentry directives. 66 localEntrySymbols map[string]struct{} 67 // redirectors maps from out-call symbol name to the name of a 68 // redirector function for that symbol. E.g. “memcpy” -> 69 // “bcm_redirector_memcpy”. 70 redirectors map[string]string 71 // bssAccessorsNeeded maps from a BSS symbol name to the symbol that 72 // should be used to reference it. E.g. “P384_data_storage” -> 73 // “P384_data_storage”. 74 bssAccessorsNeeded map[string]string 75 // tocLoaders is a set of symbol names for which TOC helper functions 76 // are required. (ppc64le only.) 77 tocLoaders map[string]struct{} 78 // gotExternalsNeeded is a set of symbol names for which we need 79 // “delta” symbols: symbols that contain the offset from their location 80 // to the memory in question. 81 gotExternalsNeeded map[string]struct{} 82 83 currentInput inputFile 84} 85 86func (d *delocation) contents(node *node32) string { 87 return d.currentInput.contents[node.begin:node.end] 88} 89 90// writeNode writes out an AST node. 91func (d *delocation) writeNode(node *node32) { 92 if _, err := d.output.WriteString(d.contents(node)); err != nil { 93 panic(err) 94 } 95} 96 97func (d *delocation) writeCommentedNode(node *node32) { 98 line := d.contents(node) 99 if _, err := d.output.WriteString("# WAS " + strings.TrimSpace(line) + "\n"); err != nil { 100 panic(err) 101 } 102} 103 104func locateError(err error, with *node32, in inputFile) error { 105 posMap := translatePositions([]rune(in.contents), []int{int(with.begin)}) 106 var line int 107 for _, pos := range posMap { 108 line = pos.line 109 } 110 111 return fmt.Errorf("error while processing %q on line %d: %q", in.contents[with.begin:with.end], line, err) 112} 113 114func (d *delocation) processInput(input inputFile) (err error) { 115 d.currentInput = input 116 117 var origStatement *node32 118 defer func() { 119 if err := recover(); err != nil { 120 panic(locateError(fmt.Errorf("%s", err), origStatement, input)) 121 } 122 }() 123 124 for statement := input.ast.up; statement != nil; statement = statement.next { 125 assertNodeType(statement, ruleStatement) 126 origStatement = statement 127 128 node := skipWS(statement.up) 129 if node == nil { 130 d.writeNode(statement) 131 continue 132 } 133 134 switch node.pegRule { 135 case ruleGlobalDirective, ruleComment, ruleLocationDirective: 136 d.writeNode(statement) 137 case ruleDirective: 138 statement, err = d.processDirective(statement, node.up) 139 case ruleLabelContainingDirective: 140 statement, err = d.processLabelContainingDirective(statement, node.up) 141 case ruleLabel: 142 statement, err = d.processLabel(statement, node.up) 143 case ruleInstruction: 144 switch d.processor { 145 case x86_64: 146 statement, err = d.processIntelInstruction(statement, node.up) 147 case ppc64le: 148 statement, err = d.processPPCInstruction(statement, node.up) 149 default: 150 panic("unknown processor") 151 } 152 default: 153 panic(fmt.Sprintf("unknown top-level statement type %q", rul3s[node.pegRule])) 154 } 155 156 if err != nil { 157 return locateError(err, origStatement, input) 158 } 159 } 160 161 return nil 162} 163 164func (d *delocation) processDirective(statement, directive *node32) (*node32, error) { 165 assertNodeType(directive, ruleDirectiveName) 166 directiveName := d.contents(directive) 167 168 var args []string 169 forEachPath(directive, func(arg *node32) { 170 // If the argument is a quoted string, use the raw contents. 171 // (Note that this doesn't unescape the string, but that's not 172 // needed so far. 173 if arg.up != nil { 174 arg = arg.up 175 assertNodeType(arg, ruleQuotedArg) 176 if arg.up == nil { 177 args = append(args, "") 178 return 179 } 180 arg = arg.up 181 assertNodeType(arg, ruleQuotedText) 182 } 183 args = append(args, d.contents(arg)) 184 }, ruleArgs, ruleArg) 185 186 switch directiveName { 187 case "comm", "lcomm": 188 if len(args) < 1 { 189 return nil, errors.New("comm directive has no arguments") 190 } 191 d.bssAccessorsNeeded[args[0]] = args[0] 192 d.writeNode(statement) 193 194 case "data": 195 // ASAN and some versions of MSAN are adding a .data section, 196 // and adding references to symbols within it to the code. We 197 // will have to work around this in the future. 198 return nil, errors.New(".data section found in module") 199 200 case "section": 201 section := args[0] 202 203 if section == ".data.rel.ro" { 204 // In a normal build, this is an indication of a 205 // problem but any references from the module to this 206 // section will result in a relocation and thus will 207 // break the integrity check. ASAN can generate these 208 // sections and so we will likely have to work around 209 // that in the future. 210 return nil, errors.New(".data.rel.ro section found in module") 211 } 212 213 sectionType, ok := sectionType(section) 214 if !ok { 215 // Unknown sections are permitted in order to be robust 216 // to different compiler modes. 217 d.writeNode(statement) 218 break 219 } 220 221 switch sectionType { 222 case ".rodata", ".text": 223 // Move .rodata to .text so it may be accessed without 224 // a relocation. GCC with -fmerge-constants will place 225 // strings into separate sections, so we move all 226 // sections named like .rodata. Also move .text.startup 227 // so the self-test function is also in the module. 228 d.writeCommentedNode(statement) 229 d.output.WriteString(".text\n") 230 231 case ".data": 232 // See above about .data 233 return nil, errors.New(".data section found in module") 234 235 case ".init_array", ".fini_array", ".ctors", ".dtors": 236 // init_array/ctors/dtors contains function 237 // pointers to constructor/destructor 238 // functions. These contain relocations, but 239 // they're in a different section anyway. 240 d.writeNode(statement) 241 break 242 243 case ".debug", ".note", ".toc": 244 d.writeNode(statement) 245 break 246 247 case ".bss": 248 d.writeNode(statement) 249 return d.handleBSS(statement) 250 } 251 252 default: 253 d.writeNode(statement) 254 } 255 256 return statement, nil 257} 258 259func (d *delocation) processLabelContainingDirective(statement, directive *node32) (*node32, error) { 260 // The symbols within directives need to be mapped so that local 261 // symbols in two different .s inputs don't collide. 262 changed := false 263 assertNodeType(directive, ruleLabelContainingDirectiveName) 264 name := d.contents(directive) 265 266 node := directive.next 267 assertNodeType(node, ruleWS) 268 269 node = node.next 270 assertNodeType(node, ruleSymbolArgs) 271 272 var args []string 273 for node = skipWS(node.up); node != nil; node = skipWS(node.next) { 274 assertNodeType(node, ruleSymbolArg) 275 arg := node.up 276 var mapped string 277 278 for term := arg; term != nil; term = term.next { 279 if term.pegRule != ruleLocalSymbol { 280 mapped += d.contents(term) 281 continue 282 } 283 284 oldSymbol := d.contents(term) 285 newSymbol := d.mapLocalSymbol(oldSymbol) 286 if newSymbol != oldSymbol { 287 changed = true 288 } 289 290 mapped += newSymbol 291 } 292 293 args = append(args, mapped) 294 } 295 296 if !changed { 297 d.writeNode(statement) 298 } else { 299 d.writeCommentedNode(statement) 300 d.output.WriteString("\t" + name + "\t" + strings.Join(args, ", ") + "\n") 301 } 302 303 if name == ".localentry" { 304 d.output.WriteString(localEntryName(args[0]) + ":\n") 305 } 306 307 return statement, nil 308} 309 310func (d *delocation) processLabel(statement, label *node32) (*node32, error) { 311 symbol := d.contents(label) 312 313 switch label.pegRule { 314 case ruleLocalLabel: 315 d.output.WriteString(symbol + ":\n") 316 case ruleLocalSymbol: 317 // symbols need to be mapped so that local symbols from two 318 // different .s inputs don't collide. 319 d.output.WriteString(d.mapLocalSymbol(symbol) + ":\n") 320 case ruleSymbolName: 321 d.output.WriteString(localTargetName(symbol) + ":\n") 322 d.writeNode(statement) 323 default: 324 return nil, fmt.Errorf("unknown label type %q", rul3s[label.pegRule]) 325 } 326 327 return statement, nil 328} 329 330// instructionArgs collects all the arguments to an instruction. 331func instructionArgs(node *node32) (argNodes []*node32) { 332 for node = skipWS(node); node != nil; node = skipWS(node.next) { 333 assertNodeType(node, ruleInstructionArg) 334 argNodes = append(argNodes, node.up) 335 } 336 337 return argNodes 338} 339 340/* ppc64le 341 342[PABI]: “64-Bit ELF V2 ABI Specification. Power Architecture.” March 21st, 343 2017 344 345(Also useful is “Power ISA Version 2.07 B”. Note that version three of that 346document is /not/ good as that's POWER9 specific.) 347 348ppc64le doesn't have IP-relative addressing and does a lot to work around this. 349Rather than reference a PLT and GOT direction, it has a single structure called 350the TOC (Table Of Contents). Within the TOC is the contents of .rodata, .data, 351.got, .plt, .bss, etc sections [PABI;3.3]. 352 353A pointer to the TOC is maintained in r2 and the following pattern is used to 354load the address of an element into a register: 355 356 addis <address register>, 2, foo@toc@ha 357 addi <address register>, <address register>, foo@toc@l 358 359The “addis” instruction shifts a signed constant left 16 bits and adds the 360result to its second argument, saving the result in the first argument. The 361“addi” instruction does the same, but without shifting. Thus the “@toc@ha" 362suffix on a symbol means “the top 16 bits of the TOC offset” and “@toc@l” means 363“the bottom 16 bits of the offset”. However, note that both values are signed, 364thus offsets in the top half of a 64KB chunk will have an @ha value that's one 365greater than expected and a negative @l value. 366 367The TOC is specific to a “module” (basically an executable or shared object). 368This means that there's not a single TOC in a process and that r2 needs to 369change as control moves between modules. Thus functions have two entry points: 370the “global” entry point and the “local” entry point. Jumps from within the 371same module can use the local entry while jumps from other modules must use the 372global entry. The global entry establishes the correct value of r2 before 373running the function and the local entry skips that code. 374 375The global entry point for a function is defined by its label. The local entry 376is a power-of-two number of bytes from the global entry, set by the 377“.localentry” directive. (ppc64le instructions are always 32 bits, so an offset 378of 1 or 2 bytes is treated as an offset of zero.) 379 380In order to help the global entry code set r2 to point to the local TOC, r12 is 381set to the address of the global entry point when called [PABI;2.2.1.1]. Thus 382the global entry will typically use an addis+addi pair to add a known offset to 383r12 and store it in r2. For example: 384 385foo: 386 addis 2, 12, .TOC. - foo@ha 387 addi 2, 2, .TOC. - foo@l 388 389(It's worth noting that the '@' operator binds very loosely, so the 3rd 390arguments parse as (.TOC. - foo)@ha and (.TOC. - foo)@l.) 391 392When calling a function, the compiler doesn't know whether that function is in 393the same module or not. Thus it doesn't know whether r12 needs to be set nor 394whether r2 will be clobbered on return. Rather than always assume the worst, 395the linker fixes stuff up once it knows that a call is going out of module: 396 397Firstly, calling, say, memcpy (which we assume to be in a different module) 398won't actually jump directly to memcpy, or even a PLT resolution function. 399It'll call a synthesised function that: 400 a) saves r2 in the caller's stack frame 401 b) loads the address of memcpy@PLT into r12 402 c) jumps to r12. 403 404As this synthesised function loads memcpy@PLT, a call to memcpy from the 405compiled code just references “memcpy” directly, not “memcpy@PLT”. 406 407Since it jumps directly to memcpy@PLT, it can't restore r2 on return. Thus 408calls must be followed by a nop. If the call ends up going out-of-module, the 409linker will rewrite that nop to load r2 from the stack. 410 411Speaking of the stack, the stack pointer is kept in r1 and there's a 288-byte 412red-zone. The format of the stack frame is defined [PABI;2.2.2] and must be 413followed as called functions will write into their parent's stack frame. For 414example, the synthesised out-of-module trampolines will save r2 24 bytes into 415the caller's frame and all non-leaf functions save the return address 16 bytes 416into the caller's frame. 417 418A final point worth noting: some RISC ISAs have r0 wired to zero: all reads 419result in zero and all writes are discarded. POWER does something a little like 420that, but r0 is only special in certain argument positions for certain 421instructions. You just have to read the manual to know which they are. 422 423 424Delocation is easier than Intel because there's just TOC references, but it's 425also harder because there's no IP-relative addressing. 426 427Jumps are IP-relative however, and have a 24-bit immediate value. So we can 428jump to functions that set a register to the needed value. (r3 is the 429return-value register and so that's what is generally used here.) */ 430 431// isPPC64LEAPair recognises an addis+addi pair that's adding the offset of 432// source to relative and writing the result to target. 433func (d *delocation) isPPC64LEAPair(statement *node32) (target, source, relative string, ok bool) { 434 instruction := skipWS(statement.up).up 435 assertNodeType(instruction, ruleInstructionName) 436 name1 := d.contents(instruction) 437 args1 := instructionArgs(instruction.next) 438 439 statement = statement.next 440 instruction = skipWS(statement.up).up 441 assertNodeType(instruction, ruleInstructionName) 442 name2 := d.contents(instruction) 443 args2 := instructionArgs(instruction.next) 444 445 if name1 != "addis" || 446 len(args1) != 3 || 447 name2 != "addi" || 448 len(args2) != 3 { 449 return "", "", "", false 450 } 451 452 target = d.contents(args1[0]) 453 relative = d.contents(args1[1]) 454 source1 := d.contents(args1[2]) 455 source2 := d.contents(args2[2]) 456 457 if !strings.HasSuffix(source1, "@ha") || 458 !strings.HasSuffix(source2, "@l") || 459 source1[:len(source1)-3] != source2[:len(source2)-2] || 460 d.contents(args2[0]) != target || 461 d.contents(args2[1]) != target { 462 return "", "", "", false 463 } 464 465 source = source1[:len(source1)-3] 466 ok = true 467 return 468} 469 470// establishTOC writes the global entry prelude for a function. The standard 471// prelude involves relocations so this version moves the relocation outside 472// the integrity-checked area. 473func establishTOC(w stringWriter) { 474 w.WriteString("999:\n") 475 w.WriteString("\taddis 2, 12, .LBORINGSSL_external_toc-999b@ha\n") 476 w.WriteString("\taddi 2, 2, .LBORINGSSL_external_toc-999b@l\n") 477 w.WriteString("\tld 12, 0(2)\n") 478 w.WriteString("\tadd 2, 2, 12\n") 479} 480 481// loadTOCFuncName returns the name of a synthesized function that sets r3 to 482// the value of “symbol+offset”. 483func loadTOCFuncName(symbol, offset string) string { 484 symbol = strings.Replace(symbol, ".", "_dot_", -1) 485 ret := ".Lbcm_loadtoc_" + symbol 486 if len(offset) != 0 { 487 offset = strings.Replace(offset, "+", "_plus_", -1) 488 offset = strings.Replace(offset, "-", "_minus_", -1) 489 ret += "_" + offset 490 } 491 return ret 492} 493 494func (d *delocation) loadFromTOC(w stringWriter, symbol, offset, dest string) wrapperFunc { 495 d.tocLoaders[symbol+"\x00"+offset] = struct{}{} 496 497 return func(k func()) { 498 w.WriteString("\taddi 1, 1, -288\n") // Clear the red zone. 499 w.WriteString("\tmflr " + dest + "\n") // Stash the link register. 500 w.WriteString("\tstd " + dest + ", -8(1)\n") 501 // The TOC loader will use r3, so stash it if necessary. 502 if dest != "3" { 503 w.WriteString("\tstd 3, -16(1)\n") 504 } 505 506 // Because loadTOCFuncName returns a “.L” name, we don't need a 507 // nop after this call. 508 w.WriteString("\tbl " + loadTOCFuncName(symbol, offset) + "\n") 509 510 // Cycle registers around. We need r3 -> destReg, -8(1) -> 511 // lr and, optionally, -16(1) -> r3. 512 w.WriteString("\tstd 3, -24(1)\n") 513 w.WriteString("\tld 3, -8(1)\n") 514 w.WriteString("\tmtlr 3\n") 515 w.WriteString("\tld " + dest + ", -24(1)\n") 516 if dest != "3" { 517 w.WriteString("\tld 3, -16(1)\n") 518 } 519 w.WriteString("\taddi 1, 1, 288\n") 520 521 k() 522 } 523} 524 525func (d *delocation) gatherOffsets(symRef *node32, offsets string) (*node32, string) { 526 for symRef != nil && symRef.pegRule == ruleOffset { 527 offset := d.contents(symRef) 528 if offset[0] != '+' && offset[0] != '-' { 529 offset = "+" + offset 530 } 531 offsets = offsets + offset 532 symRef = symRef.next 533 } 534 return symRef, offsets 535} 536 537func (d *delocation) parseMemRef(memRef *node32) (symbol, offset, section string, didChange, symbolIsLocal bool, nextRef *node32) { 538 if memRef.pegRule != ruleSymbolRef { 539 return "", "", "", false, false, memRef 540 } 541 542 symRef := memRef.up 543 nextRef = memRef.next 544 545 // (Offset* '+')? 546 symRef, offset = d.gatherOffsets(symRef, offset) 547 548 // (LocalSymbol / SymbolName) 549 symbol = d.contents(symRef) 550 if symRef.pegRule == ruleLocalSymbol { 551 symbolIsLocal = true 552 mapped := d.mapLocalSymbol(symbol) 553 if mapped != symbol { 554 symbol = mapped 555 didChange = true 556 } 557 } 558 symRef = symRef.next 559 560 // Offset* 561 symRef, offset = d.gatherOffsets(symRef, offset) 562 563 // ('@' Section / Offset*)? 564 if symRef != nil { 565 assertNodeType(symRef, ruleSection) 566 section = d.contents(symRef) 567 symRef = symRef.next 568 569 symRef, offset = d.gatherOffsets(symRef, offset) 570 } 571 572 if symRef != nil { 573 panic(fmt.Sprintf("unexpected token in SymbolRef: %q", rul3s[symRef.pegRule])) 574 } 575 576 return 577} 578 579func (d *delocation) processPPCInstruction(statement, instruction *node32) (*node32, error) { 580 assertNodeType(instruction, ruleInstructionName) 581 instructionName := d.contents(instruction) 582 isBranch := instructionName[0] == 'b' 583 584 argNodes := instructionArgs(instruction.next) 585 586 var wrappers wrapperStack 587 var args []string 588 changed := false 589 590Args: 591 for i, arg := range argNodes { 592 fullArg := arg 593 isIndirect := false 594 595 if arg.pegRule == ruleIndirectionIndicator { 596 arg = arg.next 597 isIndirect = true 598 } 599 600 switch arg.pegRule { 601 case ruleRegisterOrConstant, ruleLocalLabelRef: 602 args = append(args, d.contents(fullArg)) 603 604 case ruleTOCRefLow: 605 return nil, errors.New("Found low TOC reference outside preamble pattern") 606 607 case ruleTOCRefHigh: 608 target, _, relative, ok := d.isPPC64LEAPair(statement) 609 if !ok { 610 return nil, errors.New("Found high TOC reference outside preamble pattern") 611 } 612 613 if relative != "12" { 614 return nil, fmt.Errorf("preamble is relative to %q, not r12", relative) 615 } 616 617 if target != "2" { 618 return nil, fmt.Errorf("preamble is setting %q, not r2", target) 619 } 620 621 statement = statement.next 622 establishTOC(d.output) 623 instructionName = "" 624 changed = true 625 break Args 626 627 case ruleMemoryRef: 628 symbol, offset, section, didChange, symbolIsLocal, memRef := d.parseMemRef(arg.up) 629 changed = didChange 630 631 if len(symbol) > 0 { 632 if _, localEntrySymbol := d.localEntrySymbols[symbol]; localEntrySymbol && isBranch { 633 symbol = localEntryName(symbol) 634 changed = true 635 } else if _, knownSymbol := d.symbols[symbol]; knownSymbol { 636 symbol = localTargetName(symbol) 637 changed = true 638 } else if !symbolIsLocal && !isSynthesized(symbol) && len(section) == 0 { 639 changed = true 640 d.redirectors[symbol] = redirectorName(symbol) 641 symbol = redirectorName(symbol) 642 // TODO(davidben): This should sanity-check the next 643 // instruction is a nop and ideally remove it. 644 wrappers = append(wrappers, func(k func()) { 645 k() 646 // Like the linker's PLT stubs, redirector functions 647 // expect callers to restore r2. 648 d.output.WriteString("\tld 2, 24(1)\n") 649 }) 650 } 651 } 652 653 switch section { 654 case "": 655 656 case "tls": 657 // This section identifier just tells the 658 // assembler to use r13, the pointer to the 659 // thread-local data [PABI;3.7.3.3]. 660 661 case "toc@ha": 662 // Delete toc@ha instructions. Per 663 // [PABI;3.6.3], the linker is allowed to erase 664 // toc@ha instructions. We take advantage of 665 // this by unconditionally erasing the toc@ha 666 // instructions and doing the full lookup when 667 // processing toc@l. 668 // 669 // Note that any offset here applies before @ha 670 // and @l. That is, 42+foo@toc@ha is 671 // #ha(42+foo-.TOC.), not 42+#ha(foo-.TOC.). Any 672 // corresponding toc@l references are required 673 // by the ABI to have the same offset. The 674 // offset will be incorporated in full when 675 // those are processed. 676 if instructionName != "addis" || len(argNodes) != 3 || i != 2 || args[1] != "2" { 677 return nil, errors.New("can't process toc@ha reference") 678 } 679 changed = true 680 instructionName = "" 681 break Args 682 683 case "toc@l": 684 // Per [PAB;3.6.3], this instruction must take 685 // as input a register which was the output of 686 // a toc@ha computation and compute the actual 687 // address of some symbol. The toc@ha 688 // computation was elided, so we ignore that 689 // input register and compute the address 690 // directly. 691 changed = true 692 693 // For all supported toc@l instructions, the 694 // destination register is the first argument. 695 destReg := args[0] 696 697 wrappers = append(wrappers, d.loadFromTOC(d.output, symbol, offset, destReg)) 698 switch instructionName { 699 case "addi": 700 // The original instruction was: 701 // addi destReg, tocHaReg, offset+symbol@toc@l 702 instructionName = "" 703 704 case "ld", "lhz", "lwz": 705 // The original instruction was: 706 // l?? destReg, offset+symbol@toc@l(tocHaReg) 707 // 708 // We transform that into the 709 // equivalent dereference of destReg: 710 // l?? destReg, 0(destReg) 711 origInstructionName := instructionName 712 instructionName = "" 713 714 assertNodeType(memRef, ruleBaseIndexScale) 715 assertNodeType(memRef.up, ruleRegisterOrConstant) 716 if memRef.next != nil || memRef.up.next != nil { 717 return nil, errors.New("expected single register in BaseIndexScale for ld argument") 718 } 719 720 baseReg := destReg 721 if baseReg == "0" { 722 // Register zero is special as the base register for a load. 723 // Avoid it by spilling and using r3 instead. 724 baseReg = "3" 725 wrappers = append(wrappers, func(k func()) { 726 d.output.WriteString("\taddi 1, 1, -288\n") // Clear the red zone. 727 d.output.WriteString("\tstd " + baseReg + ", -8(1)\n") 728 d.output.WriteString("\tmr " + baseReg + ", " + destReg + "\n") 729 k() 730 d.output.WriteString("\tld " + baseReg + ", -8(1)\n") 731 d.output.WriteString("\taddi 1, 1, 288\n") // Clear the red zone. 732 }) 733 } 734 735 wrappers = append(wrappers, func(k func()) { 736 d.output.WriteString("\t" + origInstructionName + " " + destReg + ", 0(" + baseReg + ")\n") 737 }) 738 default: 739 return nil, fmt.Errorf("can't process TOC argument to %q", instructionName) 740 } 741 742 default: 743 return nil, fmt.Errorf("Unknown section type %q", section) 744 } 745 746 argStr := "" 747 if isIndirect { 748 argStr += "*" 749 } 750 argStr += symbol 751 if len(offset) > 0 { 752 argStr += offset 753 } 754 if len(section) > 0 { 755 argStr += "@" 756 argStr += section 757 } 758 759 for ; memRef != nil; memRef = memRef.next { 760 argStr += d.contents(memRef) 761 } 762 763 args = append(args, argStr) 764 765 default: 766 panic(fmt.Sprintf("unknown instruction argument type %q", rul3s[arg.pegRule])) 767 } 768 } 769 770 if changed { 771 d.writeCommentedNode(statement) 772 773 var replacement string 774 if len(instructionName) > 0 { 775 replacement = "\t" + instructionName + "\t" + strings.Join(args, ", ") + "\n" 776 } 777 778 wrappers.do(func() { 779 d.output.WriteString(replacement) 780 }) 781 } else { 782 d.writeNode(statement) 783 } 784 785 return statement, nil 786} 787 788/* Intel */ 789 790type instructionType int 791 792const ( 793 instrPush instructionType = iota 794 instrMove 795 instrJump 796 instrConditionalMove 797 instrOther 798) 799 800func classifyInstruction(instr string, args []*node32) instructionType { 801 switch instr { 802 case "push", "pushq": 803 if len(args) == 1 { 804 return instrPush 805 } 806 807 case "mov", "movq", "vmovq": 808 if len(args) == 2 { 809 return instrMove 810 } 811 812 case "cmovneq", "cmoveq": 813 if len(args) == 2 { 814 return instrConditionalMove 815 } 816 817 case "call", "callq", "jmp", "jo", "jno", "js", "jns", "je", "jz", "jne", "jnz", "jb", "jnae", "jc", "jnb", "jae", "jnc", "jbe", "jna", "ja", "jnbe", "jl", "jnge", "jge", "jnl", "jle", "jng", "jg", "jnle", "jp", "jpe", "jnp", "jpo": 818 if len(args) == 1 { 819 return instrJump 820 } 821 } 822 823 return instrOther 824} 825 826func push(w stringWriter) wrapperFunc { 827 return func(k func()) { 828 w.WriteString("\tpushq %rax\n") 829 k() 830 w.WriteString("\txchg %rax, (%rsp)\n") 831 } 832} 833 834func (d *delocation) loadFromGOT(w stringWriter, destination, symbol, section string, redzoneCleared bool) wrapperFunc { 835 d.gotExternalsNeeded[symbol+"@"+section] = struct{}{} 836 837 return func(k func()) { 838 if !redzoneCleared { 839 w.WriteString("\tleaq -128(%rsp), %rsp\n") // Clear the red zone. 840 } 841 w.WriteString("\tpushf\n") 842 w.WriteString(fmt.Sprintf("\tleaq %s_%s_external(%%rip), %s\n", symbol, section, destination)) 843 w.WriteString(fmt.Sprintf("\taddq (%s), %s\n", destination, destination)) 844 w.WriteString(fmt.Sprintf("\tmovq (%s), %s\n", destination, destination)) 845 w.WriteString("\tpopf\n") 846 if !redzoneCleared { 847 w.WriteString("\tleaq\t128(%rsp), %rsp\n") 848 } 849 } 850} 851 852func saveRegister(w stringWriter) wrapperFunc { 853 return func(k func()) { 854 w.WriteString("\tleaq -128(%rsp), %rsp\n") // Clear the red zone. 855 w.WriteString("\tpushq %rax\n") 856 k() 857 w.WriteString("\tpopq %rax\n") 858 w.WriteString("\tleaq 128(%rsp), %rsp\n") 859 } 860} 861 862func moveTo(w stringWriter, target string) wrapperFunc { 863 return func(k func()) { 864 k() 865 w.WriteString("\tmovq %rax, " + target + "\n") 866 } 867} 868 869func isValidLEATarget(reg string) bool { 870 return !strings.HasPrefix(reg, "%xmm") && !strings.HasPrefix(reg, "%ymm") && !strings.HasPrefix(reg, "%zmm") 871} 872 873func undoConditionalMove(w stringWriter, instr string) wrapperFunc { 874 var invertedCondition string 875 876 switch instr { 877 case "cmoveq": 878 invertedCondition = "ne" 879 case "cmovneq": 880 invertedCondition = "e" 881 default: 882 panic(fmt.Sprintf("don't know how to handle conditional move instruction %q", instr)) 883 } 884 885 return func(k func()) { 886 w.WriteString("\tj" + invertedCondition + " 999f\n") 887 k() 888 w.WriteString("999:\n") 889 } 890} 891 892func (d *delocation) isRIPRelative(node *node32) bool { 893 return node != nil && node.pegRule == ruleBaseIndexScale && d.contents(node) == "(%rip)" 894} 895 896func (d *delocation) processIntelInstruction(statement, instruction *node32) (*node32, error) { 897 assertNodeType(instruction, ruleInstructionName) 898 instructionName := d.contents(instruction) 899 900 argNodes := instructionArgs(instruction.next) 901 902 var wrappers wrapperStack 903 var args []string 904 changed := false 905 906Args: 907 for i, arg := range argNodes { 908 fullArg := arg 909 isIndirect := false 910 911 if arg.pegRule == ruleIndirectionIndicator { 912 arg = arg.next 913 isIndirect = true 914 } 915 916 switch arg.pegRule { 917 case ruleRegisterOrConstant, ruleLocalLabelRef: 918 args = append(args, d.contents(fullArg)) 919 920 case ruleMemoryRef: 921 symbol, offset, section, didChange, symbolIsLocal, memRef := d.parseMemRef(arg.up) 922 changed = didChange 923 924 if symbol == "OPENSSL_ia32cap_P" { 925 var ok bool 926 if section == "GOTPCREL" { 927 ok = instructionName == "movq" 928 } else if section == "" { 929 ok = instructionName == "leaq" 930 } 931 932 if !ok { 933 return nil, fmt.Errorf("instruction %q referenced OPENSSL_ia32cap_P in section %q, should be a movq from GOTPCREL or a direct leaq", instructionName, section) 934 } 935 936 if i != 0 || len(argNodes) != 2 || !d.isRIPRelative(memRef) || len(offset) > 0 { 937 return nil, fmt.Errorf("invalid OPENSSL_ia32cap_P reference in instruction %q", instructionName) 938 } 939 940 target := argNodes[1] 941 assertNodeType(target, ruleRegisterOrConstant) 942 reg := d.contents(target) 943 944 if !strings.HasPrefix(reg, "%r") { 945 return nil, fmt.Errorf("tried to load OPENSSL_ia32cap_P into %q, which is not a standard register.", reg) 946 } 947 948 changed = true 949 wrappers = append(wrappers, func(k func()) { 950 d.output.WriteString("\tleaq\t-128(%rsp), %rsp\n") // Clear the red zone. 951 d.output.WriteString("\tpushfq\n") 952 d.output.WriteString("\tleaq\tOPENSSL_ia32cap_addr_delta(%rip), " + reg + "\n") 953 d.output.WriteString("\taddq\t(" + reg + "), " + reg + "\n") 954 d.output.WriteString("\tpopfq\n") 955 d.output.WriteString("\tleaq\t128(%rsp), %rsp\n") 956 }) 957 958 break Args 959 } 960 961 switch section { 962 case "": 963 if _, knownSymbol := d.symbols[symbol]; knownSymbol { 964 symbol = localTargetName(symbol) 965 changed = true 966 } 967 968 case "PLT": 969 if classifyInstruction(instructionName, argNodes) != instrJump { 970 return nil, fmt.Errorf("Cannot rewrite PLT reference for non-jump instruction %q", instructionName) 971 } 972 973 if _, knownSymbol := d.symbols[symbol]; knownSymbol { 974 symbol = localTargetName(symbol) 975 changed = true 976 } else if !symbolIsLocal && !isSynthesized(symbol) { 977 // Unknown symbol via PLT is an 978 // out-call from the module, e.g. 979 // memcpy. 980 d.redirectors[symbol+"@"+section] = redirectorName(symbol) 981 symbol = redirectorName(symbol) 982 } 983 984 changed = true 985 986 case "GOTPCREL": 987 if len(offset) > 0 { 988 return nil, errors.New("loading from GOT with offset is unsupported") 989 } 990 if i != 0 { 991 return nil, errors.New("GOT access must be source operand") 992 } 993 if !d.isRIPRelative(memRef) { 994 return nil, errors.New("GOT access must be IP-relative") 995 } 996 997 useGOT := false 998 if _, knownSymbol := d.symbols[symbol]; knownSymbol { 999 symbol = localTargetName(symbol) 1000 changed = true 1001 } else if !isSynthesized(symbol) { 1002 useGOT = true 1003 } 1004 1005 // Reduce the instruction to movq symbol@GOTPCREL, targetReg. 1006 var targetReg string 1007 switch classifyInstruction(instructionName, argNodes) { 1008 case instrPush: 1009 wrappers = append(wrappers, push(d.output)) 1010 targetReg = "%rax" 1011 case instrConditionalMove: 1012 wrappers = append(wrappers, undoConditionalMove(d.output, instructionName)) 1013 fallthrough 1014 case instrMove: 1015 assertNodeType(argNodes[1], ruleRegisterOrConstant) 1016 targetReg = d.contents(argNodes[1]) 1017 default: 1018 return nil, fmt.Errorf("Cannot rewrite GOTPCREL reference for instruction %q", instructionName) 1019 } 1020 1021 var redzoneCleared bool 1022 if !isValidLEATarget(targetReg) { 1023 // Sometimes the compiler will load from the GOT to an 1024 // XMM register, which is not a valid target of an LEA 1025 // instruction. 1026 wrappers = append(wrappers, saveRegister(d.output)) 1027 wrappers = append(wrappers, moveTo(d.output, targetReg)) 1028 targetReg = "%rax" 1029 redzoneCleared = true 1030 } 1031 1032 if useGOT { 1033 wrappers = append(wrappers, d.loadFromGOT(d.output, targetReg, symbol, section, redzoneCleared)) 1034 } else { 1035 wrappers = append(wrappers, func(k func()) { 1036 d.output.WriteString(fmt.Sprintf("\tleaq\t%s(%%rip), %s\n", symbol, targetReg)) 1037 }) 1038 } 1039 changed = true 1040 break Args 1041 1042 default: 1043 return nil, fmt.Errorf("Unknown section type %q", section) 1044 } 1045 1046 if !changed && len(section) > 0 { 1047 panic("section was not handled") 1048 } 1049 section = "" 1050 1051 argStr := "" 1052 if isIndirect { 1053 argStr += "*" 1054 } 1055 argStr += symbol 1056 argStr += offset 1057 1058 for ; memRef != nil; memRef = memRef.next { 1059 argStr += d.contents(memRef) 1060 } 1061 1062 args = append(args, argStr) 1063 1064 default: 1065 panic(fmt.Sprintf("unknown instruction argument type %q", rul3s[arg.pegRule])) 1066 } 1067 } 1068 1069 if changed { 1070 d.writeCommentedNode(statement) 1071 replacement := "\t" + instructionName + "\t" + strings.Join(args, ", ") + "\n" 1072 wrappers.do(func() { 1073 d.output.WriteString(replacement) 1074 }) 1075 } else { 1076 d.writeNode(statement) 1077 } 1078 1079 return statement, nil 1080} 1081 1082func (d *delocation) handleBSS(statement *node32) (*node32, error) { 1083 lastStatement := statement 1084 for statement = statement.next; statement != nil; lastStatement, statement = statement, statement.next { 1085 node := skipWS(statement.up) 1086 if node == nil { 1087 d.writeNode(statement) 1088 continue 1089 } 1090 1091 switch node.pegRule { 1092 case ruleGlobalDirective, ruleComment, ruleInstruction, ruleLocationDirective: 1093 d.writeNode(statement) 1094 1095 case ruleDirective: 1096 directive := node.up 1097 assertNodeType(directive, ruleDirectiveName) 1098 directiveName := d.contents(directive) 1099 if directiveName == "text" || directiveName == "section" || directiveName == "data" { 1100 return lastStatement, nil 1101 } 1102 d.writeNode(statement) 1103 1104 case ruleLabel: 1105 label := node.up 1106 d.writeNode(statement) 1107 1108 if label.pegRule != ruleLocalSymbol { 1109 symbol := d.contents(label) 1110 localSymbol := localTargetName(symbol) 1111 d.output.WriteString(fmt.Sprintf("\n%s:\n", localSymbol)) 1112 1113 d.bssAccessorsNeeded[symbol] = localSymbol 1114 } 1115 1116 case ruleLabelContainingDirective: 1117 var err error 1118 statement, err = d.processLabelContainingDirective(statement, node.up) 1119 if err != nil { 1120 return nil, err 1121 } 1122 1123 default: 1124 return nil, fmt.Errorf("unknown BSS statement type %q in %q", rul3s[node.pegRule], d.contents(statement)) 1125 } 1126 } 1127 1128 return lastStatement, nil 1129} 1130 1131func transform(w stringWriter, inputs []inputFile) error { 1132 // symbols contains all defined symbols. 1133 symbols := make(map[string]struct{}) 1134 // localEntrySymbols contains all symbols with a .localentry directive. 1135 localEntrySymbols := make(map[string]struct{}) 1136 1137 for _, input := range inputs { 1138 forEachPath(input.ast.up, func(node *node32) { 1139 symbol := input.contents[node.begin:node.end] 1140 if _, ok := symbols[symbol]; ok { 1141 panic(fmt.Sprintf("Duplicate symbol found: %q in %q", symbol, input.path)) 1142 } 1143 symbols[symbol] = struct{}{} 1144 }, ruleStatement, ruleLabel, ruleSymbolName) 1145 1146 forEachPath(input.ast.up, func(node *node32) { 1147 node = node.up 1148 assertNodeType(node, ruleLabelContainingDirectiveName) 1149 directive := input.contents[node.begin:node.end] 1150 if directive != ".localentry" { 1151 return 1152 } 1153 // Extract the first argument. 1154 node = skipWS(node.next) 1155 assertNodeType(node, ruleSymbolArgs) 1156 node = node.up 1157 assertNodeType(node, ruleSymbolArg) 1158 symbol := input.contents[node.begin:node.end] 1159 if _, ok := localEntrySymbols[symbol]; ok { 1160 panic(fmt.Sprintf("Duplicate .localentry directive found: %q in %q", symbol, input.path)) 1161 } 1162 localEntrySymbols[symbol] = struct{}{} 1163 }, ruleStatement, ruleLabelContainingDirective) 1164 } 1165 1166 processor := x86_64 1167 if len(inputs) > 0 { 1168 processor = detectProcessor(inputs[0]) 1169 } 1170 1171 d := &delocation{ 1172 symbols: symbols, 1173 localEntrySymbols: localEntrySymbols, 1174 processor: processor, 1175 output: w, 1176 redirectors: make(map[string]string), 1177 bssAccessorsNeeded: make(map[string]string), 1178 tocLoaders: make(map[string]struct{}), 1179 gotExternalsNeeded: make(map[string]struct{}), 1180 } 1181 1182 w.WriteString(".text\nBORINGSSL_bcm_text_start:\n") 1183 1184 for _, input := range inputs { 1185 if err := d.processInput(input); err != nil { 1186 return err 1187 } 1188 } 1189 1190 w.WriteString(".text\nBORINGSSL_bcm_text_end:\n") 1191 1192 // Emit redirector functions. Each is a single jump instruction. 1193 var redirectorNames []string 1194 for name := range d.redirectors { 1195 redirectorNames = append(redirectorNames, name) 1196 } 1197 sort.Strings(redirectorNames) 1198 1199 for _, name := range redirectorNames { 1200 redirector := d.redirectors[name] 1201 if d.processor == ppc64le { 1202 w.WriteString(".section \".toc\", \"aw\"\n") 1203 w.WriteString(".Lredirector_toc_" + name + ":\n") 1204 w.WriteString(".quad " + name + "\n") 1205 w.WriteString(".text\n") 1206 w.WriteString(".type " + redirector + ", @function\n") 1207 w.WriteString(redirector + ":\n") 1208 // |name| will clobber r2, so save it. This is matched by a restore in 1209 // redirector calls. 1210 w.WriteString("\tstd 2, 24(1)\n") 1211 // Load and call |name|'s global entry point. 1212 w.WriteString("\taddis 12, 2, .Lredirector_toc_" + name + "@toc@ha\n") 1213 w.WriteString("\tld 12, .Lredirector_toc_" + name + "@toc@l(12)\n") 1214 w.WriteString("\tmtctr 12\n") 1215 w.WriteString("\tbctr\n") 1216 } else { 1217 w.WriteString(".type " + redirector + ", @function\n") 1218 w.WriteString(redirector + ":\n") 1219 w.WriteString("\tjmp\t" + name + "\n") 1220 } 1221 } 1222 1223 var accessorNames []string 1224 for accessor := range d.bssAccessorsNeeded { 1225 accessorNames = append(accessorNames, accessor) 1226 } 1227 sort.Strings(accessorNames) 1228 1229 // Emit BSS accessor functions. Each is a single LEA followed by RET. 1230 for _, name := range accessorNames { 1231 funcName := accessorName(name) 1232 w.WriteString(".type " + funcName + ", @function\n") 1233 w.WriteString(funcName + ":\n") 1234 target := d.bssAccessorsNeeded[name] 1235 1236 if d.processor == ppc64le { 1237 w.WriteString("\taddis 3, 2, " + target + "@toc@ha\n") 1238 w.WriteString("\taddi 3, 3, " + target + "@toc@l\n") 1239 w.WriteString("\tblr\n") 1240 } else { 1241 w.WriteString("\tleaq\t" + target + "(%rip), %rax\n\tret\n") 1242 } 1243 } 1244 1245 if d.processor == ppc64le { 1246 loadTOCNames := sortedSet(d.tocLoaders) 1247 for _, symbolAndOffset := range loadTOCNames { 1248 parts := strings.SplitN(symbolAndOffset, "\x00", 2) 1249 symbol, offset := parts[0], parts[1] 1250 1251 funcName := loadTOCFuncName(symbol, offset) 1252 ref := symbol + offset 1253 1254 w.WriteString(".type " + funcName[2:] + ", @function\n") 1255 w.WriteString(funcName[2:] + ":\n") 1256 w.WriteString(funcName + ":\n") 1257 w.WriteString("\taddis 3, 2, " + ref + "@toc@ha\n") 1258 w.WriteString("\taddi 3, 3, " + ref + "@toc@l\n") 1259 w.WriteString("\tblr\n") 1260 } 1261 1262 w.WriteString(".LBORINGSSL_external_toc:\n") 1263 w.WriteString(".quad .TOC.-.LBORINGSSL_external_toc\n") 1264 } else { 1265 externalNames := sortedSet(d.gotExternalsNeeded) 1266 for _, name := range externalNames { 1267 parts := strings.SplitN(name, "@", 2) 1268 symbol, section := parts[0], parts[1] 1269 w.WriteString(".type " + symbol + "_" + section + "_external, @object\n") 1270 w.WriteString(".size " + symbol + "_" + section + "_external, 8\n") 1271 w.WriteString(symbol + "_" + section + "_external:\n") 1272 // Ideally this would be .quad foo@GOTPCREL, but clang's 1273 // assembler cannot emit a 64-bit GOTPCREL relocation. Instead, 1274 // we manually sign-extend the value, knowing that the GOT is 1275 // always at the end, thus foo@GOTPCREL has a positive value. 1276 w.WriteString("\t.long " + symbol + "@" + section + "\n") 1277 w.WriteString("\t.long 0\n") 1278 } 1279 1280 w.WriteString(".type OPENSSL_ia32cap_get, @function\n") 1281 w.WriteString("OPENSSL_ia32cap_get:\n") 1282 w.WriteString("\tleaq OPENSSL_ia32cap_P(%rip), %rax\n") 1283 w.WriteString("\tret\n") 1284 1285 w.WriteString(".extern OPENSSL_ia32cap_P\n") 1286 w.WriteString(".type OPENSSL_ia32cap_addr_delta, @object\n") 1287 w.WriteString(".size OPENSSL_ia32cap_addr_delta, 8\n") 1288 w.WriteString("OPENSSL_ia32cap_addr_delta:\n") 1289 w.WriteString(".quad OPENSSL_ia32cap_P-OPENSSL_ia32cap_addr_delta\n") 1290 } 1291 1292 w.WriteString(".type BORINGSSL_bcm_text_hash, @object\n") 1293 w.WriteString(".size BORINGSSL_bcm_text_hash, 64\n") 1294 w.WriteString("BORINGSSL_bcm_text_hash:\n") 1295 for _, b := range uninitHashValue { 1296 w.WriteString(".byte 0x" + strconv.FormatUint(uint64(b), 16) + "\n") 1297 } 1298 1299 return nil 1300} 1301 1302func parseInputs(inputs []inputFile) error { 1303 for i, input := range inputs { 1304 var contents string 1305 1306 if input.isArchive { 1307 arFile, err := os.Open(input.path) 1308 if err != nil { 1309 return err 1310 } 1311 defer arFile.Close() 1312 1313 ar, err := ParseAR(arFile) 1314 if err != nil { 1315 return err 1316 } 1317 1318 if len(ar) != 1 { 1319 return fmt.Errorf("expected one file in archive, but found %d", len(ar)) 1320 } 1321 1322 for _, c := range ar { 1323 contents = string(c) 1324 } 1325 } else { 1326 inBytes, err := ioutil.ReadFile(input.path) 1327 if err != nil { 1328 return err 1329 } 1330 1331 contents = string(inBytes) 1332 } 1333 1334 asm := Asm{Buffer: contents, Pretty: true} 1335 asm.Init() 1336 if err := asm.Parse(); err != nil { 1337 return fmt.Errorf("error while parsing %q: %s", input.path, err) 1338 } 1339 ast := asm.AST() 1340 1341 inputs[i].contents = contents 1342 inputs[i].ast = ast 1343 } 1344 1345 return nil 1346} 1347 1348func main() { 1349 // The .a file, if given, is expected to be an archive of textual 1350 // assembly sources. That's odd, but CMake really wants to create 1351 // archive files so it's the only way that we can make it work. 1352 arInput := flag.String("a", "", "Path to a .a file containing assembly sources") 1353 outFile := flag.String("o", "", "Path to output assembly") 1354 1355 flag.Parse() 1356 1357 if len(*outFile) == 0 { 1358 fmt.Fprintf(os.Stderr, "Must give argument to -o.\n") 1359 os.Exit(1) 1360 } 1361 1362 var inputs []inputFile 1363 if len(*arInput) > 0 { 1364 inputs = append(inputs, inputFile{ 1365 path: *arInput, 1366 index: 0, 1367 isArchive: true, 1368 }) 1369 } 1370 1371 for i, path := range flag.Args() { 1372 if len(path) == 0 { 1373 continue 1374 } 1375 1376 inputs = append(inputs, inputFile{ 1377 path: path, 1378 index: i + 1, 1379 }) 1380 } 1381 1382 if err := parseInputs(inputs); err != nil { 1383 fmt.Fprintf(os.Stderr, "%s\n", err) 1384 os.Exit(1) 1385 } 1386 1387 out, err := os.OpenFile(*outFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644) 1388 if err != nil { 1389 panic(err) 1390 } 1391 defer out.Close() 1392 1393 if err := transform(out, inputs); err != nil { 1394 fmt.Fprintf(os.Stderr, "%s\n", err) 1395 os.Exit(1) 1396 } 1397} 1398 1399func forEachPath(node *node32, cb func(*node32), rules ...pegRule) { 1400 if node == nil { 1401 return 1402 } 1403 1404 if len(rules) == 0 { 1405 cb(node) 1406 return 1407 } 1408 1409 rule := rules[0] 1410 childRules := rules[1:] 1411 1412 for ; node != nil; node = node.next { 1413 if node.pegRule != rule { 1414 continue 1415 } 1416 1417 if len(childRules) == 0 { 1418 cb(node) 1419 } else { 1420 forEachPath(node.up, cb, childRules...) 1421 } 1422 } 1423} 1424 1425func skipNodes(node *node32, ruleToSkip pegRule) *node32 { 1426 for ; node != nil && node.pegRule == ruleToSkip; node = node.next { 1427 } 1428 return node 1429} 1430 1431func skipWS(node *node32) *node32 { 1432 return skipNodes(node, ruleWS) 1433} 1434 1435func assertNodeType(node *node32, expected pegRule) { 1436 if rule := node.pegRule; rule != expected { 1437 panic(fmt.Sprintf("node was %q, but wanted %q", rul3s[rule], rul3s[expected])) 1438 } 1439} 1440 1441type wrapperFunc func(func()) 1442 1443type wrapperStack []wrapperFunc 1444 1445func (w *wrapperStack) do(baseCase func()) { 1446 if len(*w) == 0 { 1447 baseCase() 1448 return 1449 } 1450 1451 wrapper := (*w)[0] 1452 *w = (*w)[1:] 1453 wrapper(func() { w.do(baseCase) }) 1454} 1455 1456// localTargetName returns the name of the local target label for a global 1457// symbol named name. 1458func localTargetName(name string) string { 1459 return ".L" + name + "_local_target" 1460} 1461 1462func localEntryName(name string) string { 1463 return ".L" + name + "_local_entry" 1464} 1465 1466func isSynthesized(symbol string) bool { 1467 return strings.HasSuffix(symbol, "_bss_get") || 1468 symbol == "OPENSSL_ia32cap_get" || 1469 strings.HasPrefix(symbol, "BORINGSSL_bcm_text_") 1470} 1471 1472func redirectorName(symbol string) string { 1473 return "bcm_redirector_" + symbol 1474} 1475 1476// sectionType returns the type of a section. I.e. a section called “.text.foo” 1477// is a “.text” section. 1478func sectionType(section string) (string, bool) { 1479 if len(section) == 0 || section[0] != '.' { 1480 return "", false 1481 } 1482 1483 i := strings.Index(section[1:], ".") 1484 if i != -1 { 1485 section = section[:i+1] 1486 } 1487 1488 if strings.HasPrefix(section, ".debug_") { 1489 return ".debug", true 1490 } 1491 1492 return section, true 1493} 1494 1495// accessorName returns the name of the accessor function for a BSS symbol 1496// named name. 1497func accessorName(name string) string { 1498 return name + "_bss_get" 1499} 1500 1501func (d *delocation) mapLocalSymbol(symbol string) string { 1502 if d.currentInput.index == 0 { 1503 return symbol 1504 } 1505 return symbol + "_BCM_" + strconv.Itoa(d.currentInput.index) 1506} 1507 1508func detectProcessor(input inputFile) processorType { 1509 for statement := input.ast.up; statement != nil; statement = statement.next { 1510 node := skipNodes(statement.up, ruleWS) 1511 if node == nil || node.pegRule != ruleInstruction { 1512 continue 1513 } 1514 1515 instruction := node.up 1516 instructionName := input.contents[instruction.begin:instruction.end] 1517 1518 switch instructionName { 1519 case "movq", "call", "leaq": 1520 return x86_64 1521 case "addis", "addi", "mflr": 1522 return ppc64le 1523 } 1524 } 1525 1526 panic("processed entire input and didn't recognise any instructions.") 1527} 1528 1529func sortedSet(m map[string]struct{}) []string { 1530 ret := make([]string, 0, len(m)) 1531 for key := range m { 1532 ret = append(ret, key) 1533 } 1534 sort.Strings(ret) 1535 return ret 1536} 1537