Bug 1839740 - Hook relrhack in the build system. r=firefox-build-system-reviewers,andi

Disabled by default for now.

Differential Revision: https://phabricator.services.mozilla.com/D187090
This commit is contained in:
Mike Hommey 2023-09-16 19:52:26 +00:00
parent 90c8c29f23
commit 0971a7a2da
5 changed files with 175 additions and 37 deletions

View File

@ -1940,7 +1940,8 @@ def linker_ldflags_tmpl(host_or_target):
linker_ldflags = linker_ldflags_tmpl(target)
add_old_configure_assignment("LINKER_LDFLAGS", linker_ldflags)
add_old_configure_assignment("HOST_LINKER_LDFLAGS", linker_ldflags_tmpl(host))
host_linker_ldflags = linker_ldflags_tmpl(host)
add_old_configure_assignment("HOST_LINKER_LDFLAGS", host_linker_ldflags)
# There's a wrinkle with MinGW: linker configuration is not enabled, so

View File

@ -209,6 +209,12 @@ netwerk/test/http3server/target: security/target
endif
endif
ifdef RELRHACK
# When building with RELR-based ELF hack, we need to build the relevant parts
# before any target.
$(filter %/target,$(compile_targets)): build/unix/elfhack/host build/unix/elfhack/inject/target-objects
endif
ifdef MOZ_USING_WASM_SANDBOXING
security/rlbox/pre-compile: config/external/wasm2c_sandbox_compiler/host
dom/media/ogg/target-objects extensions/spellcheck/hunspell/glue/target-objects gfx/thebes/target-objects parser/expat/target-objects parser/htmlparser/target-objects gfx/ots/src/target-objects dom/media/target-objects dom/media/mediasink/target-objects: security/rlbox/pre-compile

View File

@ -523,7 +523,7 @@ endif
$(SHARED_LIBRARY): $(OBJS) $(call resfile,$(SHARED_LIBRARY)) $(STATIC_LIBS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
$(REPORT_BUILD)
$(RM) $@
$(MKSHLIB) $($@_OBJS) $(filter %.res,$^) $(LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(OS_LIBS)
$(MKSHLIB) $($@_OBJS) $(filter %.res,$^) $(RELRHACK_LDFLAGS) $(LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(OS_LIBS)
$(call py_action,check_binary,$@)
ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))

View File

@ -160,8 +160,8 @@ class TestToolkitMozConfigure(BaseConfigureTest):
return (
sandbox._value_for(sandbox["select_linker"]).KIND,
sandbox._value_for(sandbox["pack_relative_relocs"]),
sandbox._value_for(sandbox["use_elf_hack"]),
sandbox._value_for(sandbox["pack_relative_relocs_flags"]),
sandbox._value_for(sandbox["which_elf_hack"]),
)
PACK = ["-Wl,-z,pack-relative-relocs"]
@ -181,17 +181,36 @@ class TestToolkitMozConfigure(BaseConfigureTest):
):
self.assertEqual(get_values(mockcc, readelf), ("lld", None, None))
self.assertEqual(
get_values(mockcc, readelf, ["--enable-release"]), ("bfd", None, True)
get_values(mockcc, readelf, ["--enable-release"]),
("bfd", None, "legacy"),
)
# LLD is picked by default and enabling elfhack fails because of that.
with self.assertRaises(SystemExit):
get_values(mockcc, readelf, ["--enable-elf-hack"])
with self.assertRaises(SystemExit):
get_values(mockcc, readelf, ["--enable-elf-hack=legacy"])
if readelf.with_relr:
# Explicitly enabling relrhack works because pack-relative-relocs are supported.
self.assertEqual(
get_values(mockcc, readelf, ["--enable-elf-hack=relr"]),
("lld", None, "relr"),
)
else:
# relrhack doesn't work without pack-relative-relocs support.
with self.assertRaises(SystemExit):
get_values(mockcc, readelf, ["--enable-elf-hack=relr"])
# If we force to use BFD ld, it works.
self.assertEqual(
get_values(
mockcc, readelf, ["--enable-elf-hack", "--enable-linker=bfd"]
),
("bfd", None, True),
("bfd", None, "legacy"),
)
self.assertEqual(
get_values(
mockcc, readelf, ["--enable-elf-hack=legacy", "--enable-linker=bfd"]
),
("bfd", None, "legacy"),
)
# Linker supports pack-relative-relocs, and glibc too. We use pack-relative-relocs
@ -205,10 +224,23 @@ class TestToolkitMozConfigure(BaseConfigureTest):
# LLD is picked by default and enabling elfhack fails because of that.
with self.assertRaises(SystemExit):
get_values(mockcc, readelf, ["--enable-elf-hack"])
with self.assertRaises(SystemExit):
get_values(mockcc, readelf, ["--enable-elf-hack=legacy"])
# If we force to use BFD ld, it works.
self.assertEqual(
get_values(mockcc, readelf, ["--enable-elf-hack", "--enable-linker=bfd"]),
("bfd", None, True),
("bfd", None, "legacy"),
)
self.assertEqual(
get_values(
mockcc, readelf, ["--enable-elf-hack=legacy", "--enable-linker=bfd"]
),
("bfd", None, "legacy"),
)
# Explicitly enabling relrhack works because pack-relative-relocs are supported.
self.assertEqual(
get_values(mockcc, readelf, ["--enable-elf-hack=relr"]),
("lld", None, "relr"),
)

