[libcxx-commits] [libcxx] [libcxx] Support ABI symbol sizes on macOS (PR #75623)
Will Hawkins via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Dec 15 08:56:39 PST 2023
https://github.com/hawkinsw created https://github.com/llvm/llvm-project/pull/75623
Generated dylibs on macOS do not contain size information for symbols. As a result, the abi list that we keep for macOS is devoid of size information.
This patch works around that limitation by using supplementary information generated by the linker (i.e., a map file) that generate_abi_list.py can optionally use to update the information that nm generates about ABI symbols.
>From da9de2a53355003d1409fe3dad30e289530f0f3c Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Fri, 15 Dec 2023 11:48:15 -0500
Subject: [PATCH] [libcxx] Support ABI symbol sizes on macOS
Generated dylibs on macOS do not contain size information for symbols. As a
result, the abi list that we keep for macOS is devoid of size information.
This patch works around that limitation by using supplementary information
generated by the linker (i.e., a map file) that generate_abi_list.py can
optionally use to update the information that nm generates about ABI
symbols.
---
libcxx/cmake/Modules/HandleLibCXXABI.cmake | 41 ++++++++++++++++
libcxx/lib/abi/CMakeLists.txt | 56 ++++------------------
libcxx/src/CMakeLists.txt | 20 ++++++++
libcxx/utils/generate_abi_list.py | 21 ++++++++
libcxx/utils/libcxx/sym_check/util.py | 34 +++++++++++++
5 files changed, 126 insertions(+), 46 deletions(-)
diff --git a/libcxx/cmake/Modules/HandleLibCXXABI.cmake b/libcxx/cmake/Modules/HandleLibCXXABI.cmake
index 34e9a672a960f9..27b743a4b0ca68 100644
--- a/libcxx/cmake/Modules/HandleLibCXXABI.cmake
+++ b/libcxx/cmake/Modules/HandleLibCXXABI.cmake
@@ -176,3 +176,44 @@ elseif ("${LIBCXX_CXX_ABI}" STREQUAL "none")
add_library(libcxx-abi-static INTERFACE)
target_link_libraries(libcxx-abi-static INTERFACE libcxx-abi-headers)
endif()
+
+# This function generates a "unique" identifier based on various properties
+# given as arguments. The idea is to encode all ABI-affecting properties
+# in that identifier, so that we can store ABI information and associate it
+# to a specific ABI configuration.
+#
+# Right now, this is done by using the ABI identifier as the filename containing
+# the list of symbols exported by libc++ for that configuration, however we could
+# make it more sophisticated if the number of ABI-affecting parameters grew.
+function(cxx_abi_identifier result triple abi_library abi_version unstable exceptions new_delete_in_libcxx)
+ set(abi_properties)
+
+ if ("${triple}" MATCHES "darwin")
+ # Ignore the major, minor, and patchlevel versions of darwin targets.
+ string(REGEX REPLACE "darwin[0-9]+\\.[0-9]+\\.[0-9]+" "darwin" triple "${triple}")
+ elseif("${triple}" MATCHES "freebsd")
+ # Ignore the major and minor versions of freebsd targets.
+ string(REGEX REPLACE "freebsd[0-9]+\\.[0-9]+" "freebsd" triple "${triple}")
+ endif()
+ list(APPEND abi_properties "${triple}")
+ list(APPEND abi_properties "${abi_library}")
+ list(APPEND abi_properties "v${abi_version}")
+ if (${unstable})
+ list(APPEND abi_properties "unstable")
+ else()
+ list(APPEND abi_properties "stable")
+ endif()
+ if (${exceptions})
+ list(APPEND abi_properties "exceptions")
+ else()
+ list(APPEND abi_properties "noexceptions")
+ endif()
+ if (${new_delete_in_libcxx})
+ list(APPEND abi_properties "new")
+ else()
+ list(APPEND abi_properties "nonew")
+ endif()
+
+ list(JOIN abi_properties "." tmp)
+ set(${result} "${tmp}" PARENT_SCOPE)
+endfunction()
diff --git a/libcxx/lib/abi/CMakeLists.txt b/libcxx/lib/abi/CMakeLists.txt
index 7c08bd06c50b21..98212e698a32ff 100644
--- a/libcxx/lib/abi/CMakeLists.txt
+++ b/libcxx/lib/abi/CMakeLists.txt
@@ -1,51 +1,9 @@
-
-# This function generates a "unique" identifier based on various properties
-# given as arguments. The idea is to encode all ABI-affecting properties
-# in that identifier, so that we can store ABI information and associate it
-# to a specific ABI configuration.
-#
-# Right now, this is done by using the ABI identifier as the filename containing
-# the list of symbols exported by libc++ for that configuration, however we could
-# make it more sophisticated if the number of ABI-affecting parameters grew.
-function(cxx_abi_list_identifier result triple abi_library abi_version unstable exceptions new_delete_in_libcxx)
- set(abi_properties)
-
- if ("${triple}" MATCHES "darwin")
- # Ignore the major, minor, and patchlevel versions of darwin targets.
- string(REGEX REPLACE "darwin[0-9]+\\.[0-9]+\\.[0-9]+" "darwin" triple "${triple}")
- elseif("${triple}" MATCHES "freebsd")
- # Ignore the major and minor versions of freebsd targets.
- string(REGEX REPLACE "freebsd[0-9]+\\.[0-9]+" "freebsd" triple "${triple}")
- endif()
- list(APPEND abi_properties "${triple}")
- list(APPEND abi_properties "${abi_library}")
- list(APPEND abi_properties "v${abi_version}")
- if (${unstable})
- list(APPEND abi_properties "unstable")
- else()
- list(APPEND abi_properties "stable")
- endif()
- if (${exceptions})
- list(APPEND abi_properties "exceptions")
- else()
- list(APPEND abi_properties "noexceptions")
- endif()
- if (${new_delete_in_libcxx})
- list(APPEND abi_properties "new")
- else()
- list(APPEND abi_properties "nonew")
- endif()
-
- list(JOIN abi_properties "." tmp)
- set(${result} "${tmp}" PARENT_SCOPE)
-endfunction()
-
if (CMAKE_CXX_COMPILER_TARGET)
set(triple "${CMAKE_CXX_COMPILER_TARGET}")
else()
set(triple "${LLVM_DEFAULT_TARGET_TRIPLE}")
endif()
-cxx_abi_list_identifier(abi_list_identifier
+cxx_abi_identifier(abi_list_identifier
"${triple}"
"${LIBCXX_CXX_ABI}"
"${LIBCXX_ABI_VERSION}"
@@ -56,6 +14,7 @@ cxx_abi_list_identifier(abi_list_identifier
if (TARGET cxx_shared)
set(abi_list_file "${CMAKE_CURRENT_SOURCE_DIR}/${abi_list_identifier}.abilist")
+ set(abi_map_file "${CMAKE_CURRENT_SOURCE_DIR}/${abi_list_identifier}.linker.map")
if (EXISTS "${abi_list_file}")
add_custom_target(check-cxx-abilist
@@ -69,10 +28,15 @@ if (TARGET cxx_shared)
message(STATUS "ABI list file not generated for configuration ${abi_list_identifier}, `check-cxx-abilist` will not be available.")
endif()
- add_custom_target(generate-cxx-abilist
- COMMAND "${Python3_EXECUTABLE}" "${LIBCXX_SOURCE_DIR}/utils/generate_abi_list.py"
+ set(generate_cxx_abilist_parameters "${LIBCXX_SOURCE_DIR}/utils/generate_abi_list.py"
--output "${abi_list_file}"
- "$<TARGET_FILE:cxx_shared>"
+ "$<TARGET_FILE:cxx_shared>")
+ if (EXISTS ${abi_map_file})
+ list(APPEND generate_cxx_abilist_parameters --mapfile "${abi_map_file}")
+ endif()
+
+ add_custom_target(generate-cxx-abilist
+ COMMAND "${Python3_EXECUTABLE}" ${generate_cxx_abilist_parameters}
DEPENDS cxx_shared
COMMENT "Generating the ABI list file for configuration ${abi_list_identifier}")
else()
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index be0113e6b0a585..fea88a73f28049 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -193,6 +193,26 @@ split_list(LIBCXX_LINK_FLAGS)
# Build the shared library.
if (LIBCXX_ENABLE_SHARED)
+
+ if (APPLE)
+ # If we are on an Apple platform, let's ask the linker to generate a map
+ # that we can use to determine the size of the abi symbols (see generate-cxx-abilist target).
+ if (CMAKE_CXX_COMPILER_TARGET)
+ set(triple "${CMAKE_CXX_COMPILER_TARGET}")
+ else()
+ set(triple "${LLVM_DEFAULT_TARGET_TRIPLE}")
+ endif()
+ cxx_abi_identifier(abi_identifier
+ "${triple}"
+ "${LIBCXX_CXX_ABI}"
+ "${LIBCXX_ABI_VERSION}"
+ "${LIBCXX_ABI_UNSTABLE}"
+ "${LIBCXX_ENABLE_EXCEPTIONS}"
+ "${LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS}"
+ )
+ add_link_flags("-Wl,-map,${CMAKE_CURRENT_SOURCE_DIR}/../lib/abi/${abi_identifier}.linker.map")
+ endif()
+
add_library(cxx_shared SHARED ${exclude_from_all} ${LIBCXX_SOURCES} ${LIBCXX_HEADERS})
target_include_directories(cxx_shared PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(cxx_shared PUBLIC cxx-headers
diff --git a/libcxx/utils/generate_abi_list.py b/libcxx/utils/generate_abi_list.py
index 94e49dca60af14..5febfda35f4cb1 100755
--- a/libcxx/utils/generate_abi_list.py
+++ b/libcxx/utils/generate_abi_list.py
@@ -29,6 +29,13 @@ def main(argv):
parser.add_argument(
"library", metavar="LIB", type=str, help="The library to extract symbols from."
)
+ parser.add_argument(
+ "-m",
+ "--mapfile",
+ dest="mapfile",
+ default=None,
+ help="The name of the mapfile that contains supplementary information about symbols. (optional)",
+ )
parser.add_argument(
"-o",
"--output",
@@ -43,6 +50,20 @@ def main(argv):
symbols = libcxx.sym_check.extract.extract_symbols(args.library)
symbols, _ = libcxx.sym_check.util.filter_stdlib_symbols(symbols)
+ supplemental_info = {}
+ if args.mapfile != None:
+ supplemental_info = libcxx.sym_check.util.extract_object_sizes_from_map(
+ args.mapfile
+ )
+
+ if len(supplemental_info) != 0:
+ for sym in symbols:
+ if "size" not in sym or sym["size"] != 0 or sym["type"] != "OBJECT":
+ continue
+ if sym["name"] in supplemental_info:
+ updated_size = supplemental_info[sym["name"]]
+ sym["size"] = updated_size
+
lines = [pprint.pformat(sym, width=99999) for sym in symbols]
args.output.writelines("\n".join(sorted(lines)))
diff --git a/libcxx/utils/libcxx/sym_check/util.py b/libcxx/utils/libcxx/sym_check/util.py
index fc7ba4244ab5aa..6409af76c8b0d5 100644
--- a/libcxx/utils/libcxx/sym_check/util.py
+++ b/libcxx/utils/libcxx/sym_check/util.py
@@ -123,6 +123,40 @@ def adjust_mangled_name(name):
return name[1:]
+def extract_object_sizes_from_map(mapfilename: str):
+ maplines = []
+ result = {}
+
+ with open(mapfilename, "r") as f:
+ maplines = f.readlines()
+
+ if len(maplines) == 0:
+ return {}
+
+ # Yes, this is fragile.
+ symbols_start_index = -1
+ for i in range(0, len(maplines)):
+ if re.search("# Symbols:", maplines[i]):
+ symbols_start_index = i
+ break
+
+ if symbols_start_index == -1:
+ return {}
+
+ # There is a header after the line we use to detect
+ # the start of the symbol section -- + 2 to jump
+ # over that.
+ maplines = maplines[symbols_start_index + 2 :]
+ for line in maplines:
+ components = line.split()
+ name = components[4]
+ size = int(components[1], 16)
+ if size != 0:
+ result[name] = size
+
+ return result
+
+
new_delete_std_symbols = ["_Znam", "_Znwm", "_ZdaPv", "_ZdaPvm", "_ZdlPv", "_ZdlPvm"]
cxxabi_symbols = [
More information about the libcxx-commits
mailing list