1
1
mirror of https://github.com/rui314/mold.git synced 2024-10-04 08:37:28 +03:00

Merge pull request #520 from tapthaker/macho-tbd-files

[Mach-O] Adds support for objc and weak symbols in TBD files
This commit is contained in:
Rui Ueyama 2022-05-18 12:03:11 +08:00 committed by GitHub
commit c654d42c14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 131 additions and 1 deletions

View File

@ -679,8 +679,30 @@ void DylibFile<E>::parse(Context<E> &ctx) {
switch (get_file_type(this->mf)) {
case FileType::TAPI: {
TextDylib tbd = parse_tbd(ctx, this->mf);
auto add_symbol_with_prefix = [&](std::string_view prefix,
std::string_view sym_name) {
std::string symbol_name = std::string(prefix);
symbol_name.append(sym_name);
Symbol<E> *sym = get_symbol(ctx, save_string(ctx, symbol_name));
this->syms.push_back(sym);
};
for (std::string_view sym : tbd.exports)
this->syms.push_back(get_symbol(ctx, sym));
for (std::string_view weak_sym : tbd.weak_exports) {
Symbol<E> *sym = get_symbol(ctx, weak_sym);
sym->is_weak_def = true;
this->syms.push_back(sym);
}
for (std::string_view objc_class : tbd.objc_classes) {
add_symbol_with_prefix(OBJC2_CLASS_NAME_PREFIX, objc_class);
add_symbol_with_prefix(OBJC2_METACLASS_NAME_PREFIX, objc_class);
}
for (std::string_view eh_type : tbd.objc_eh_types)
add_symbol_with_prefix(OBJC2_EHTYPE_PREFIX, eh_type);
for (std::string_view ivar : tbd.objc_ivars)
add_symbol_with_prefix(OBJC2_IVAR_PREFIX, ivar);
install_name = tbd.install_name;
break;
}

View File

@ -702,6 +702,12 @@ parse_yaml(std::string_view str);
// tapi.cc
//
static const std::string_view OBJC2_CLASS_NAME_PREFIX = "_OBJC_CLASS_$_";
static const std::string_view OBJC2_METACLASS_NAME_PREFIX =
"_OBJC_METACLASS_$_";
static const std::string_view OBJC2_EHTYPE_PREFIX = "_OBJC_EHTYPE_$_";
static const std::string_view OBJC2_IVAR_PREFIX = "_OBJC_IVAR_$_";
struct TextDylib {
std::string_view uuid;
std::string_view install_name;
@ -709,6 +715,10 @@ struct TextDylib {
std::string_view parent_umbrella;
std::vector<std::string_view> reexported_libs;
std::vector<std::string_view> exports;
std::vector<std::string_view> weak_exports;
std::vector<std::string_view> objc_classes;
std::vector<std::string_view> objc_eh_types;
std::vector<std::string_view> objc_ivars;
};
template <typename E>

View File

@ -72,10 +72,23 @@ static std::optional<TextDylib> to_tbd(YamlNode &node, std::string_view arch) {
for (std::string_view key : {"exports", "reexports"})
for (YamlNode &mem : get_vector(node, key))
if (contains(get_vector(mem, "targets"), arch))
if (contains(get_vector(mem, "targets"), arch)) {
for (YamlNode &mem : get_vector(mem, "symbols"))
if (auto *sym = std::get_if<std::string_view>(&mem.data))
tbd.exports.push_back(*sym);
for (YamlNode &mem : get_vector(mem, "weak-symbols"))
if (auto *sym = std::get_if<std::string_view>(&mem.data))
tbd.weak_exports.push_back(*sym);
for (YamlNode &mem : get_vector(mem, "objc-classes"))
if (auto *clazz = std::get_if<std::string_view>(&mem.data))
tbd.objc_classes.push_back(*clazz);
for (YamlNode &mem : get_vector(mem, "objc-eh-types"))
if (auto *eh_type = std::get_if<std::string_view>(&mem.data))
tbd.objc_eh_types.push_back(*eh_type);
for (YamlNode &mem : get_vector(mem, "objc-ivars"))
if (auto *ivar = std::get_if<std::string_view>(&mem.data))
tbd.objc_ivars.push_back(*ivar);
}
return tbd;
}

85
test/macho/tbd.sh Executable file
View File

@ -0,0 +1,85 @@
#!/bin/bash
export LC_ALL=C
set -e
CC="${TEST_CC:-cc}"
CXX="${TEST_CXX:-c++}"
GCC="${TEST_GCC:-gcc}"
GXX="${TEST_GXX:-g++}"
OBJDUMP="${OBJDUMP:-objdump}"
MACHINE="${MACHINE:-$(uname -m)}"
testname=$(basename "$0" .sh)
echo -n "Testing $testname ... "
cd "$(dirname "$0")"/../..
t=out/test/macho/$testname
mkdir -p $t
some_fw=$t/SF/SomeFramework.framework/
mkdir -p $some_fw
cat > $some_fw/SomeFramework.tbd <<EOF
--- !tapi-tbd
tbd-version: 4
targets: [ x86_64-macos, arm64-macos ]
uuids:
- target: x86_64-macos
value: 00000000-0000-0000-0000-000000000000
- target: arm64-macos
value: 00000000-0000-0000-0000-000000000000
install-name: '/usr/frameworks/SomeFramework.framework/SomeFramework'
current-version: 0000
compatibility-version: 150
reexported-libraries:
- targets: [ x86_64-macos, arm64-macos ]
libraries: [ ]
exports:
- targets: [ x86_64-macos, arm64-macos ]
symbols: [ _some_framework_print ]
objc-classes: [ SomeObjectiveC ]
weak-symbols: [ _weak_some_framework_print ]
...
EOF
cat <<EOF | clang -o $t/TestTBDFiles.o -c -xobjective-c -
#include <stdio.h>
#import <CoreFoundation/CoreFoundation.h>
// Interface Declaration for SomeFramework.framework
@interface SomeObjectiveC: NSObject
@end
void some_framework_print(char*);
void weak_some_framework_print(char*) __attribute__((weak));;
// End Interface Declaration for SomeFramework.framework
@interface TestTBDFiles: SomeObjectiveC
@end
@implementation TestTBDFiles
-(void) helloWorld {
some_framework_print("Hello World");
weak_some_framework_print("Hello World");
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
TestTBDFiles *tbd = [[TestTBDFiles alloc]init];
[tbd helloWorld];
}
return 0;
}
EOF
clang --ld-path=./ld64 -F$t/SF/ -Wl,-framework,SomeFramework \
-Wl,-framework,CoreFoundation -lobjc -o $t/exe $t/TestTBDFiles.o
otool -L $t/exe > $t/install_paths.log
grep -q '/usr/frameworks/SomeFramework.framework/SomeFramework' $t/install_paths.log
echo OK