Skip to content

IRGen: ensure that ObjC sections match on all targets #13225

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 4, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/IRGen/GenClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2108,10 +2108,14 @@ namespace {
IGM.getPointerAlignment(),
/*constant*/ true,
llvm::GlobalVariable::PrivateLinkage);

switch (IGM.TargetInfo.OutputObjectFormat) {
case llvm::Triple::MachO:
var->setSection("__DATA, __objc_const");
break;
case llvm::Triple::COFF:
var->setSection(".data");
break;
case llvm::Triple::ELF:
var->setSection(".data");
break;
Expand Down
80 changes: 66 additions & 14 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -770,31 +770,82 @@ void IRGenModule::addLazyConformances(NominalTypeDecl *Nominal) {
}
}

std::string IRGenModule::GetObjCSectionName(StringRef Section,
StringRef MachOAttributes) {
assert(Section.substr(0, 2) == "__" && "expected the name to begin with __");

switch (TargetInfo.OutputObjectFormat) {
case llvm::Triple::UnknownObjectFormat:
llvm_unreachable("must know the object file format");
case llvm::Triple::MachO:
return MachOAttributes.empty()
? ("__DATA," + Section).str()
: ("__DATA," + Section + "," + MachOAttributes).str();
case llvm::Triple::ELF:
return Section.substr(2).str();
case llvm::Triple::COFF:
return ("." + Section.substr(2) + "$B").str();
case llvm::Triple::Wasm:
error(SourceLoc(), "wasm is not a supported object file format");
}

llvm_unreachable("unexpected object file format");
}

void IRGenModule::SetCStringLiteralSection(llvm::GlobalVariable *GV,
ObjCLabelType Type) {
switch (TargetInfo.OutputObjectFormat) {
case llvm::Triple::UnknownObjectFormat:
llvm_unreachable("must know the object file format");
case llvm::Triple::MachO:
switch (Type) {
case ObjCLabelType::ClassName:
GV->setSection("__TEXT,__objc_classname,cstring_literals");
return;
case ObjCLabelType::MethodVarName:
GV->setSection("__TEXT,__objc_methname,cstring_literals");
return;
case ObjCLabelType::MethodVarType:
GV->setSection("__TEXT,__objc_methtype,cstring_literals");
return;
case ObjCLabelType::PropertyName:
GV->setSection("__TEXT,__cstring,cstring_literals");
return;
}
case llvm::Triple::ELF:
return;
case llvm::Triple::COFF:
return;
case llvm::Triple::Wasm:
error(SourceLoc(), "wasm is not a supported object file format");
return;
}

llvm_unreachable("unexpected object file format");
}

void IRGenModule::emitGlobalLists() {
if (ObjCInterop) {
assert(TargetInfo.OutputObjectFormat == llvm::Triple::MachO);
// Objective-C class references go in a variable with a meaningless
// name but a magic section.
emitGlobalList(*this, ObjCClasses, "objc_classes",
"__DATA, __objc_classlist, regular, no_dead_strip",
llvm::GlobalValue::InternalLinkage,
Int8PtrTy,
false);
GetObjCSectionName("__objc_classlist",
"regular,no_dead_strip"),
llvm::GlobalValue::InternalLinkage, Int8PtrTy, false);

// So do categories.
emitGlobalList(*this, ObjCCategories, "objc_categories",
"__DATA, __objc_catlist, regular, no_dead_strip",
llvm::GlobalValue::InternalLinkage,
Int8PtrTy,
false);
GetObjCSectionName("__objc_catlist",
"regular,no_dead_strip"),
llvm::GlobalValue::InternalLinkage, Int8PtrTy, false);

// Emit nonlazily realized class references in a second magic section to make
// sure they are realized by the Objective-C runtime before any instances
// are allocated.
emitGlobalList(*this, ObjCNonLazyClasses, "objc_non_lazy_classes",
"__DATA, __objc_nlclslist, regular, no_dead_strip",
llvm::GlobalValue::InternalLinkage,
Int8PtrTy,
false);
GetObjCSectionName("__objc_nlclslist",
"regular,no_dead_strip"),
llvm::GlobalValue::InternalLinkage, Int8PtrTy, false);
}