View File

@ -1497,36 +1497,38 @@ with only_when("--enable-compile-environment"):
and target.cpu in ("arm", "aarch64", "x86", "x86_64")
)
@depends("--enable-release", enable_linker)
def default_elfhack(release, linker):
# Disable elfhack when explicitly building with --enable-linker=lld
if linker and linker.origin != "default" and linker[0] in ("lld", "mold"):
return False
return bool(release)
option(
"--disable-elf-hack",
default=default_elfhack,
nargs="?",
choices=("legacy", "relr"),
help="{Enable|Disable} elf hacks",
when=has_elfhack,
)
@depends("--enable-elf-hack", when=has_elfhack)
def may_enable_legacy_elfhack(enable):
if enable and enable != ("relr",):
return enable
@depends("--enable-elf-hack", when=has_elfhack)
def may_enable_relrhack(enable):
# For now, only enable relrhack when explicitly given with
# --enable-elf-hack=relr
if enable == ("relr",):
return enable
@depends(
have_arc4random,
android_version,
depends("--enable-elf-hack", when=has_elfhack)(lambda x: x),
when=target_has_linux_kernel,
)
def may_use_pack_relative_relocs(have_arc4random, android_version, elfhack):
def may_use_pack_relative_relocs(have_arc4random, android_version):
# Packed relative relocations are only supported on Android since
# version 11 (API 30), and in glibc since version 2.36.
# glibc 2.36 also added the arc4random function, which is our proxy
# to detect this (or newer) version being used.
# When targetting those newer versions, we allow ourselves to use
# packed relative relocations rather than elfhack. We still prefer
# elfhack when explicitly enabled.
if elfhack and elfhack.origin != "default":
return False
# packed relative relocations rather than elfhack.
if android_version:
return android_version >= 30
return have_arc4random
@ -1536,14 +1538,14 @@ with only_when("--enable-compile-environment"):
extra_toolchain_flags,
linker_ldflags,
readelf,
when=may_use_pack_relative_relocs,
when=may_use_pack_relative_relocs | may_enable_relrhack,
)
@checking("for -z pack-relative-relocs option to ld", bool)
@imports(_from="__builtin__", _import="FileNotFoundError")
@imports("os")
@imports(_from="tempfile", _import="mkstemp")
@imports("textwrap")
def pack_relative_relocs(
def has_pack_relative_relocs(
c_compiler,
extra_toolchain_flags,
linker_ldflags,
@ -1603,28 +1605,125 @@ with only_when("--enable-compile-environment"):
except FileNotFoundError:
pass
add_old_configure_assignment("PACK_REL_RELOC_FLAGS", pack_relative_relocs)
@depends(
has_pack_relative_relocs,
may_enable_legacy_elfhack,
may_enable_relrhack,
may_use_pack_relative_relocs,
when=has_pack_relative_relocs,
)
def pack_relative_relocs_flags(
flags,
may_enable_legacy_elfhack,
may_enable_relrhack,
may_use_pack_relative_relocs,
):
# When relrhack is enabled, we don't pass the flag to the linker because
# relrhack will take care of it.
if may_enable_relrhack and may_enable_relrhack.origin != "default":
return None
# if elfhack is explicitly enabled instead of relrhack, we prioritize it
# over packed relative relocs.
if may_enable_legacy_elfhack and may_enable_legacy_elfhack.origin != "default":
return None
if may_use_pack_relative_relocs:
return flags
add_old_configure_assignment("PACK_REL_RELOC_FLAGS", pack_relative_relocs_flags)
@depends(
select_linker,
pack_relative_relocs,
"--enable-elf-hack",
pack_relative_relocs_flags,
has_pack_relative_relocs,
may_enable_legacy_elfhack,
may_enable_relrhack,
when=has_elfhack,
)
def use_elf_hack(linker, pack_relative_relocs, elfhack):
if elfhack:
# If elfhack was not manually enabled and packed relative relocations
# can be used, then don't enable elfhack even if it would normally have.
if elfhack.origin == "default" and pack_relative_relocs:
return
if linker and linker.KIND == "lld":
def which_elf_hack(
linker,
pack_relative_relocs_flags,
has_pack_relative_relocs,
may_enable_legacy_elfhack,
may_enable_relrhack,
):
if pack_relative_relocs_flags:
return
if may_enable_relrhack:
if has_pack_relative_relocs:
return "relr"
elif (
may_enable_relrhack.origin != "default"
and not may_enable_legacy_elfhack
):
die(
"Cannot enable elfhack with lld."
" Use --enable-linker=bfd, --enable-linker=gold, or --disable-elf-hack"
"Cannot enable relrhack without linker support for -z pack-relative-relocs"
)
return True
if may_enable_legacy_elfhack:
if linker and linker.KIND in ("lld", "mold"):
if may_enable_legacy_elfhack.origin != "default":
die(
f"Cannot enable elfhack with {linker.KIND}."
" Use --enable-linker=bfd, --enable-linker=gold, or --disable-elf-hack"
)
else:
return "legacy"
set_config("USE_ELF_HACK", use_elf_hack)
set_config(
"USE_ELF_HACK", True, when=depends(which_elf_hack)(lambda x: x == "legacy")
)
use_relrhack = depends(which_elf_hack)(lambda x: x == "relr")
set_config("RELRHACK", True, when=use_relrhack)
@depends(c_compiler, linker_ldflags, when=use_relrhack)
def relrhack_real_linker(c_compiler, linker_ldflags):
ld = "ld"
for flag in linker_ldflags:
if flag.startswith("-fuse-ld="):
ld = "ld." + flag[len("-fuse-ld=") :]
ld = check_cmd_output(
c_compiler.compiler, f"--print-prog-name={ld}", *c_compiler.flags
)
return ld.rstrip()
@depends(relrhack_real_linker, when=use_relrhack)
def relrhack_linker(ld):
return os.path.basename(ld)
set_config("RELRHACK_LINKER", relrhack_linker)
std_filesystem = host_cxx_compiler.try_run(
header="#include <filesystem>",
body='auto foo = std::filesystem::absolute("");',
flags=host_linker_ldflags,
when=use_relrhack,
onerror=lambda: None,
)
stdcxxfs = host_cxx_compiler.try_run(
header="#include <filesystem>",
body='auto foo = std::filesystem::absolute("");',
flags=depends(host_linker_ldflags)(
lambda flags: (flags or []) + ["-lstdc++fs"]
),
check_msg="whether std::filesystem requires -lstdc++fs",
when=use_relrhack & depends(std_filesystem)(lambda x: not x),
onerror=lambda: None,
)
set_config("RELRHACK_LIBS", ["stdc++fs"], when=stdcxxfs)
@depends(build_environment, relrhack_real_linker, when=use_relrhack)
def relrhack_ldflags(build_env, ld):
flags = [
"-B",
os.path.join(build_env.topobjdir, "build", "unix", "elfhack"),
]
if os.path.basename(ld) != ld:
flags.append(f"-Wl,--real-linker,{ld}")
return flags
set_config("RELRHACK_LDFLAGS", relrhack_ldflags)
@depends(build_environment)