Jerome Forissier via llvm-dev
2020-Jun-11 14:10 UTC
[llvm-dev] Issue with __attribute__((constructor)) and -Os -fno-common
Hi, I think that Clang erroneously discards a function annotated with __attribute__((constructor)) when flags -Os -fno-common are given. Test case below. What do you think? Thanks. ----8<--------8<--------8<--------8<--------8<--------8<-------- $ cat ctor.c int val; static void __attribute__((constructor)) init_fn(void) { val = 1; } int main(int argc, char *argv[]) { return val; } ----8<--------8<--------8<--------8<--------8<--------8<-------- Here is what I observed: - Clang (10.0.0-4ubuntu1) with -Os -fno-common: function init_fn() is NOT emitted, - Clang (10.0.0-4ubuntu1) with no flag, or only -Os or -fno-common: init_fn() is present as expected, - GCC (Ubuntu 9.3.0-10ubuntu1) with the same flags: init_fn() is present too, - Since https://reviews.llvm.org/D75056, -fno-common is the default and therefore -Os is enough to cause the issue. ----8<--------8<--------8<--------8<--------8<--------8<-------- $ clang --target=arm-linux-gnueabihf -Os -fno-common -S ctor.c \ -o /dev/stdout | grep init_fn $ clang --target=arm-linux-gnueabihf -Os -S ctor.c \ -o /dev/stdout | grep init_fn .p2align 2 @ -- Begin function init_fn .type init_fn,%function .code 32 @ @init_fn init_fn: .size init_fn, .Lfunc_end0-init_fn .long init_fn(target1) .addrsig_sym init_fn $ clang --target=arm-linux-gnueabihf -fno-common -S ctor.c \ -o /dev/stdout | grep init_fn .p2align 2 @ -- Begin function init_fn .type init_fn,%function .code 32 @ @init_fn init_fn: .size init_fn, .Lfunc_end0-init_fn .long init_fn(target1) .addrsig_sym init_fn $ arm-linux-gnueabihf-gcc -Os -fno-common -S ctor.c \ -o /dev/stdout | grep init_fn .type init_fn, %function init_fn: .size init_fn, .-init_fn .word init_fn(target1) ----8<--------8<--------8<--------8<--------8<--------8<-------- -- Jerome
James Y Knight via llvm-dev
2020-Jun-11 21:25 UTC
[llvm-dev] Issue with __attribute__((constructor)) and -Os -fno-common
The global constructor was removed by setting the initial value of "val" to 1 instead of 0. So, the behavior of this program is preserved. Doesn't look like erroneous behavior. On Thu, Jun 11, 2020 at 10:12 AM Jerome Forissier via llvm-dev < llvm-dev at lists.llvm.org> wrote:> Hi, > > I think that Clang erroneously discards a function annotated with > __attribute__((constructor)) when flags -Os -fno-common are given. Test > case below. > > What do you think? > > Thanks. > > ----8<--------8<--------8<--------8<--------8<--------8<-------- > $ cat ctor.c > int val; > > static void __attribute__((constructor)) init_fn(void) > { > val = 1; > } > > int main(int argc, char *argv[]) > { > return val; > } > ----8<--------8<--------8<--------8<--------8<--------8<-------- > > Here is what I observed: > > - Clang (10.0.0-4ubuntu1) with -Os -fno-common: function init_fn() is > NOT emitted, > - Clang (10.0.0-4ubuntu1) with no flag, or only -Os or -fno-common: > init_fn() is present as expected, > - GCC (Ubuntu 9.3.0-10ubuntu1) with the same flags: init_fn() is present > too, > - Since https://reviews.llvm.org/D75056, -fno-common is the default and > therefore -Os is enough to cause the issue. > > ----8<--------8<--------8<--------8<--------8<--------8<-------- > $ clang --target=arm-linux-gnueabihf -Os -fno-common -S ctor.c \ > -o /dev/stdout | grep init_fn > $ clang --target=arm-linux-gnueabihf -Os -S ctor.c \ > -o /dev/stdout | grep init_fn > .p2align 2 @ -- Begin function init_fn > .type init_fn,%function > .code 32 @ @init_fn > init_fn: > .size init_fn, .Lfunc_end0-init_fn > .long init_fn(target1) > .addrsig_sym init_fn > $ clang --target=arm-linux-gnueabihf -fno-common -S ctor.c \ > -o /dev/stdout | grep init_fn > .p2align 2 @ -- Begin function init_fn > .type init_fn,%function > .code 32 @ @init_fn > init_fn: > .size init_fn, .Lfunc_end0-init_fn > .long init_fn(target1) > .addrsig_sym init_fn > $ arm-linux-gnueabihf-gcc -Os -fno-common -S ctor.c \ > -o /dev/stdout | grep init_fn > .type init_fn, %function > init_fn: > .size init_fn, .-init_fn > .word init_fn(target1) > ----8<--------8<--------8<--------8<--------8<--------8<-------- > > -- > Jerome > _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20200611/85ec4980/attachment.html>
Jerome Forissier via llvm-dev
2020-Jun-12 08:05 UTC
[llvm-dev] Issue with __attribute__((constructor)) and -Os -fno-common
On 6/11/20 11:25 PM, James Y Knight wrote:> The global constructor was removed by setting the initial value of "val" to > 1 instead of 0. So, the behavior of this program is preserved. Doesn't look > like erroneous behavior.OK, my example is too simplified indeed. Please consider the following instead: int val; static void __attribute__((constructor)) init_fn(void) { val++; } int main(int argc, char *argv[]) { return val; } With this, clang -Os -fno-common generates a global variable initialized to 1 and discards init_fn(). Now, what happens if the executable is later linked against a shared library which has its own constructor and sets "val" to some non-zero value? I mean this for instance: extern int val; static void __attribute__((constructor)) so_init_fn(void) { val = 1; } I would expect the main program to return 2, not 1. Last thing, if I define "val" as volatile, the programs behaves as expected. Are we in "unspecified, just don't do this" territory here? Thanks, -- Jerome> > On Thu, Jun 11, 2020 at 10:12 AM Jerome Forissier via llvm-dev < > llvm-dev at lists.llvm.org> wrote: > >> Hi, >> >> I think that Clang erroneously discards a function annotated with >> __attribute__((constructor)) when flags -Os -fno-common are given. Test >> case below. >> >> What do you think? >> >> Thanks. >> >> ----8<--------8<--------8<--------8<--------8<--------8<-------- >> $ cat ctor.c >> int val; >> >> static void __attribute__((constructor)) init_fn(void) >> { >> val = 1; >> } >> >> int main(int argc, char *argv[]) >> { >> return val; >> } >> ----8<--------8<--------8<--------8<--------8<--------8<-------- >> >> Here is what I observed: >> >> - Clang (10.0.0-4ubuntu1) with -Os -fno-common: function init_fn() is >> NOT emitted, >> - Clang (10.0.0-4ubuntu1) with no flag, or only -Os or -fno-common: >> init_fn() is present as expected, >> - GCC (Ubuntu 9.3.0-10ubuntu1) with the same flags: init_fn() is present >> too, >> - Since https://reviews.llvm.org/D75056, -fno-common is the default and >> therefore -Os is enough to cause the issue. >> >> ----8<--------8<--------8<--------8<--------8<--------8<-------- >> $ clang --target=arm-linux-gnueabihf -Os -fno-common -S ctor.c \ >> -o /dev/stdout | grep init_fn >> $ clang --target=arm-linux-gnueabihf -Os -S ctor.c \ >> -o /dev/stdout | grep init_fn >> .p2align 2 @ -- Begin function init_fn >> .type init_fn,%function >> .code 32 @ @init_fn >> init_fn: >> .size init_fn, .Lfunc_end0-init_fn >> .long init_fn(target1) >> .addrsig_sym init_fn >> $ clang --target=arm-linux-gnueabihf -fno-common -S ctor.c \ >> -o /dev/stdout | grep init_fn >> .p2align 2 @ -- Begin function init_fn >> .type init_fn,%function >> .code 32 @ @init_fn >> init_fn: >> .size init_fn, .Lfunc_end0-init_fn >> .long init_fn(target1) >> .addrsig_sym init_fn >> $ arm-linux-gnueabihf-gcc -Os -fno-common -S ctor.c \ >> -o /dev/stdout | grep init_fn >> .type init_fn, %function >> init_fn: >> .size init_fn, .-init_fn >> .word init_fn(target1) >> ----8<--------8<--------8<--------8<--------8<--------8<-------- >> >> -- >> Jerome >> _______________________________________________ >> LLVM Developers mailing list >> llvm-dev at lists.llvm.org >> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev >> >