[libcxx-commits] [libcxx] [libcxx] Support ABI symbol sizes on macOS (PR #75623)

via libcxx-commits libcxx-commits at lists.llvm.org
Fri Dec 15 08:57:08 PST 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Will Hawkins (hawkinsw)

<details>
<summary>Changes</summary>

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.

---
Full diff: https://github.com/llvm/llvm-project/pull/75623.diff


5 Files Affected:

- (modified) libcxx/cmake/Modules/HandleLibCXXABI.cmake (+41) 
- (modified) libcxx/lib/abi/CMakeLists.txt (+10-46) 
- (modified) libcxx/src/CMakeLists.txt (+20) 
- (modified) libcxx/utils/generate_abi_list.py (+21) 
- (modified) libcxx/utils/libcxx/sym_check/util.py (+34) 


``````````diff
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 = [

``````````

</details>


https://github.com/llvm/llvm-project/pull/75623


More information about the libcxx-commits mailing list