-
Notifications
You must be signed in to change notification settings - Fork 15.2k
Description
For the following C code:
int main(int argc, char *argv[]) {
return argc ? (long)__builtin___CFStringMakeConstantString("foo")
: (long)__builtin___CFStringMakeConstantString("bar");
}
If we build it with -O3 on top of a Clang which contains #101222 (which enables private globals to be merged), the resulting object file is different if we compile to an object directly vs. if we compile to assembly and then compile that assembly:
$ clang -target arm64-apple-macos11 -O3 -c merge.c
$ llvm-nm -m merge.o | grep l__unnamed_cfstring_.2
0000000000000040 (__DATA,__cfstring) non-external [alt entry] l__unnamed_cfstring_.2
$ clang -target arm64-apple-macos11 -O3 -S -o merge.s merge.c
$ llvm-mc --triple=arm64-apple-macos11 --filetype=obj -o merge2.o merge.s
$ llvm-nm -m merge2.o | grep l__unnamed_cfstring_.2
0000000000000040 (__DATA,__cfstring) non-external [no dead strip] [alt entry] l__unnamed_cfstring_.2
Notice that the symbol is marked as no-dead-strip when built from assembly but not when built from source directly. The reason is that the generated assembly contains the following:
.set l__unnamed_cfstring_.2, __MergedGlobals+32
Which triggers this logic in MC:
llvm-project/llvm/lib/MC/MCParser/AsmParser.cpp
Line 2959 in 907c7eb
| Out.emitSymbolAttribute(Sym, MCSA_NoDeadStrip); |
If I instead change the line to:
l__unnamed_cfstring_.2 = __MergedGlobals+32
the symbol is not marked as no-dead-strip, which matches the Clang output. It's strange for direct object file emission to not produce the same result as generating assembly and then compiling the assembly; perhaps Clang should be using = instead of .set in its generated assembly? CC @MaskRay