2 # Move symbols from other shared objects into libc.so.
3 # Copyright (C) 2020-2022 Free Software Foundation, Inc.
4 # This file is part of the GNU C Library.
6 # The GNU C Library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
11 # The GNU C Library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with the GNU C Library; if not, see
18 # <https://www.gnu.org/licenses/>.
20 """Move symbols from other shared objects into libc.so.
22 This script moves ABI symbols from non-libc abilists in to
23 libc.abilist. Symbol versions are preserved. The script must be
24 called from the top of the glibc source tree.
32 # Make available glibc Python modules.
33 sys
.path
.append(os
.path
.dirname(os
.path
.realpath(__file__
)))
37 def add_to_libc_path(path
, new_symbols
):
38 """Add SYMBOLS to the abilist file PATH.
40 NEW_SYMBOLS is a dictionary from glibcsymbols.VersionedSymbol
41 objects to their flags.
44 original_symbols
= glibcsymbols
.read_abilist(path
)
45 updated_symbols
= original_symbols
.copy()
46 updated_symbols
.update(new_symbols
)
47 if updated_symbols
!= original_symbols
:
48 sys
.stdout
.write('updating libc abilist {}\n'.format(path
))
49 glibcsymbols
.replace_file(
50 path
, glibcsymbols
.abilist_lines(updated_symbols
))
52 # The name of the libc.so abilist file.
53 libc_abilist
= 'libc.abilist'
55 def add_to_libc_fallback(directory
, subdirs
, symbol_lines
):
56 """Add SYMBOL_LINES to the libc.abilist files in SUBDIRS in DIRECTORY.
58 All subdirectories must exist. If they do, return True. If not,
59 skip processing and return False.
62 abilists
= [os
.path
.join(directory
, subdir
, libc_abilist
)
63 for subdir
in subdirs
]
64 for abilist
in abilists
:
65 if not os
.path
.exists(abilist
):
67 for abilist
in abilists
:
68 add_to_libc_path(abilist
, symbol_lines
)
71 def add_to_libc(directory
, symbol_lines
):
73 """Add SYMBOL_LINES (a list of strings) to libc.abilist in DIRECTORY.
75 Try specific subdirectories as well if libc.abilist is not found
79 libc_path
= os
.path
.join(directory
, libc_abilist
)
80 if os
.path
.exists(libc_path
):
81 add_to_libc_path(libc_path
, symbol_lines
)
84 # Special case for powerpc32 and mips32 variants.
85 if add_to_libc_fallback(directory
, ('fpu', 'nofpu'), symbol_lines
):
88 # Special case for mips64.
89 if add_to_libc_fallback(directory
, ('n32', 'n64'), symbol_lines
):
92 raise IOError('No libc.abilist found for: {}'.format(directory
))
94 def move_symbols_1(path
, to_move
, moved_symbols
):
95 """Move SYMBOLS from the abilist file PATH to MOVED_SYMBOLS.
97 TO_MOVE must be a set of strings. MOVED_SYMBOLS is a dictionary.
101 assert path
.endswith('.abilist')
102 library
= os
.path
.basename(path
)[:-len(suffix
)]
103 placeholder
= '__{}_version_placeholder'.format(library
)
108 old_symbols
= glibcsymbols
.read_abilist(path
)
109 old_versions
= set(versym
.version
for versym
in old_symbols
.keys())
110 matching_symbols
= dict(e
for e
in old_symbols
.items()
111 if e
[0].symbol
in to_move
)
113 sys
.stdout
.write('updating {} abilist {}\n'.format(library
, path
))
114 new_symbols
= dict(e
for e
in old_symbols
.items()
115 if e
[0].symbol
not in to_move
)
117 # Add placeholder symbols to prevent symbol versions from
118 # going away completely.
119 new_versions
= set(versym
.version
for versym
in new_symbols
.keys())
120 for missing_version
in old_versions
- new_versions
:
121 new_symbols
[glibcsymbols
.VersionedSymbol(
122 placeholder
, missing_version
)] = 'F'
124 glibcsymbols
.replace_file(
125 path
, glibcsymbols
.abilist_lines(new_symbols
))
127 moved_symbols
.update(matching_symbols
)
129 def move_symbols(directory
, files
, symbols
):
130 """Move SYMBOLS from FILES (a list of abilist file names) in DIRECTORY.
132 SYMBOLS must be a set of strings.
136 for filename
in files
:
137 move_symbols_1(os
.path
.join(directory
, filename
), symbols
,
140 add_to_libc(directory
, moved_symbols
)
143 """Return an argument parser for this module."""
144 parser
= argparse
.ArgumentParser(description
=__doc__
)
145 parser
.add_argument('--only-linux', action
='store_true',
146 help='Restrict the operation to Linux abilists')
147 parser
.add_argument('symbols', help='name of the symbol to move',
152 """The main entry point."""
153 parser
= get_parser()
154 opts
= parser
.parse_args(argv
)
156 sysdeps
= 'sysdeps/unix/sysv/linux'
160 symbols
= frozenset(opts
.symbols
)
162 for directory
, dirs
, files
in os
.walk(sysdeps
):
163 move_symbols(directory
, [name
for name
in files
164 if name
!= 'libc.abilist'
165 and name
.endswith('.abilist')], symbols
)
167 if __name__
== '__main__':