Skip to content

.set with an offset inconsistently marked as no-dead-strip on Mach-O #104623

@smeenai

Description

@smeenai

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:

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    llvm:mcMachine (object) code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions