xref: /aosp_15_r20/external/tensorflow/tensorflow/lite/ios/hide_symbols_with_allowlist.sh (revision b6fb3261f9314811a0f4371741dbb8839866f948)
1#!/bin/bash
2# Copyright 2020 The TensorFlow Authors. All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15# ==============================================================================
16#
17# A script to merge Mach-O object files into a single object file and hide
18# their internal symbols. Only allowed symbols will be visible in the
19# symbol table after this script.
20
21# To run this script, you must set several variables:
22#   INPUT_FRAMEWORK: a zip file containing the iOS static framework.
23#   BUNDLE_NAME: the pod/bundle name of the iOS static framework.
24#   ALLOWLIST_FILE_PATH: contains the allowed symbols.
25#   EXTRACT_SCRIPT_PATH: path to the extract_object_files script.
26#   OUTPUT: the output zip file.
27
28# Halt on any error or any unknown variable.
29set -ue
30
31# mktemp from coreutils has different flags. Make sure we get the iOS one.
32MKTEMP=/usr/bin/mktemp
33
34LD_DEBUGGABLE_FLAGS="-x"
35# Uncomment the below to get debuggable output. This can only be done for one
36# library at a time.
37# LD_DEBUGGABLE_FLAGS="-d"
38
39# Exits if C++ symbols are found in the allowlist.
40if grep -q "^__Z" "${ALLOWLIST_FILE_PATH}"; then
41  echo "ERROR: Failed in symbol hiding. This rule does not permit hiding of" \
42       "C++ symbols due to possible serious problems mixing symbol hiding," \
43       "shared libraries and the C++ runtime." \
44       "More info can be found in go/ios-symbols-hiding." \
45       "Please recheck the allowlist and remove C++ symbols:"
46  echo "$(grep "^__Z" "${ALLOWLIST_FILE_PATH}")"
47  exit 1 # terminate and indicate error
48fi
49# Unzips the framework zip file into a temp workspace.
50framework=$($MKTEMP -t framework -d)
51unzip "${INPUT_FRAMEWORK}" -d "${framework}"/
52
53# Executable file in the framework.
54executable_file="${BUNDLE_NAME}.framework/${BUNDLE_NAME}"
55
56# Extracts architectures from the framework binary.
57archs_str=$(xcrun lipo -info "${framework}/${executable_file}" |
58sed -En -e 's/^(Non-|Architectures in the )fat file: .+( is architecture| are): (.*)$/\3/p')
59
60IFS=' ' read -r -a archs <<< "${archs_str}"
61
62merge_cmd=(xcrun lipo)
63
64# Merges object files and hide symbols for each architecture.
65for arch in "${archs[@]}"; do
66    archdir=$($MKTEMP -t "${arch}" -d)
67    arch_file="${archdir}/${arch}"
68
69    # Handles the binary differently if they are fat or thin.
70    if [[ "${#archs[@]}" -gt 1 ]]; then
71       xcrun lipo "${framework}/${executable_file}" -thin "${arch}" -output "${arch_file}"
72    else
73       mv "${framework}/${executable_file}" "${arch_file}"
74    fi
75    if [[ "$arch" == "armv7" ]]; then
76      # Check that there are no thread local variables in the input, as they get broken.
77      # See b/124533863.
78      thread_locals=$(xcrun nm -m -g "${arch_file}" | awk '/__DATA,__thread_vars/ { print $5 }' | c++filt)
79      if [[ -n "${thread_locals}" ]]; then
80         echo
81         echo "WARNING: This symbol hiding script breaks thread local variables on 32-bit arm, you had:"
82         echo "${thread_locals}"
83         echo
84         echo "Your build will crash if these variables are actually used at runtime."
85         echo
86      fi
87    fi
88    if [[ ! -z "${EXTRACT_SCRIPT_PATH}" ]]; then
89      "${EXTRACT_SCRIPT_PATH}" "${arch_file}" "${archdir}"
90    else
91      # ar tool extracts the objects in the current working directory. Since the
92      # default working directory for a genrule is always the same, there can be
93      # a race condition when this script is called for multiple targets
94      # simultaneously.
95      pushd "${archdir}" > /dev/null
96      xcrun ar -x "${arch_file}"
97      popd > /dev/null
98    fi
99
100    objects_file_list=$($MKTEMP)
101    # Hides the symbols except the allowed ones.
102    find "${archdir}" -name "*.o" >> "${objects_file_list}"
103
104    # Checks whether bitcode is enabled in the framework.
105    all_objects_have_bitcode=true
106    for object_file in $(cat "$objects_file_list"); do
107      if otool -arch "${arch}" -l "${object_file}" | grep -q __LLVM; then
108        : # Do nothing
109      else
110        echo "The ${arch} in ${object_file} is NOT bitcode-enabled."
111        all_objects_have_bitcode=false
112        break
113      fi
114    done
115    if [[ "$all_objects_have_bitcode" = "true" ]]; then
116      echo "The ${arch} in ${executable_file} is fully bitcode-enabled."
117      xcrun ld -r -bitcode_bundle -exported_symbols_list \
118        "${ALLOWLIST_FILE_PATH}" \
119        $LD_DEBUGGABLE_FLAGS \
120        -filelist "${objects_file_list}" -o "${arch_file}_processed.o"
121    else
122      echo "The ${arch} in ${executable_file} is NOT fully bitcode-enabled."
123      xcrun ld -r -exported_symbols_list \
124        "${ALLOWLIST_FILE_PATH}" \
125        $LD_DEBUGGABLE_FLAGS \
126        -filelist "${objects_file_list}" -o "${arch_file}_processed.o"
127    fi
128
129    output_object="${framework}/${arch}"
130
131    mv "${arch_file}_processed.o" "${output_object}"
132    rm -rf "${archdir}"
133    rm "${objects_file_list}"
134    merge_cmd+=(-arch "${arch}" "${output_object}")
135done
136
137# Repackages the processed object files.
138unzip "${INPUT_FRAMEWORK}"
139merge_cmd+=(-create -output "${BUNDLE_NAME}")
140"${merge_cmd[@]}"
141
142chmod +x "${BUNDLE_NAME}"
143rm "${executable_file}"
144mv "${BUNDLE_NAME}" "${executable_file}"
145( TZ=UTC find "${BUNDLE_NAME}.framework/" -exec touch -h -t 198001010000 {} \+ )
146zip --compression-method store --symlinks --recurse-paths --quiet "${OUTPUT}" "${BUNDLE_NAME}.framework/"
147