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