summaryrefslogtreecommitdiffhomepage
path: root/src/abi.h
blob: 98d972ef018c437eebf2067b04a59480cebc33f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
 * Copyright © 2023 Michael Smith <mikesmiffy128@gmail.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef INC_ABI_H
#define INC_ABI_H

#include "intdefs.h"

/*
 * This file defines miscellaneous C++ ABI stuff. Looking at it may cause brain
 * damage and/or emotional trauma.
 */

#ifdef _WIN32 // Windows RTTI stuff, obviously only used on Windows.

// MSVC RTTI is quite a black box, but thankfully there's some useful sources:
// - https://doxygen.reactos.org/d0/dcf/cxx_8h_source.html
// - https://blog.quarkslab.com/visual-c-rtti-inspection.html
// - https://www.geoffchappell.com/studies/msvc/language/predefined/
// - https://docs.rs/pelite/0.5.0/src/pelite/pe32/msvc.rs.html

// By the way, while I'm here I'd just like to point out how ridiculous this
// layout is. Whoever decided to put this many levels of indirection over what
// should be a small lookup table is an absolute nutcase. I hope that individual
// has gotten some help by now, mostly for the sake of others.

struct msvc_rtti_descriptor_head {
	void **vtab;
	void *unknown; // ???
	// descriptor includes this, but constant flexible arrays are annoying, so
	// this structure is just the header part and the string is tacked on in the
	// DEF_MSVC_BASIC_RTTI macro below
	//char classname[];
};

// "pointer to member displacement"
struct msvc_pmd { int mdisp, pdisp, vdisp; };

struct msvc_basedesc {
	const struct msvc_rtti_descriptor_head *desc;
	uint nbases;
	struct msvc_pmd where;
	uint attr;
};

struct msvc_rtti_hierarchy {
	uint sig;
	uint attrs;
	uint nbaseclasses;
	const struct msvc_basedesc **baseclasses;
};

struct msvc_rtti_locator {
	uint sig;
	int baseoff;
	// ctor offset, or some flags; reactos and rust pelite say different things?
	int unknown;
	const struct msvc_rtti_descriptor_head *desc;
	const struct msvc_rtti_hierarchy *hier;
};

// I mean seriously look at this crap!
#define DEF_MSVC_BASIC_RTTI(mod, name, vtab, typestr) \
mod const struct msvc_rtti_locator name; \
static const struct { \
	struct msvc_rtti_descriptor_head d; \
	char classname[sizeof("" typestr)]; \
} _desc_##name = {(vtab), 0, .classname = "" typestr}; \
static const struct msvc_basedesc _basedesc_##name = { \
	&_desc_##name.d, 0, {0, 0, 0}, 0 \
}; \
mod const struct msvc_rtti_locator name = { \
	0, 0, 0, \
	&_desc_##name.d, \
	&(struct msvc_rtti_hierarchy){ \
		0, 1 /* match engine */, 1, \
		(const struct msvc_basedesc *[]){&_basedesc_##name} \
	} \
};

#else

struct itanium_type_info_vtable {
	void *dtor1, *dtor2;
};

struct itanium_type_info {
	struct itanium_type_info_vtable *vtable;
	const char *name;
};

struct itanium_vmi_type_info {
	struct itanium_type_info base;
	uint flags;
	uint nbases;
	// then there's a flexible array of `__base_class_type_info`s, but for our
	// purposes we can just have zero bases and avoid dealing with more nonsense
};

struct itanium_type_info_vtable_wrapper {
	// Oh CHRIST, Unix RTTI is bonkers too. Each type_info is itself one of
	// several subclasses with its own RTTI; the RTTI has RTTI!
	ssize topoffset;
	struct itanium_type_info *rtti;
	struct itanium_type_info_vtable vtable;
};

// `typeinfo for __cxxabiv1::__vmi_class_type_info` in libcxxabi - type_info
// comparison is identity-based, so we need to import this from a shared object
// in order to implement the same ABI. I honestly don't know whether this or the
// MSVC design is more stupid.
extern struct itanium_type_info _ZTIN10__cxxabiv121__vmi_class_type_infoE;

// XXX: just static for now, as only used for cvars and lto would dedupe anyway.
static void _itanium_type_info_dtor(void *this) {}

#define DEF_ITANIUM_BASIC_RTTI(mod, name, typestr) \
	mod const struct itanium_vmi_type_info name = { \
		&(struct itanium_type_info_vtable_wrapper){ \
			0, &_ZTIN10__cxxabiv121__vmi_class_type_infoE, \
			(void *)&_itanium_type_info_dtor, (void *)&_itanium_type_info_dtor \
		}.vtable, \
		typestr, \
		0, 0 \
	};

#endif

#endif

// vi: sw=4 ts=4 noet tw=80 cc=80