惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
MyScale Blog
MyScale Blog
Microsoft Azure Blog
Microsoft Azure Blog
N
Netflix TechBlog - Medium
M
MIT News - Artificial intelligence
GbyAI
GbyAI
人人都是产品经理
人人都是产品经理
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园_首页
爱范儿
爱范儿
博客园 - 三生石上(FineUI控件)
L
LangChain Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
云风的 BLOG
云风的 BLOG
Y
Y Combinator Blog
L
LINUX DO - 热门话题
Project Zero
Project Zero
罗磊的独立博客
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
MongoDB | Blog
MongoDB | Blog
Spread Privacy
Spread Privacy
S
Schneier on Security
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
J
Java Code Geeks
P
Palo Alto Networks Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
博客园 - Franky
T
Threat Research - Cisco Blogs
D
Docker
Hugging Face - Blog
Hugging Face - Blog
S
Securelist
Google DeepMind News
Google DeepMind News
T
The Exploit Database - CXSecurity.com
L
Lohrmann on Cybersecurity
月光博客
月光博客
V
Vulnerabilities – Threatpost
NISL@THU
NISL@THU
V
Visual Studio Blog
AWS News Blog
AWS News Blog
I
Intezer
T
The Blog of Author Tim Ferriss
P
Privacy International News Feed
T
Tor Project blog
F
Full Disclosure
P
Proofpoint News Feed
SecWiki News
SecWiki News
H
Heimdal Security Blog
Help Net Security
Help Net Security
The Hacker News
The Hacker News

博客园 - chaoguo1234

如何自定义 UIScrollView 的减速系数 Plist 二进制格式 UIImageView 设置图片不生效的原因排查 Mach-O 文件结构 Block Copy 的内存布局详解 __block 变量内存布局详解 Block 内存布局详解 XNU Inside: iOS 模拟器 WebKit Insie: WebKit 调试(二) NSMutableDictionary 的内存布局 NSDictionary 内存布局 WebKit Inside: GPU 进程调试 WebKit Inside: 渲染树 WebKit Inside: px 与 pt WebKit Inside: CSS 的匹配原理 dyld: 神秘的 __dso_handle 一文搞懂 ARM 64 系列: ADD(立即数版) 一文搞懂 ARM 64: AUTIBSP 一文搞懂 ARM 64 系列: PACISB XCode 编译 PAG 源码 一文搞懂 ARM 64 系列: 一文搞懂 ARM 64 系列: 函数调用传参与返回值 一文搞懂 ARM 64 系列: 寄存器
Any metadata 的内存布局
chaoguo1234 · 2026-04-12 · via 博客园 - chaoguo1234

Swiftenumstructclassprotocol都有对应的metadata

metadata用来描述上述这些类型本身,这点和OC的元类有点类似。

假设用下面代码定义了一个enum:

enum Direction {
  case top
  case left
  case bottom
  case right
}

经过编译链接之后,上面的enum Direction以及对应的metadata都写入到了对应的Mach-O文件中。

假设编译链接之后的Mach-O文件名为A,那么,使用下面命令就可以查看enum Direction以及对应metadata的位置:

nm -n A | xcrun swift-demangle | grep -i Direction

nm 命令读取Mach-O中的所有符号信息。

swift-demangle对已经mangleswift符号名进行demangle

输出的结果如下:

000000000001e004 s _symbolic _____ 7iOSTest9DirectionO
0000000000020820 s full type metadata for iOSTest.Direction
0000000000020830 S type metadata for iOSTest.Direction

1列的数字代表对应项在Mach-O文件中的偏移。

输出的第1行的符号名7iOSTest9DirectionO有点怪。

这是因为swift-demangle没有彻底demangle干净,我们再次手动demangle下:

xcrun swift-demangle s7iOSTest9DirectionO

注意我们在符号名字前加了一个小写字母s

Swift会在mangle名前加一个字母s,代表Swift

再次demangle的输出结果为:

$s7iOSTest9DirectionO ---> iOSTest.Direction

可以看到,它正是enum Direction本身,位于0x1e004

输出第3行可以看到enum Directionmetadata位于0x20830

输出的第2行还有一个full type metadata,这是什么呢?

Swift里,一个类型的metadata前面根据类型的不同,会有一些其他数据。

其中任何类型都有一个数据是value witness table指针。

value witness tableSwift用来管理类型的生命周期,比如怎么复制、怎么销毁。

metadata

可以看到,所谓的full type metadata就是「其他数据」+对应的type metadata

而我们平时使用的.self语法,得到的就是metadata本身:

(lldb) p unsafeBitCast(Direction.self, to: UnsafeRawPointer.self)
(UnsafeRawPointer) 0x100adc830
(lldb) p/x 0x100adc830 - 0x0000000100abc000
(Int) 0x0000000000020830

从上面lldb的输出看到,经过ASLR的调整,Direction.self的位置正是0x20830

Any是一个protocol,如下面输出:

(lldb) p Any.self
(Any.Protocol) Any

Any还是一个空协议组合,表示「没有任何要求」。

而「没有任何要求」是任何类型都满足的,这也是任何类型都能转成Any的原因。

Anymetadata定义为:

