Skip to content

Commit 44b99a6

Browse files
committed
exec: Build page-vary-common.c with -fno-lto
In bbc17ca, we used an alias attribute to allow target_page to be declared const, and yet be initialized late. This fails when using LTO with several versions of gcc. The compiler looks through the alias and decides that the const variable is statically initialized to zero, then propagates that zero to many uses of the variable. This can be avoided by compiling one object file with -fno-lto. In this way, any initializer cannot be seen, and the constant propagation does not occur. Since we are certain to have this separate compilation unit, we can drop the alias attribute as well. We simply have differing declarations for target_page in different compilation units. Drop the use of init_target_page, and drop the configure detection for CONFIG_ATTRIBUTE_ALIAS. In order to change the compilation flags for a file with meson, we must use a static_library. This runs into specific_ss, where we would need to create many static_library instances. Fix this by splitting page-vary.c: the page-vary-common.c part is compiled once as a static_library, while the page-vary.c part is left in specific_ss in order to handle the target-specific value of TARGET_PAGE_BITS_MIN. Reported-by: Gavin Shan <[email protected]> Signed-off-by: Richard Henderson <[email protected]> Message-Id: <[email protected]> [PMD: Fix typo in subject, split original patch in 3] Signed-off-by: Philippe Mathieu-Daudé <[email protected]> Tested-by: Gavin Shan <[email protected]> Message-Id: <[email protected]> [rth: Update MAINTAINERS] Signed-off-by: Richard Henderson <[email protected]>
1 parent 27eb9d6 commit 44b99a6

File tree

7 files changed

+84
-96
lines changed

7 files changed

+84
-96
lines changed

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ S: Maintained
118118
F: softmmu/cpus.c
119119
F: cpus-common.c
120120
F: page-vary.c
121+
F: page-vary-common.c
121122
F: accel/tcg/
122123
F: accel/stubs/tcg-stub.c
123124
F: util/cacheinfo.c

configure

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4889,21 +4889,6 @@ if test "$plugins" = "yes" &&
48894889
"for this purpose. You can't build with --static."
48904890
fi
48914891

4892-
########################################
4893-
# See if __attribute__((alias)) is supported.
4894-
# This false for Xcode 9, but has been remedied for Xcode 10.
4895-
# Unfortunately, travis uses Xcode 9 by default.
4896-
4897-
attralias=no
4898-
cat > $TMPC << EOF
4899-
int x = 1;
4900-
extern const int y __attribute__((alias("x")));
4901-
int main(void) { return 0; }
4902-
EOF
4903-
if compile_prog "" "" ; then
4904-
attralias=yes
4905-
fi
4906-
49074892
########################################
49084893
# check if getauxval is available.
49094894

@@ -5935,10 +5920,6 @@ if test "$atomic64" = "yes" ; then
59355920
echo "CONFIG_ATOMIC64=y" >> $config_host_mak
59365921
fi
59375922

5938-
if test "$attralias" = "yes" ; then
5939-
echo "CONFIG_ATTRIBUTE_ALIAS=y" >> $config_host_mak
5940-
fi
5941-
59425923
if test "$getauxval" = "yes" ; then
59435924
echo "CONFIG_GETAUXVAL=y" >> $config_host_mak
59445925
fi

include/exec/cpu-all.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,11 +216,7 @@ static inline void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val
216216

217217
#ifdef TARGET_PAGE_BITS_VARY
218218
# include "exec/page-vary.h"
219-
#if defined(CONFIG_ATTRIBUTE_ALIAS) || !defined(IN_EXEC_VARY)
220219
extern const TargetPageBits target_page;
221-
#else
222-
extern TargetPageBits target_page;
223-
#endif
224220
#ifdef CONFIG_DEBUG_TCG
225221
#define TARGET_PAGE_BITS ({ assert(target_page.decided); target_page.bits; })
226222
#define TARGET_PAGE_MASK ({ assert(target_page.decided); \

include/exec/page-vary.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,9 @@ typedef struct {
2626
uint64_t mask;
2727
} TargetPageBits;
2828

29+
#ifdef IN_PAGE_VARY
30+
extern bool set_preferred_target_page_bits_common(int bits);
31+
extern void finalize_target_page_bits_common(int min);
32+
#endif
33+
2934
#endif /* EXEC_PAGE_VARY_H */

meson.build

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1944,6 +1944,24 @@ specific_ss.add(when: 'CONFIG_TCG', if_true: files(
19441944
))
19451945
specific_ss.add(when: 'CONFIG_TCG_INTERPRETER', if_true: files('tcg/tci.c'))
19461946

1947+
# Work around a gcc bug/misfeature wherein constant propagation looks
1948+
# through an alias:
1949+
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99696
1950+
# to guess that a const variable is always zero. Without lto, this is
1951+
# impossible, as the alias is restricted to page-vary-common.c. Indeed,
1952+
# without lto, not even the alias is required -- we simply use different
1953+
# declarations in different compilation units.
1954+
pagevary = files('page-vary-common.c')
1955+
if get_option('b_lto')
1956+
pagevary_flags = ['-fno-lto']
1957+
if get_option('cfi')
1958+
pagevary_flags += '-fno-sanitize=cfi-icall'
1959+
endif
1960+
pagevary = static_library('page-vary-common', sources: pagevary,
1961+
c_args: pagevary_flags)
1962+
pagevary = declare_dependency(link_with: pagevary)
1963+
endif
1964+
common_ss.add(pagevary)
19471965
specific_ss.add(files('page-vary.c'))
19481966

