1// Copyright 2018 The BoringSSL Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//go:build ignore
16
17// This program takes a file containing newline-separated symbols, and generates
18// boringssl_prefix_symbols.h, boringssl_prefix_symbols_asm.h, and
19// boringssl_prefix_symbols_nasm.inc. These header files can be used to build
20// BoringSSL with a prefix for all symbols in order to avoid symbol name
21// conflicts when linking a project with multiple copies of BoringSSL; see
22// BUILDING.md for more details.
23package main
24
25// TODO(joshlf): For platforms which support it, use '#pragma redefine_extname'
26// instead of a custom macro. This avoids the need for a custom macro, but also
27// ensures that our renaming won't conflict with symbols defined and used by our
28// consumers (the "HMAC" problem). An example of this approach can be seen in
29// IllumOS' fork of OpenSSL:
30// https://github.com/joyent/illumos-extra/blob/master/openssl1x/sunw_prefix.h
31
32import (
33	"bufio"
34	"flag"
35	"fmt"
36	"os"
37	"path/filepath"
38	"strings"
39)
40
41var out = flag.String("out", ".", "Path to a directory where the outputs will be written")
42
43// Read newline-separated symbols from a file, ignoring any comments started
44// with '#'.
45func readSymbols(path string) ([]string, error) {
46	f, err := os.Open(path)
47	if err != nil {
48		return nil, err
49	}
50	defer f.Close()
51	scanner := bufio.NewScanner(f)
52	var ret []string
53	for scanner.Scan() {
54		line := scanner.Text()
55		if idx := strings.IndexByte(line, '#'); idx >= 0 {
56			line = line[:idx]
57		}
58		line = strings.TrimSpace(line)
59		if len(line) == 0 {
60			continue
61		}
62		ret = append(ret, line)
63	}
64	if err := scanner.Err(); err != nil {
65		return nil, err
66	}
67	return ret, nil
68}
69
70func writeCHeader(symbols []string, path string) error {
71	f, err := os.Create(path)
72	if err != nil {
73		return err
74	}
75	defer f.Close()
76
77	if _, err := f.WriteString(`// Copyright 2018 The BoringSSL Authors
78//
79// Licensed under the Apache License, Version 2.0 (the "License");
80// you may not use this file except in compliance with the License.
81// You may obtain a copy of the License at
82//
83//     https://www.apache.org/licenses/LICENSE-2.0
84//
85// Unless required by applicable law or agreed to in writing, software
86// distributed under the License is distributed on an "AS IS" BASIS,
87// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
88// See the License for the specific language governing permissions and
89// limitations under the License.
90
91// BORINGSSL_ADD_PREFIX pastes two identifiers into one. It performs one
92// iteration of macro expansion on its arguments before pasting.
93#define BORINGSSL_ADD_PREFIX(a, b) BORINGSSL_ADD_PREFIX_INNER(a, b)
94#define BORINGSSL_ADD_PREFIX_INNER(a, b) a ## _ ## b
95
96`); err != nil {
97		return err
98	}
99
100	for _, symbol := range symbols {
101		if _, err := fmt.Fprintf(f, "#define %s BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, %s)\n", symbol, symbol); err != nil {
102			return err
103		}
104	}
105
106	return nil
107}
108
109func writeASMHeader(symbols []string, path string) error {
110	f, err := os.Create(path)
111	if err != nil {
112		return err
113	}
114	defer f.Close()
115
116	if _, err := f.WriteString(`// Copyright 2018 The BoringSSL Authors
117//
118// Licensed under the Apache License, Version 2.0 (the "License");
119// you may not use this file except in compliance with the License.
120// You may obtain a copy of the License at
121//
122//     https://www.apache.org/licenses/LICENSE-2.0
123//
124// Unless required by applicable law or agreed to in writing, software
125// distributed under the License is distributed on an "AS IS" BASIS,
126// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
127// See the License for the specific language governing permissions and
128// limitations under the License.
129
130#if !defined(__APPLE__)
131#include <boringssl_prefix_symbols.h>
132#else
133// On iOS and macOS, we need to treat assembly symbols differently from other
134// symbols. The linker expects symbols to be prefixed with an underscore.
135// Perlasm thus generates symbol with this underscore applied. Our macros must,
136// in turn, incorporate it.
137#define BORINGSSL_ADD_PREFIX_MAC_ASM(a, b) BORINGSSL_ADD_PREFIX_INNER_MAC_ASM(a, b)
138#define BORINGSSL_ADD_PREFIX_INNER_MAC_ASM(a, b) _ ## a ## _ ## b
139
140`); err != nil {
141		return err
142	}
143
144	for _, symbol := range symbols {
145		if _, err := fmt.Fprintf(f, "#define _%s BORINGSSL_ADD_PREFIX_MAC_ASM(BORINGSSL_PREFIX, %s)\n", symbol, symbol); err != nil {
146			return err
147		}
148	}
149
150	_, err = fmt.Fprintf(f, "#endif\n")
151	return nil
152}
153
154func writeNASMHeader(symbols []string, path string) error {
155	f, err := os.Create(path)
156	if err != nil {
157		return err
158	}
159	defer f.Close()
160
161	// NASM uses a different syntax from the C preprocessor.
162	if _, err := f.WriteString(`; Copyright 2018 The BoringSSL Authors
163;
164; Licensed under the Apache License, Version 2.0 (the "License");
165; you may not use this file except in compliance with the License.
166; You may obtain a copy of the License at
167;
168;     https://www.apache.org/licenses/LICENSE-2.0
169;
170; Unless required by applicable law or agreed to in writing, software
171; distributed under the License is distributed on an "AS IS" BASIS,
172; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
173; See the License for the specific language governing permissions and
174; limitations under the License.
175
176; 32-bit Windows adds underscores to C functions, while 64-bit Windows does not.
177%ifidn __OUTPUT_FORMAT__, win32
178`); err != nil {
179		return err
180	}
181
182	for _, symbol := range symbols {
183		if _, err := fmt.Fprintf(f, "%%xdefine _%s _ %%+ BORINGSSL_PREFIX %%+ _%s\n", symbol, symbol); err != nil {
184			return err
185		}
186	}
187
188	if _, err := fmt.Fprintf(f, "%%else\n"); err != nil {
189		return err
190	}
191
192	for _, symbol := range symbols {
193		if _, err := fmt.Fprintf(f, "%%xdefine %s BORINGSSL_PREFIX %%+ _%s\n", symbol, symbol); err != nil {
194			return err
195		}
196	}
197
198	if _, err := fmt.Fprintf(f, "%%endif\n"); err != nil {
199		return err
200	}
201
202	return nil
203}
204
205func main() {
206	flag.Parse()
207	if flag.NArg() != 1 {
208		fmt.Fprintf(os.Stderr, "Usage: %s [-out OUT] SYMBOLS\n", os.Args[0])
209		os.Exit(1)
210	}
211
212	symbols, err := readSymbols(flag.Arg(0))
213	if err != nil {
214		fmt.Fprintf(os.Stderr, "Error reading symbols: %s\n", err)
215		os.Exit(1)
216	}
217
218	if err := writeCHeader(symbols, filepath.Join(*out, "boringssl_prefix_symbols.h")); err != nil {
219		fmt.Fprintf(os.Stderr, "Error writing boringssl_prefix_symbols.h: %s\n", err)
220		os.Exit(1)
221	}
222
223	if err := writeASMHeader(symbols, filepath.Join(*out, "boringssl_prefix_symbols_asm.h")); err != nil {
224		fmt.Fprintf(os.Stderr, "Error writing boringssl_prefix_symbols_asm.h: %s\n", err)
225		os.Exit(1)
226	}
227
228	if err := writeNASMHeader(symbols, filepath.Join(*out, "boringssl_prefix_symbols_nasm.inc")); err != nil {
229		fmt.Fprintf(os.Stderr, "Error writing boringssl_prefix_symbols_nasm.inc: %s\n", err)
230		os.Exit(1)
231	}
232
233}
234