/// stdlib/public/runtime/metadata.cpp
/// The standard metadata for Any.
const FullMetadata<ExistentialTypeMetadata> swift::
METADATA_SYM(ANY_MANGLING) = {
  { &OpaqueExistentialValueWitnesses_0 }, // ValueWitnesses
  ExistentialTypeMetadata(
    ExistentialTypeFlags() // Flags
      .withNumWitnessTables(0)
      .withClassConstraint(ProtocolClassConstraint::Any)
      .withHasSuperclass(false)
      .withSpecialProtocol(SpecialProtocol::None)),
};

上面的定义准确的说,是Anyfull metadata

定义中的FullMetadata是一个C++结构体,定义为:

/// swift/ABI/metadata.h

template <class T> struct FullMetadata : T::HeaderType, T {
  ...
};

其中模版参数T = ExistentialTypeMetadata

我们手动代入后,FullMetadata的完整定义为:

struct FullMetadata : ExistentialTypeMetadata::HeaderType, ExistentialMetadata {
  ...
};

从上面代码可以看到,FullMetadata是多重继承。

一部分继承自ExistentialTypeMetadata::HeaderType

一部分继承ExistentialTypeMetadata

要想弄清楚ExistentialTypeMetadata::HeaderType,首先得看下ExistentialTypeMetadata的定义:

/// stdlib/public/runtime/metadata.cpp

using ExistentialTypeMetadata
  = TargetExistentialTypeMetadata<InProcess>;

从代码上可以看到,ExistentialTypeMetadata实际上是TargetExistentialTypeMetadata<InProcess>

接着看TargetExistentialTypeMetadata的定义:

/// swift/ABI/metadata.h

template <typename Runtime>
struct TargetExistentialTypeMetadata
  : TargetMetadata<Runtime>,
    swift::ABI::TrailingObjects<
      TargetExistentialTypeMetadata<Runtime>,
      ConstTargetMetadataPointer<Runtime, TargetMetadata>,
      TargetProtocolDescriptorRef<Runtime>> {
  using HeaderType = TargetTypeMetadataHeaderBase<Runtime>;
  ...

public:
  using StoredPointer = typename Runtime::StoredPointer;
  /// The number of witness tables and class-constrained-ness of the type.
  ExistentialTypeFlags Flags;

  /// The number of protocols.
  uint32_t NumProtocols;

  ...
};

从代码里可以看到,TargetExistentialTypeMetadata同样是多重继承。

一部分继承自TargetMetadata

一部分继承自swift::ABI::TrailingObjects

swift::ABI::TrailingObjects结构体没有任何实例变量,可以先不用关心。

swift::ABI::TrailingObjects的定义如下:

/// swift/ABI/TrailingObjects.h

emplate <typename BaseTy, typename... TrailingTys>
class swift_ptrauth_struct_derived(BaseTy) TrailingObjects
    : private trailing_objects_internal::TrailingObjectsImpl<
                            trailing_objects_internal::AlignmentCalcHelper<
                                TrailingTys...>::Alignment,
                            BaseTy, TrailingObjects<BaseTy, TrailingTys...>,
                            BaseTy, TrailingTys...> {
  ...
};

我们继续回到TargetExistentialTypeMetadata结构体上来。

TargetExistentialTypeMetadata内部定义了HeaderType:

using HeaderType = TargetTypeMetadataHeaderBase<Runtime>;

从定义上看,TargetExistentialTypeMetadata::HeaderType实际上是TargetTypeMetadataHeaderBase

呜~~~

现在,FullMetadata完整定义可以重写为:

struct FullMetadata : TargetTypeMetadataHeaderBase, TargetExistentialTypeMetadata {
  ...
};

FullMetadata

2.2 内存布局

有了继承关系,就可以画出full metadata的内存布局。

内存布局

2.2.1 ValueWitness

ValueWitness就是value witness table指针,8字节。

2.2.2 Kind

Kind 是一个标识符,代表了当前是什么类型,8字节。

Kind的定义为:

/// swift/ABI/MetadataValues.h

enum class MetadataKind : uint32_t {
#define METADATAKIND(name, value) name = value,
#define ABSTRACTMETADATAKIND(name, start, end)                                 \
  name##_Start = start, name##_End = end,
#include "MetadataKind.def"
  LastEnumerated = 0x7FF,
};

注意看,这里的MetadataKind32bit的,而Kind本身是8字节的。

之所以这么设计,是因为如果一个class可以与OC交互,此时Kind要当成isa指针看待。

完整的Kind定义在文件MetadaKind.def中。

常见的Kind如下:

// 纯 Swift 类
class - 0x0
struct - 0x200
enum - 0x201
optional - 0x202
opaqual - 0x300
tuple - 0x301
existential - 0x303

2.2.3 Flags

Flags是一个C++类,定义如下:

/// swift/ABI/MetadataValues.h

class ExistentialTypeFlags {
public:
  typedef uint32_t int_type;

private:
  enum : int_type {
    NumWitnessTablesMask  = 0x00FFFFFFU,
    ClassConstraintMask   = 0x80000000U, // Warning: Set if NOT class-constrained!
    HasSuperclassMask     = 0x40000000U,
    SpecialProtocolMask   = 0x3F000000U,
    SpecialProtocolShift  = 24U,
  };
  int_type Data;

它里面只有一个实例变量Data,占用4字节32bit

2.3.4 numOfProtocols

numOfProtocols占用4字节。