19491967
subdir('backends')

page-vary-common.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Variable page size handling -- target independent part.
3+
*
4+
* Copyright (c) 2003 Fabrice Bellard
5+
*
6+
* This library is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public
8+
* License as published by the Free Software Foundation; either
9+
* version 2.1 of the License, or (at your option) any later version.
10+
*
11+
* This library is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public
17+
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#define IN_PAGE_VARY 1
21+
22+
#include "qemu/osdep.h"
23+
#include "qemu-common.h"
24+
#include "exec/page-vary.h"
25+
26+
/* WARNING: This file must *not* be complied with -flto. */
27+
28+
TargetPageBits target_page;
29+
30+
bool set_preferred_target_page_bits_common(int bits)
31+
{
32+
/*
33+
* The target page size is the lowest common denominator for all
34+
* the CPUs in the system, so we can only make it smaller, never
35+
* larger. And we can't make it smaller once we've committed to
36+
* a particular size.
37+
*/
38+
if (target_page.bits == 0 || target_page.bits > bits) {
39+
if (target_page.decided) {
40+
return false;
41+
}
42+
target_page.bits = bits;
43+
}
44+
return true;
45+
}
46+
47+
void finalize_target_page_bits_common(int min)
48+
{
49+
if (target_page.bits == 0) {
50+
target_page.bits = min;
51+
}
52+
target_page.mask = -1ull << target_page.bits;
53+
target_page.decided = true;
54+
}

page-vary.c

Lines changed: 6 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -17,92 +17,25 @@
1717
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
1818
*/
1919

20+
#define IN_PAGE_VARY 1
21+
2022
#include "qemu/osdep.h"
2123
#include "qemu-common.h"
22-
23-
#define IN_EXEC_VARY 1
24-
2524
#include "exec/exec-all.h"
2625

27-
#ifdef TARGET_PAGE_BITS_VARY
28-
# ifdef CONFIG_ATTRIBUTE_ALIAS
29-
/*
30-
* We want to declare the "target_page" variable as const, which tells
31-
* the compiler that it can cache any value that it reads across calls.
32-
* This avoids multiple assertions and multiple reads within any one user.
33-
*
34-
* This works because we finish initializing the data before we ever read
35-
* from the "target_page" symbol.
36-
*
37-
* This also requires that we have a non-constant symbol by which we can
38-
* perform the actual initialization, and which forces the data to be
39-
* allocated within writable memory. Thus "init_target_page", and we use
40-
* that symbol exclusively in the two functions that initialize this value.
41-
*
42-
* The "target_page" symbol is created as an alias of "init_target_page".
43-
*/
44-
static TargetPageBits init_target_page;
45-
46-
/*
47-
* Note that this is *not* a redundant decl, this is the definition of
48-
* the "target_page" symbol. The syntax for this definition requires
49-
* the use of the extern keyword. This seems to be a GCC bug in
50-
* either the syntax for the alias attribute or in -Wredundant-decls.
51-
*
52-
* See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91765
53-
*/
54-
# pragma GCC diagnostic push
55-
# pragma GCC diagnostic ignored "-Wredundant-decls"
56-
57-
extern const TargetPageBits target_page
58-
__attribute__((alias("init_target_page")));
59-
60-
# pragma GCC diagnostic pop
61-
# else
62-
/*
63-
* When aliases are not supported then we force two different declarations,
64-
* by way of suppressing the header declaration with IN_EXEC_VARY.
65-
* We assume that on such an old compiler, LTO cannot be used, and so the
66-
* compiler cannot not detect the mismatched declarations, and all is well.
67-
*/
68-
TargetPageBits target_page;
69-
# define init_target_page target_page
70-
# endif
71-
#endif
72-
7326
bool set_preferred_target_page_bits(int bits)
7427
{
75-
/*
76-
* The target page size is the lowest common denominator for all
77-
* the CPUs in the system, so we can only make it smaller, never
78-
* larger. And we can't make it smaller once we've committed to
79-
* a particular size.
80-
*/
8128
#ifdef TARGET_PAGE_BITS_VARY
8229
assert(bits >= TARGET_PAGE_BITS_MIN);
83-
if (init_target_page.bits == 0 || init_target_page.bits > bits) {
84-
if (init_target_page.decided) {
85-
return false;
86-
}
87-
init_target_page.bits = bits;
88-
}
89-
#endif
30+
return set_preferred_target_page_bits_common(bits);
31+
#else
9032
return true;
33+
#endif
9134
}
9235

9336
void finalize_target_page_bits(void)
9437
{
9538
#ifdef TARGET_PAGE_BITS_VARY
96-
if (init_target_page.bits == 0) {
97-
init_target_page.bits = TARGET_PAGE_BITS_MIN;
98-
}
99-
init_target_page.mask = (target_long)-1 << init_target_page.bits;
100-
init_target_page.decided = true;
101-
102-
/*
103-
* For the benefit of an -flto build, prevent the compiler from
104-
* hoisting a read from target_page before we finish initializing.
105-
*/
106-
barrier();
39+
finalize_target_page_bits_common(TARGET_PAGE_BITS_MIN);
10740
#endif
10841
}

0 commit comments

Comments
 (0)