// @llvm.used
Expand Down Expand Up @@ -2422,7 +2473,8 @@ Address IRGenModule::getAddrOfObjCClassRef(ClassDecl *theClass) {
// Define it lazily.
if (auto global = dyn_cast<llvm::GlobalVariable>(addr)) {
if (global->isDeclaration()) {
global->setSection("__DATA,__objc_classrefs,regular,no_dead_strip");
global->setSection(GetObjCSectionName("__objc_classrefs",
"regular,no_dead_strip"));
global->setLinkage(llvm::GlobalVariable::PrivateLinkage);
global->setExternallyInitialized(true);
global->setInitializer(getAddrOfObjCClass(theClass, NotForDefinition));
Expand Down
3 changes: 2 additions & 1 deletion lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3939,7 +3939,8 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
bool isIndirect = false;

StringRef section{};
if (classDecl->isObjC())
if (classDecl->isObjC() &&
IGM.TargetInfo.OutputObjectFormat == llvm::Triple::MachO)
section = "__DATA,__objc_data, regular";

auto var = IGM.defineTypeMetadata(declaredType, isIndirect, isPattern,
Expand Down
21 changes: 11 additions & 10 deletions lib/IRGen/GenObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ llvm::Constant *IRGenModule::getAddrOfObjCMethodName(StringRef selector) {
llvm::GlobalValue::PrivateLinkage,
init,
llvm::Twine("\01L_selector_data(") + selector + ")");
global->setSection("__TEXT,__objc_methname,cstring_literals");
SetCStringLiteralSection(global, ObjCLabelType::MethodVarName);
global->setAlignment(1);
addCompilerUsedGlobal(global);

Expand Down Expand Up @@ -364,7 +364,8 @@ llvm::Constant *IRGenModule::getAddrOfObjCSelectorRef(StringRef selector) {
global->setAlignment(getPointerAlignment().getValue());

// This section name is magical for the Darwin static and dynamic linkers.
global->setSection("__DATA,__objc_selrefs,literal_pointers,no_dead_strip");
global->setSection(GetObjCSectionName("__objc_selrefs",
"literal_pointers,no_dead_strip"));

// Make sure that this reference does not get optimized away.
addCompilerUsedGlobal(global);
Expand Down Expand Up @@ -426,19 +427,19 @@ IRGenModule::getObjCProtocolGlobalVars(ProtocolDecl *proto) {
+ protocolName);
protocolLabel->setAlignment(getPointerAlignment().getValue());
protocolLabel->setVisibility(llvm::GlobalValue::HiddenVisibility);
protocolLabel->setSection("__DATA,__objc_protolist,coalesced,no_dead_strip");

protocolLabel->setSection(GetObjCSectionName("__objc_protolist",
"coalesced,no_dead_strip"));

// Introduce a variable to reference the protocol.
auto *protocolRef
= new llvm::GlobalVariable(Module, Int8PtrTy,
/*constant*/ false,
auto *protocolRef =
new llvm::GlobalVariable(Module, Int8PtrTy, /*constant*/ false,
llvm::GlobalValue::WeakAnyLinkage,
protocolRecord,
llvm::Twine("\01l_OBJC_PROTOCOL_REFERENCE_$_")
+ protocolName);
llvm::Twine("\01l_OBJC_PROTOCOL_REFERENCE_$_") + protocolName);
protocolRef->setAlignment(getPointerAlignment().getValue());
protocolRef->setVisibility(llvm::GlobalValue::HiddenVisibility);
protocolRef->setSection("__DATA,__objc_protorefs,coalesced,no_dead_strip");
protocolRef->setSection(GetObjCSectionName("__objc_protorefs",
"coalesced,no_dead_strip"));

ObjCProtocolPair pair{protocolRecord, protocolRef};
ObjCProtocols.insert({proto, pair});
Expand Down
10 changes: 10 additions & 0 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,16 @@ class IRGenModule {
Size getAtomicBoolSize() const { return AtomicBoolSize; }
Alignment getAtomicBoolAlignment() const { return AtomicBoolAlign; }

enum class ObjCLabelType {
ClassName,
MethodVarName,
MethodVarType,
PropertyName,
};

std::string GetObjCSectionName(StringRef Section, StringRef MachOAttributes);
void SetCStringLiteralSection(llvm::GlobalVariable *GV, ObjCLabelType Type);

private:
Size PtrSize;
Size AtomicBoolSize;
Expand Down
12 changes: 12 additions & 0 deletions test/IRGen/Inputs/usr/include/ObjCInterop.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

@protocol P
@optional
- (void)method;
@end

@interface I
- (instancetype _Nonnull)init;
@end

I * _Nonnull f(I * _Nonnull);

4 changes: 4 additions & 0 deletions test/IRGen/Inputs/usr/include/module.map
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ module Foundation {
module CoreFoundation {
header "BridgeTestCoreFoundation.h"
}

module ObjCInterop {
header "ObjCInterop.h"
}
47 changes: 47 additions & 0 deletions test/IRGen/objc-sections.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// RUN: %swift -target x86_64-unknown-windows-msvc -parse-stdlib -enable-objc-interop -disable-objc-attr-requires-foundation-module -I %S/Inputs/usr/include -emit-ir %s -o - | %FileCheck %s -check-prefix CHECK-COFF
// RUN: %swift -target x86_64-unknown-linux-gnu -parse-stdlib -enable-objc-interop -disable-objc-attr-requires-foundation-module -I %S/Inputs/usr/include -Xcc --sysroot=/var/empty -emit-ir %s -o - | %FileCheck %s -check-prefix CHECK-ELF
// RUN: %swift -target x86_64-apple-ios -parse-stdlib -enable-objc-interop -disable-objc-attr-requires-foundation-module -I %S/Inputs/usr/include -emit-ir %s -o - | %FileCheck %s -check-prefix CHECK-MACHO

import ObjCInterop

@objc
class C {
}

extension C : P {
public func method() {
f(I())
}
}

@objc_non_lazy_realization
class D {
}

// CHECK-COFF-NOT: @_T04main1CCMf = {{.*}}, section "__DATA,__objc_data, regular"
// CHECK-COFF: @"\01l_OBJC_LABEL_PROTOCOL_$_P" = {{.*}}, section ".objc_protolist$B"
// CHECK-COFF: @"\01l_OBJC_PROTOCOL_REFERENCE_$_P" = {{.*}}, section ".objc_protorefs$B"
// CHECK-COFF: @"OBJC_CLASS_REF_$_I" = {{.*}}, section ".objc_classrefs$B"
// CHECK-COFF: @"\01L_selector(init)" = {{.*}}, section ".objc_selrefs$B"
// CHECK-COFF: @objc_classes = {{.*}}, section ".objc_classlist$B"
// CHECK-COFF: @objc_categories = {{.*}}, section ".objc_catlist$B"
// CHECK-COFF: @objc_non_lazy_classes = {{.*}}, section ".objc_nlclslist$B"

// CHECK-ELF-NOT: @_T04main1CCMf = {{.*}}, section "__DATA,__objc_data, regular"
// CHECK-ELF: @"\01l_OBJC_LABEL_PROTOCOL_$_P" = {{.*}}, section "objc_protolist"
// CHECK-ELF: @"\01l_OBJC_PROTOCOL_REFERENCE_$_P" = {{.*}}, section "objc_protorefs", align 8
// CHECK-ELF: @"OBJC_CLASS_REF_$_I" = {{.*}}, section "objc_classrefs", align 8
// CHECK-ELF: @"\01L_selector(init)" = {{.*}}, section "objc_selrefs"
// CHECK-ELF: @objc_classes = {{.*}}, section "objc_classlist"
// CHECK-ELF: @objc_categories = {{.*}}, section "objc_catlist"
// CHECK-ELF: @objc_non_lazy_classes = {{.*}}, section "objc_nlclslist", align 8

// CHECK-MACHO: @_T04main1CCMf = {{.*}}, section "__DATA,__objc_data, regular"
// CHECK-MACHO: @"\01l_OBJC_LABEL_PROTOCOL_$_P" = {{.*}}, section "__DATA,__objc_protolist,coalesced,no_dead_strip"
// CHECK-MACHO: @"\01l_OBJC_PROTOCOL_REFERENCE_$_P" = {{.*}}, section "__DATA,__objc_protorefs,coalesced,no_dead_strip"
// CHECK-MACHO: @"OBJC_CLASS_REF_$_I" = {{.*}}, section "__DATA,__objc_classrefs,regular,no_dead_strip"
// CHECK-MACHO: @"\01L_selector(init)" = {{.*}}, section "__DATA,__objc_selrefs,literal_pointers,no_dead_strip"
// CHECK-MACHO: @objc_classes = {{.*}}, section "__DATA,__objc_classlist,regular,no_dead_strip"
// CHECK-MACHO: @objc_categories = {{.*}}, section "__DATA,__objc_catlist,regular,no_dead_strip"
// CHECK-MACHO: @objc_non_lazy_classes = {{.*}}, section "__DATA,__objc_nlclslist,regular,no_dead_strip"

4 changes: 2 additions & 2 deletions test/IRGen/objc_subclass.swift
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,9 @@
// CHECK-64: ] }


// CHECK: @objc_classes = internal global [2 x i8*] [i8* bitcast (%swift.type* @_T013objc_subclass10SwiftGizmoCN to i8*), i8* bitcast (%swift.type* @_T013objc_subclass11SwiftGizmo2CN to i8*)], section "__DATA, __objc_classlist, regular, no_dead_strip", align [[WORD_SIZE_IN_BYTES]]
// CHECK: @objc_classes = internal global [2 x i8*] [i8* bitcast (%swift.type* @_T013objc_subclass10SwiftGizmoCN to i8*), i8* bitcast (%swift.type* @_T013objc_subclass11SwiftGizmo2CN to i8*)], section "__DATA,__objc_classlist,regular,no_dead_strip", align [[WORD_SIZE_IN_BYTES]]

// CHECK: @objc_non_lazy_classes = internal global [1 x i8*] [i8* bitcast (%swift.type* @_T013objc_subclass11SwiftGizmo2CN to i8*)], section "__DATA, __objc_nlclslist, regular, no_dead_strip", align [[WORD_SIZE_IN_BYTES]]
// CHECK: @objc_non_lazy_classes = internal global [1 x i8*] [i8* bitcast (%swift.type* @_T013objc_subclass11SwiftGizmo2CN to i8*)], section "__DATA,__objc_nlclslist,regular,no_dead_strip", align [[WORD_SIZE_IN_BYTES]]

import Foundation
import gizmo
Expand Down
2 changes: 1 addition & 1 deletion test/IRGen/subclass.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
// CHECK: i64 ([[B]]*)* @_T08subclass1BC1fSiyF,
// CHECK: [[A]]* ([[TYPE]]*)* @_T08subclass1AC1gACyFZ
// CHECK: }>
// CHECK: @objc_classes = internal global [2 x i8*] [i8* {{.*}} @_T08subclass1ACN {{.*}}, i8* {{.*}} @_T08subclass1BCN {{.*}}], section "__DATA, __objc_classlist, regular, no_dead_strip", align 8
// CHECK: @objc_classes = internal global [2 x i8*] [i8* {{.*}} @_T08subclass1ACN {{.*}}, i8* {{.*}} @_T08subclass1BCN {{.*}}], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8

class A {
var x = 0
Expand Down