That makes a lot of sense, thank you.
As an interesting experiment I tried commenting out IGM.setTrueConstGlobal(var);
in TypeContextDescriptorBuilderBase.emit()
. This "worked" for me. It put the nominal type descriptor for the class type I was investigating into a section .rodata.$ss29_AVRArrayBufferStorageManagerCMn
in the object file. This might seem like a trivial change, but it allowed the tools to "untangle" the necessary symbols for metadata records needed in my trivial sample programs and the symbols that aren't needed. What seemed to be happening was when metadata records from my standard library were referenced, the unresolved symbol chain ended up linking nominal type descriptors from .rodata
in one of the objects in the static library, that would also have other things that weren't actually needed but were in the same file, all their symbols got resolved, linked out to other object files and so on... before I knew it, 450kb of unused code was linked. Now my simple test program is back down to 3-4k, which is tractable.
(I think @dragomirecky saw some of the same issues in his investigations)
At the moment, the platform is in a slightly strange state because we have just started to introduce a very small amount of runtime, including a trimmed down ARC. We still don't support the vast majority of things you'd expect to see, but it's not an issue in the very simple programs we are creating. And we very much emphasise writing in such a way that things like generic type params are known at compile time and fully LTO optimised away. It's a work in progress of course. But in a lot of ways, most of the metadata records being emitted in our program are linked and never really used by the runtime in any meaningful way I think.
With regard to security, it's a really interesting point. We aren't going to have the same memory protections available as "big" processors do. If and when we start to really meaningfully need to access a lot of these metadata records, we'll probably need to resolve a lot of platform bugs in AVR to do with RAM/flash address spaces. At that point, I think it would be good to move all the metadata records the compiler emits on our platform into flash memory. That should help solve the issue of security for the nominal type descriptor (AVR micros have security protection for flash writes).
One thing I still don't quite understand, from a security point of view, shouldn't the above arguments apply also to the full type metadata?
When I looked at the llvm IR for the full type metadata and for the nominal type descriptor, they looked something like this...
@"$ss29_AVRArrayBufferStorageManagerCMf" = linkonce_odr hidden global <{ void (%Ts29_AVRArrayBufferStorageManagerC*) addrspace(1)*, i8**, i16, %swift.type*, i32, i32, i32, i16, i16, i32, i32, <{ i32, i16, i16, i16, i32, i32, i32, i32, i32, i32, i32, i32, i32, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor }>*, i8 addrspace(1)*, i16, i8 addrspace(1)*, i8 addrspace(1)*, i8 addrspace(1)*, %Ts29_AVRArrayBufferStorageManagerC* (i8*, %swift.type*) addrspace(1)* }>
<{
void (%Ts29_AVRArrayBufferStorageManagerC*) addrspace(1)* @"$ss29_AVRArrayBufferStorageManagerCfD",
i8** @"$sBoWV",
i16 0,
%swift.type* null,
i32 2,
i32 0,
i32 6,
i16 1,
i16 0,
i32 46,
i32 4,
<{ i32, i16, i16, i16, i32, i32, i32, i32, i32, i32, i32, i32, i32, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor }>* @"$ss29_AVRArrayBufferStorageManagerCMn",
i8 addrspace(1)* null,
i16 4,
i8 addrspace(1)* bitcast (void () addrspace(1)* @swift_deletedMethodError to i8 addrspace(1)*),
i8 addrspace(1)* bitcast (void () addrspace(1)* @swift_deletedMethodError to i8 addrspace(1)*),
i8 addrspace(1)* bitcast (void () addrspace(1)* @swift_deletedMethodError to i8 addrspace(1)*),
%Ts29_AVRArrayBufferStorageManagerC* (i8*, %swift.type*) addrspace(1)* @"$ss29_AVRArrayBufferStorageManagerCyABBpcfC" }>, align 2
@"$ss29_AVRArrayBufferStorageManagerCMn" = protected constant <{ i32, i16, i16, i16, i32, i32, i32, i32, i32, i32, i32, i32, i32, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor }>
<{
i32 -2147483568,
i16 sub (
i16 ptrtoint (<{ i32, i32, i16 }>* @"$ssMXM" to i16),
i16 ptrtoint (i16* getelementptr inbounds (
<{ i32, i16, i16, i16, i32, i32, i32, i32, i32, i32, i32, i32, i32, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor }>,
<{ i32, i16, i16, i16, i32, i32, i32, i32, i32, i32, i32, i32, i32, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor }>* @"$ss29_AVRArrayBufferStorageManagerCMn",
i32 0,
i32 1) to i16)),
i16 sub (
i16 ptrtoint ([30 x i8]* @.str.29._AVRArrayBufferStorageManager to i16),
i16 ptrtoint (i16* getelementptr inbounds (
<{ i32, i16, i16, i16, i32, i32, i32, i32, i32, i32, i32, i32, i32, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor }>,
<{ i32, i16, i16, i16, i32, i32, i32, i32, i32, i32, i32, i32, i32, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor }>* @"$ss29_AVRArrayBufferStorageManagerCMn",
i32 0,
i32 2) to i16)),
i16 sub (
i16 ptrtoint (%swift.metadata_response (i16) addrspace(1)* @"$ss29_AVRArrayBufferStorageManagerCMa" to i16),
i16 ptrtoint (i16* getelementptr inbounds (
<{ i32, i16, i16, i16, i32, i32, i32, i32, i32, i32, i32, i32, i32, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor }>,
<{ i32, i16, i16, i16, i32, i32, i32, i32, i32, i32, i32, i32, i32, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor }>* @"$ss29_AVRArrayBufferStorageManagerCMn",
i32 0,
i32 3) to i16)),
i32 0,
i32 0,
i32 2,
i32 21,
i32 5,
i32 1,
i32 16,
i32 17,
i32 4,
%swift.method_descriptor { i32 18, i16 0 },
%swift.method_descriptor { i32 19, i16 0 },
%swift.method_descriptor { i32 20, i16 0 },
%swift.method_descriptor { i32 1,
i16 sub (
i16 ptrtoint (%Ts29_AVRArrayBufferStorageManagerC* (i8*, %swift.type*) addrspace(1)* @"$ss29_AVRArrayBufferStorageManagerCyABBpcfC" to i16),
i16 ptrtoint (i16* getelementptr inbounds (
<{ i32, i16, i16, i16, i32, i32, i32, i32, i32, i32, i32, i32, i32, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor }>,
<{ i32, i16, i16, i16, i32, i32, i32, i32, i32, i32, i32, i32, i32, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor, %swift.method_descriptor }>* @"$ss29_AVRArrayBufferStorageManagerCMn",
i32 0,
i32 16,
i32 1) to i16))
}
}>,
section ".rodata", <<< IF WE DONT PUT IT IN RODATA, WHERE DOES IT GO?
align 4
I've added some line wrapping/whitespace to try and make it a bit easier to read!
But anyway, the point I'm not quite understanding is the full type metadata is IRGen'ed as @"$ss29_AVRArrayBufferStorageManagerCMf" = linkonce_odr hidden global ...
but the nominal type descriptor is IRGen'ed as @"$ss29_AVRArrayBufferStorageManagerCMn" = protected constant ... section ".rodata"
. So does that mean that the type metadata is "in regular data RAM" but the nominal type descriptor is in "protected read only memory"?
It's probably me not understanding the subleties of LLVM again!
Thanks very much again guys!
Carl
(p.s. @jrose the linking so far hasn't caused me any issues on metadata records but, like I mention above, I barely use them at the moment. When I later implement runtime that needs them I may well run into the issues you mention!)