[llvm-dev] [BUG Report] -dead_strip, strips prefix data unconditionally on macOS

Peter Collingbourne via llvm-dev llvm-dev at lists.llvm.org
Mon Mar 6 19:35:47 PST 2017


That will set alt_entry on every atom you define in the text section
(dsp_helper becomes alt_entry by virtue of being an alias). I think that
would prevent dead stripping in text altogether because every atom will be
linked to the previous one.

Peter

On Mon, Mar 6, 2017 at 7:10 PM, Moritz Angermann <moritz.angermann at gmail.com
> wrote:

> Hi Peter,
>
> we though that might cause troubles as well.  My current interim solution
> looks
> like the following:
>
> @.str = private unnamed_addr constant [8 x i8] c"p = %d\0A\00", align 1
>
> %struct.prefix = type { i32 }
> declare i32 @printf(i8*, ...)
>
> define i32 @main() prefix %struct.prefix { i32 123 } {
>   %main = bitcast i32 ()* @main to i32*
>   %prefix_ptr = getelementptr inbounds i32, i32* %main, i32 -1
>   %prefix_val = load i32, i32* %prefix_ptr
>   %ret = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8],
> [8 x i8]* @.str, i32 0, i32 0), i32 %prefix_val)
>   ret i32 0
> }
>
> @main.dsp_helper = alias i32, i32* getelementptr (%struct.prefix,
> %struct.prefix* bitcast (i32 ()* @main to %struct.prefix*), i32 -1, i32 0)
>
> module asm ".alt_entry _main"
> module asm "_main.dsp = _main.dsp_helper"
>
> This still generated the "ld: warning: N_ALT_ENTRY bit set on first atom
> in section __TEXT/__text” warning during linking,
> but seems to work as expected, and computes the prefix data size through
> llvm.
>
> Any drawbacks we should be aware of, using this until the prefix data with
> -dead_strip is fixed in a release built of llvm?
>
> Cheers,
>  Moritz
>
> > On Mar 7, 2017, at 10:54 AM, Peter Collingbourne <peter at pcc.me.uk>
> wrote:
> >
> > I suspect that the format isn't important if you do that, but I wouldn't
> recommend it, at least because inlining (and other inter-procedural
> optimizations) are not expected to work correctly if you produce IR like
> that.
> >
> > Peter
> >
> > On Mon, Mar 6, 2017 at 6:44 PM, Moritz Angermann <
> moritz.angermann at gmail.com> wrote:
> > Peter,
> >
> > thanks again! Yes, we only need to refer to main, but we must ensure that
> > the prefix data is not stripped.
> >
> > I’ll have a look at the AsmPrinter.
> >
> > Another idea that came to mind is abusing the prologue data. And simply
> > injecting the prefix data into the prologue data. Then adding the *real*
> > entry_point as an alt_entry after the prologue data.
> >
> > Right now we have.
> >
> > .- - - - -. <- main.dsp
> > | Prefix  |
> > |- - - - -| <- main
> > | Body    |
> > '- - - - -'
> >
> > with Prologue, I believe:
> >
> > .- - - - - -. <- main
> > | Prologue  |
> > |- - - - - -| <- alt_entry main_alt
> > | Body      |
> > '- - - - - -'
> >
> > This could probably work today. However prologue data says it needs a
> special
> > format.  Do you happen to know, if that format is important as well, if
> we
> > would never ever go through main, but only through main_alt?
> >
> > Cheers,
> >  Moritz
> >
> > > On Mar 7, 2017, at 10:33 AM, Peter Collingbourne <peter at pcc.me.uk>
> wrote:
> > >
> > > Firstly, do you need "main.dsp" defined as an external symbol, or can
> all external references go via "main"? If the answer is the latter, that
> will make the solution simpler.
> > >
> > > If only the latter, you will need to make a change to LLVM here:
> http://llvm-cs.pcc.me.uk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp#650
> > >
> > > Basically you would need to add a hook to the TargetLoweringObjectFile
> class that allows the object format to control how prefix data is emitted.
> For Mach-O you would emit a label for a dummy internal symbol, followed by
> the prefix data and then an alt_entry directive for the function symbol.
> All other object formats would just emit the prefix data.
> > >
> > > Peter
> > >
> > > On Mon, Mar 6, 2017 at 6:16 PM, Moritz Angermann <
> moritz.angermann at gmail.com> wrote:
> > > Thank you Peter!
> > >
> > > That seems to do the trick!
> > >
> > > $ cat test.s
> > >   .section  __TEXT,__text
> > >   .globl _main
> > >
> > >   .long 1
> > > _main:
> > >   inc %eax
> > >   ret
> > >
> > >   .alt_entry _main
> > > _main.dsp = _main-4
> > >
> > >   .subsections_via_symbols
> > >
> > >
> > > $ clang test.s -dead_strip
> > > $ otool -vVtdj a.out
> > > a.out:
> > > _main.dsp:
> > > 0000000100000fb1        01 00   addl    %eax, (%rax)
> > > 0000000100000fb3        00 00   addb    %al, (%rax)
> > > _main:
> > > 0000000100000fb5        ff c0   incl    %eax
> > > 0000000100000fb7        c3      retq
> > >
> > >
> > >
> > > However, now I need to figure out how to generate this from
> > > llvm via an alias.
> > >
> > > @.str = private unnamed_addr constant [8 x i8] c"p = %d\0A\00", align 1
> > >
> > > %struct.prefix = type { i32 }
> > > @main.dsp = alias i32, i32* getelementptr (%struct.prefix,
> %struct.prefix* bitcast (i32 ()* @main to %struct.prefix*), i32 -1, i32 0)
> > >
> > > declare i32 @printf(i8*, ...)
> > >
> > > define i32 @main() prefix %struct.prefix { i32 123 } {
> > >   %main = bitcast i32 ()* @main to i32*
> > >   %prefix_ptr = getelementptr inbounds i32, i32* %main, i32 -1
> > >   %prefix_val = load i32, i32* %prefix_ptr
> > >   %ret = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x
> i8], [8 x i8]* @.str, i32 0, i32 0), i32 %prefix_val)
> > >   ret i32 0
> > > }
> > >
> > >
> > > generates the following for me:
> > >
> > >         .section        __TEXT,__text,regular,pure_instructions
> > >         .macosx_version_min 10, 12
> > >         .globl  _main
> > >         .p2align        4, 0x90
> > >         .long   123                     ## @main
> > >                                         ## 0x7b
> > > _main:
> > >         .cfi_startproc
> > > ## BB#0:
> > >         pushq   %rax
> > > Ltmp0:
> > >         .cfi_def_cfa_offset 16
> > >         movl    _main-4(%rip), %esi
> > >         leaq    L_.str(%rip), %rdi
> > >         xorl    %eax, %eax
> > >         callq   _printf
> > >         xorl    %eax, %eax
> > >         popq    %rcx
> > >         retq
> > >         .cfi_endproc
> > >
> > >         .section        __TEXT,__cstring,cstring_literals
> > > L_.str:                                 ## @.str
> > >         .asciz  "p = %d\n"
> > >
> > >
> > >         .globl  _main.dsp
> > >         .alt_entry      _main.dsp
> > > _main.dsp = _main-4
> > > .subsections_via_symbols
> > >
> > > any ideas how to get the .alt_entry right?
> > >
> > > Cheers,
> > >  Moritz
> > >
> > >
> > > > On Mar 7, 2017, at 10:02 AM, Peter Collingbourne <peter at pcc.me.uk>
> wrote:
> > > >
> > > > On Mon, Mar 6, 2017 at 5:54 PM, Moritz Angermann <
> moritz.angermann at gmail.com> wrote:
> > > > Hi Peter,
> > > >
> > > > I’ve just experimented with this a bit:
> > > >
> > > > Say we would end up with the following assembly:
> > > >
> > > >   .section  __TEXT,__text
> > > >   .globl _main
> > > >
> > > >   .long 1
> > > > _main:
> > > >   inc %eax
> > > >   ret
> > > >
> > > >   .globl  _main.dsp
> > > >   .alt_entry      _main.dsp
> > > >
> > > > What happens if you try ".alt_entry _main" instead? The alt_entry is
> supposed to be bound to the atom appearing *before* it.
> > > >
> > > > _main.dsp = _main-4
> > > >
> > > >   .subsections_via_symbols
> > > >
> > > > (e.g. we inject the .alt_entry after the fact, pointing to the start
> of the prefix data)
> > > >
> > > > this will yield:
> > > >
> > > > $ clang test.s -dead_strip
> > > > ld: warning: N_ALT_ENTRY bit set on first atom in section
> __TEXT/__text
> > > >
> > > > And the prefix data will be stripped again.
> > > >
> > > > E.g. what you end up getting is:
> > > >
> > > > $ otool -vVtdj a.out
> > > > a.out:
> > > > _main:
> > > > 0000000100000fb5        ff c0   incl    %eax
> > > > 0000000100000fb7        c3      retq
> > > >
> > > > instead of what we’d like to get:
> > > >
> > > > otool -vVtdj a.out
> > > > a.out:
> > > > _main.dsp:
> > > > 0000000100000fb1        01 00   addl    %eax, (%rax)
> > > > 0000000100000fb3        00 00   addb    %al, (%rax)
> > > > _main:
> > > > 0000000100000fb5        ff c0   incl    %eax
> > > > 0000000100000fb7        c3      retq
> > > >
> > > > .alt_entry’s are not dead_strip protected, and this makes sense I
> guess, as if the alt_entry is never
> > > > actually called visibly from anywhere, it’s probably not needed.
> However there is the .no_daed_strip
> > > > directive. Thus if we graft this slightly different:
> > > >
> > > >   .section  __TEXT,__text
> > > >   .globl _main
> > > >
> > > >   .long 1
> > > > _main:
> > > >   inc %eax
> > > >   ret
> > > >
> > > >   .no_dead_strip  _main.dsp
> > > >   .alt_entry      _main.dsp
> > > > _main.dsp = _main-4
> > > >
> > > >   .subsections_via_symbols
> > > >
> > > > we still get a warning, but it won’t get stripped. At that point
> however, we don’t need the .alt_entry
> > > > anymore (and can drop the warning).
> > > >
> > > > Thus, I’d propose that for functions with prefix_data, a second
> symbol with .no_dead_strip is emitted
> > > > for the prefix data entry point.
> > > >
> > > > I don't think that is sufficient. I believe that the linker is
> allowed to move the function away from the prefix data even if the function
> is not dead stripped.
> > > >
> > > > Peter
> > > >
> > > >
> > > > Cheers,
> > > >  Moritz
> > > >
> > > >
> > > > > On Mar 7, 2017, at 3:35 AM, Peter Collingbourne <peter at pcc.me.uk>
> wrote:
> > > > >
> > > > > That is in theory what omitting the .subsections_via_symbols
> directive is supposed to do, but in an experiment I ran a year or two ago I
> found that the Mach-O linker was still dead stripping on symbol boundaries
> with this directive omitted.
> > > > >
> > > > > In any case, a more precise approach has more recently (~a few
> months ago) become possible. There is a relatively new asm directive called
> .altentry that, as I understand it, tells the linker to disregard a given
> symbol as a section boundary (LLVM already uses this for aliases pointing
> into the middle of a global). So what you would do is to use .altentry on
> the function symbol, with an internal symbol appearing before the prefix
> data to ensure that it is not considered part of the body of the previous
> function.
> > > > >
> > > > > Peter
> > > > >
> > > > > On Mon, Mar 6, 2017 at 11:19 AM, James Y Knight via llvm-dev <
> llvm-dev at lists.llvm.org> wrote:
> > > > > AFAIK, this cannot actually work on Apple platforms, because its
> object file format (Mach-O) doesn't use sections to determine the ranges of
> code/data to keep together, but instead _infers_ boundaries based on the
> range between global symbols in the symbol table.
> > > > >
> > > > > So, the symbol pointing to the beginning of @main *necessarily*
> makes that be a section boundary.
> > > > >
> > > > > I think the best that could be done in LLVM is to not emit the
> ".subsections_via_symbols" asm directive (effectively disabling dead
> stripping on that object) if any prefix data exists. Currently it emits
> that flag unconditionally for MachO.
> > > > >
> > > > > On Mon, Mar 6, 2017 at 4:40 AM, Moritz Angermann via llvm-dev <
> llvm-dev at lists.llvm.org> wrote:
> > > > > Hi,
> > > > >
> > > > > I just came across a rather annoying behavior with llvm 3.9.
> Assuming the following
> > > > > samle code in test.ll:
> > > > >
> > > > > ; Lets have some global int x = 4
> > > > > @x = global i32 10, align 4
> > > > > ; and two strings "p = %d\n" for the prefix data,
> > > > > ; as well as "x = %d\n" to print the (global) x value.
> > > > > @.str = private unnamed_addr constant [8 x i8] c"x = %d\0A\00",
> align 1
> > > > > @.str2 = private unnamed_addr constant [8 x i8] c"p = %d\0A\00",
> align 1
> > > > >
> > > > > ; declare printf, we'll use this later for printf style debugging.
> > > > > declare i32 @printf(i8*, ...)
> > > > >
> > > > > ; define a main function.
> > > > > define i32 @main() prefix i32 123 {
> > > > >   ; obtain a i32 pointer to the main function.
> > > > >   ; the prefix data is right before that pointer.
> > > > >   %main = bitcast i32 ()* @main to i32*
> > > > >
> > > > >   ; use the gep, to cmpute the start of the prefix data.
> > > > >   %prefix_ptr = getelementptr inbounds i32, i32* %main, i32 -1
> > > > >   ; and load it.
> > > > >   %prefix_val = load i32, i32* %prefix_ptr
> > > > >
> > > > >   ; print that value.
> > > > >   %ret = call i32 (i8*, ...) @printf(i8* getelementptr inbounds
> ([8 x i8], [8 x i8]* @.str2, i32 0, i32 0), i32 %prefix_val)
> > > > >
> > > > >   ; similarly let's do the same with the global x.
> > > > >   %1 = alloca i32, align 4
> > > > >   store i32 0, i32* %1, align 4
> > > > >   %2 = load i32, i32* @x, align 4
> > > > >   %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8
> x i8], [8 x i8]* @.str, i32 0, i32 0), i32 %2)
> > > > >   ret i32 0
> > > > > }
> > > > >
> > > > > gives the following result (expected)
> > > > >
> > > > >    $ clang test.ll
> > > > >    $ ./a.out
> > > > >    p = 123
> > > > >    x = 10
> > > > >
> > > > > however, with -dead_strip on macOS, we see the following:
> > > > >
> > > > >    $ clang test.ll -dead_strip
> > > > >    $ ./a.out
> > > > >    p = 0
> > > > >    x = 10
> > > > >
> > > > > Thus I believe we are incorrectly stripping prefix data when
> linking with -dead_strip on macOS.
> > > > >
> > > > > As I do not have a bugzilla account, and hence cannot post this as
> a proper bug report.
> > > > >
> > > > > Cheers,
> > > > >  Moritz
> > > > > _______________________________________________
> > > > > LLVM Developers mailing list
> > > > > llvm-dev at lists.llvm.org
> > > > > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
> > > > >
> > > > >
> > > > > _______________________________________________
> > > > > LLVM Developers mailing list
> > > > > llvm-dev at lists.llvm.org
> > > > > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
> > > > >
> > > > >
> > > > >
> > > > >
> > > > > --
> > > > > --
> > > > > Peter
> > > >
> > > >
> > > >
> > > >
> > > > --
> > > > --
> > > > Peter
> > >
> > >
> > >
> > >
> > > --
> > > --
> > > Peter
> >
> >
> >
> >
> > --
> > --
> > Peter
>
>


-- 
-- 
Peter
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170306/4d67b0f8/attachment-0001.html>


More information about the llvm-dev mailing list