mirror of
git://sourceware.org/git/glibc.git
synced 2024-11-27 03:41:23 +08:00
477a02f637
It was reported in <https://sourceware.org/ml/libc-alpha/2018-12/msg00045.html> that gen-as-const.py fails to generate test code in the case where a .sym file has no symbols in it, so resulting in a test failing to link for Hurd. The relevant difference from the old awk script is that the old script treated '--' lines as indicating that the text to do at the start of the test (or file used to compute constants) should be output at that point if not already output, as well as treating lines with actual entries for constants like that. This patch changes gen-as-const.py accordingly, making it the sole responsibility of the code parsing .sym files to determine when such text should be output and ensuring it's always output at some point even if there are no symbols and no '--' lines, since not outputting it means the test fails to link. Handling '--' like that also avoids any problems that would arise if the first entry for a symbol were inside #ifdef (since the text in question must not be output inside #ifdef). Tested for x86_64, and with build-many-glibcs.py for i686-gnu. Note that there are still compilation test failures for i686-gnu (linknamespace tests, possibly arising from recent posix_spawn-related changes). * scripts/gen-as-const.py (compute_c_consts): Take an argument 'START' to indicate that start text should be output. (gen_test): Likewise. (main): Generate 'START' for first symbol or '--' line, or at end of input if not previously generated.
166 lines
6.3 KiB
Python
166 lines
6.3 KiB
Python
#!/usr/bin/python3
|
|
# Produce headers of assembly constants from C expressions.
|
|
# Copyright (C) 2018 Free Software Foundation, Inc.
|
|
# This file is part of the GNU C Library.
|
|
#
|
|
# The GNU C Library is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
# License as published by the Free Software Foundation; either
|
|
# version 2.1 of the License, or (at your option) any later version.
|
|
#
|
|
# The GNU C Library is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# Lesser General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
# License along with the GNU C Library; if not, see
|
|
# <http://www.gnu.org/licenses/>.
|
|
|
|
# The input to this script looks like:
|
|
# #cpp-directive ...
|
|
# NAME1
|
|
# NAME2 expression ...
|
|
# A line giving just a name implies an expression consisting of just that name.
|
|
|
|
import argparse
|
|
import os.path
|
|
import re
|
|
import subprocess
|
|
import tempfile
|
|
|
|
|
|
def compute_c_consts(sym_data, cc):
|
|
"""Compute the values of some C constants.
|
|
|
|
The first argument is a list whose elements are either strings
|
|
(preprocessor directives, or the special string 'START' to
|
|
indicate this function should insert its initial boilerplate text
|
|
in the output there) or pairs of strings (a name and a C
|
|
expression for the corresponding value). Preprocessor directives
|
|
in the middle of the list may be used to select which constants
|
|
end up being evaluated using which expressions.
|
|
|
|
"""
|
|
out_lines = []
|
|
for arg in sym_data:
|
|
if isinstance(arg, str):
|
|
if arg == 'START':
|
|
out_lines.append('void\ndummy (void)\n{')
|
|
else:
|
|
out_lines.append(arg)
|
|
continue
|
|
name = arg[0]
|
|
value = arg[1]
|
|
out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" '
|
|
': : \"i\" ((long int) (%s)));'
|
|
% (name, value))
|
|
out_lines.append('}')
|
|
out_lines.append('')
|
|
out_text = '\n'.join(out_lines)
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
c_file_name = os.path.join(temp_dir, 'test.c')
|
|
s_file_name = os.path.join(temp_dir, 'test.s')
|
|
with open(c_file_name, 'w') as c_file:
|
|
c_file.write(out_text)
|
|
# Compilation has to be from stdin to avoid the temporary file
|
|
# name being written into the generated dependencies.
|
|
cmd = ('%s -S -o %s -x c - < %s' % (cc, s_file_name, c_file_name))
|
|
subprocess.check_call(cmd, shell=True)
|
|
consts = {}
|
|
with open(s_file_name, 'r') as s_file:
|
|
for line in s_file:
|
|
match = re.search('@@@name@@@([^@]*)'
|
|
'@@@value@@@[^0-9Xxa-fA-F-]*'
|
|
'([0-9Xxa-fA-F-]+).*@@@end@@@', line)
|
|
if match:
|
|
if (match.group(1) in consts
|
|
and match.group(2) != consts[match.group(1)]):
|
|
raise ValueError('duplicate constant %s'
|
|
% match.group(1))
|
|
consts[match.group(1)] = match.group(2)
|
|
return consts
|
|
|
|
|
|
def gen_test(sym_data):
|
|
"""Generate a test for the values of some C constants.
|
|
|
|
The first argument is as for compute_c_consts.
|
|
|
|
"""
|
|
out_lines = []
|
|
for arg in sym_data:
|
|
if isinstance(arg, str):
|
|
if arg == 'START':
|
|
out_lines.append('#include <stdint.h>\n'
|
|
'#include <stdio.h>\n'
|
|
'#include <bits/wordsize.h>\n'
|
|
'#if __WORDSIZE == 64\n'
|
|
'typedef uint64_t c_t;\n'
|
|
'# define U(n) UINT64_C (n)\n'
|
|
'#else\n'
|
|
'typedef uint32_t c_t;\n'
|
|
'# define U(n) UINT32_C (n)\n'
|
|
'#endif\n'
|
|
'static int\n'
|
|
'do_test (void)\n'
|
|
'{\n'
|
|
# Compilation test only, using static
|
|
# assertions.
|
|
' return 0;\n'
|
|
'}\n'
|
|
'#include <support/test-driver.c>')
|
|
else:
|
|
out_lines.append(arg)
|
|
continue
|
|
name = arg[0]
|
|
value = arg[1]
|
|
out_lines.append('_Static_assert (U (asconst_%s) == (c_t) (%s), '
|
|
'"value of %s");'
|
|
% (name, value, name))
|
|
return '\n'.join(out_lines)
|
|
|
|
|
|
def main():
|
|
"""The main entry point."""
|
|
parser = argparse.ArgumentParser(
|
|
description='Produce headers of assembly constants.')
|
|
parser.add_argument('--cc', metavar='CC',
|
|
help='C compiler (including options) to use')
|
|
parser.add_argument('--test', action='store_true',
|
|
help='Generate test case instead of header')
|
|
parser.add_argument('sym_file',
|
|
help='.sym file to process')
|
|
args = parser.parse_args()
|
|
sym_data = []
|
|
with open(args.sym_file, 'r') as sym_file:
|
|
started = False
|
|
for line in sym_file:
|
|
line = line.strip()
|
|
if line == '':
|
|
continue
|
|
# Pass preprocessor directives through.
|
|
if line.startswith('#'):
|
|
sym_data.append(line)
|
|
continue
|
|
words = line.split(maxsplit=1)
|
|
if not started:
|
|
sym_data.append('START')
|
|
started = True
|
|
# Separator.
|
|
if words[0] == '--':
|
|
continue
|
|
name = words[0]
|
|
value = words[1] if len(words) > 1 else words[0]
|
|
sym_data.append((name, value))
|
|
if not started:
|
|
sym_data.append('START')
|
|
if args.test:
|
|
print(gen_test(sym_data))
|
|
else:
|
|
consts = compute_c_consts(sym_data, args.cc)
|
|
print(''.join('#define %s %s\n' % c for c in sorted(consts.items())), end='')
|
|
|
|
if __name__ == '__main__':
|
|
main()
|