-
Notifications
You must be signed in to change notification settings - Fork 13.5k
Add unstable hotpatch flag to rustc #134004
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
nebulark
wants to merge
2
commits into
rust-lang:master
Choose a base branch
from
nebulark:hotpatch_flag
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// check if functions get the attribute, so that LLVM ensures they are hotpatchable | ||
// the attribute is only implemented for x86, aarch64 does not require it | ||
|
||
//@ revisions: x32 x64 | ||
//@[x32] only-x86 | ||
//@[x64] only-x86_64 | ||
//@ compile-flags: -Z hotpatch | ||
|
||
#![crate_type = "lib"] | ||
|
||
#[no_mangle] | ||
pub fn foo() {} | ||
|
||
// CHECK-LABEL: @foo() unnamed_addr #0 | ||
// CHECK: attributes #0 = { {{.*}} "patchable-function"="prologue-short-redirect" {{.*}}} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// to be able to hotpatch a function there are two requirements: | ||
// 1. the first instruction of a functin must be at least two bytes long | ||
// 2. there must not be a jump to the first instruction | ||
|
||
// the functions in this file already fulfill the conditions so hotpatch should not affect them | ||
|
||
// -------------------------------------------------------------------------------------------- | ||
|
||
#[no_mangle] | ||
#[inline(never)] | ||
pub fn return_42() -> i32 { | ||
42 | ||
} | ||
|
||
// -------------------------------------------------------------------------------------------- | ||
// This tailcall does not jump to the first instruction so hotpatch should leave it unaffected | ||
|
||
#[no_mangle] | ||
pub fn tailcall(a: i32) -> i32 { | ||
if a > 10000 { | ||
return a; | ||
} | ||
|
||
if a % 2 == 0 { tailcall(a / 2) } else { tailcall(a * 3 + 1) } | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// Check if hotpatch leaves the functions that are already hotpatchable untouched | ||
|
||
use run_make_support::{assertion_helpers, llvm, rustc}; | ||
|
||
fn main() { | ||
// hotpatch is only implemented for X86 and aarch64 | ||
#[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))] | ||
{ | ||
fn base_rustc() -> rustc::Rustc { | ||
let mut rustc = rustc(); | ||
rustc.input("lib.rs").crate_type("lib").opt_level("3"); | ||
rustc | ||
} | ||
|
||
fn dump_lib(libname: &str) -> String { | ||
llvm::llvm_objdump() | ||
.arg("--disassemble-symbols=return_42,tailcall") | ||
.input(libname) | ||
.run() | ||
.stdout_utf8() | ||
} | ||
|
||
base_rustc().crate_name("regular").run(); | ||
let regular_dump = dump_lib("libregular.rlib"); | ||
|
||
base_rustc().crate_name("hotpatch").arg("-Zhotpatch").run(); | ||
let hotpatch_dump = dump_lib("libhotpatch.rlib"); | ||
|
||
{ | ||
let mut lines_regular = regular_dump.lines(); | ||
let mut lines_hotpatch = hotpatch_dump.lines(); | ||
|
||
loop { | ||
match (lines_regular.next(), lines_hotpatch.next()) { | ||
(None, None) => break, | ||
(Some(r), Some(h)) => { | ||
if r.contains("libregular.rlib") { | ||
assertion_helpers::assert_contains(h, "libhotpatch.rlib") | ||
} else { | ||
assertion_helpers::assert_equals(&r, &h) | ||
} | ||
} | ||
_ => panic!("expected files to have equal number of lines"), | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// to be able to hotpatch a function there are two requirements: | ||
// 1) the first instruction of a functin must be at least two bytes long | ||
// 2) there must not be a jump to the first instruction | ||
|
||
// The LLVM attribute we use '"patchable-function", "prologue-short-redirect"' only ensures 1) | ||
// However in practice 2) rarely matters. Its rare that it occurs and the problems it caused can be | ||
// avoided by the hotpatch tool. | ||
// In this test we check if 1) is ensured by inserted nops as needed | ||
|
||
// ---------------------------------------------------------------------------------------------- | ||
|
||
// empty_fn just returns. Note that 'ret' is a single byte instruction, but hotpatch requires | ||
// a two or more byte instructions to be at the start of the functions. | ||
// Preferably we would also tests a different single byte instruction, | ||
// but I was not able to find an example with another one byte intstruction. | ||
|
||
// check that if the first instruction is just a single byte, so our test is valid | ||
// CHECK-LABEL: <empty_fn>: | ||
// CHECK-NOT: 0: {{[0-9a-f][0-9a-f]}} {{[0-9a-f][0-9a-f]}} {{.*}} | ||
|
||
// check that the first instruction is at least 2 bytes long | ||
// HOTPATCH-LABEL: <empty_fn>: | ||
// HOTPATCH-NEXT: 0: {{[0-9a-f][0-9a-f]}} {{[0-9a-f][0-9a-f]}} {{.*}} | ||
|
||
#[no_mangle] | ||
#[inline(never)] | ||
pub fn empty_fn() {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// Check if hotpatch makes the functions hotpachable that were not | ||
// More details in lib.rs | ||
|
||
use run_make_support::{llvm, rustc}; | ||
|
||
fn main() { | ||
// hotpatch is only implemented for x86 and aarch64, but for aarch64 functions | ||
// are always hotpatchable so we don't need to check it | ||
#[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))] | ||
{ | ||
fn base_rustc() -> rustc::Rustc { | ||
let mut rustc = rustc(); | ||
rustc.input("lib.rs").crate_type("lib").opt_level("3"); | ||
rustc | ||
} | ||
|
||
fn dump_lib(libname: &str) -> String { | ||
llvm::llvm_objdump() | ||
.arg("--disassemble-symbols=empty_fn") | ||
.input(libname) | ||
.run() | ||
.stdout_utf8() | ||
} | ||
|
||
{ | ||
base_rustc().crate_name("regular").run(); | ||
let regular_dump = dump_lib("libregular.rlib"); | ||
llvm::llvm_filecheck().patterns("lib.rs").stdin_buf(regular_dump).run(); | ||
} | ||
|
||
{ | ||
base_rustc().crate_name("hotpatch").arg("-Zhotpatch").run(); | ||
let hotpatch_dump = dump_lib("libhotpatch.rlib"); | ||
|
||
llvm::llvm_filecheck() | ||
.patterns("lib.rs") | ||
.check_prefix("HOTPATCH") | ||
.stdin_buf(hotpatch_dump) | ||
.run(); | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// CHECK: S_OBJNAME{{.*}}hotpatch_pdb{{.*}}.o | ||
// CHECK: S_COMPILE3 | ||
// CHECK-NOT: S_ | ||
// CHECK: flags = {{.*}}hot patchable | ||
|
||
pub fn main() {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Check if hotpatch flag is present in the Codeview. | ||
// While this is not strictly neccessary for functionpadmin to work, the currently linker | ||
// would ignore functionpadmin if this is not pressent | ||
|
||
use run_make_support::{llvm, rustc}; | ||
|
||
fn main() { | ||
// PDBs are windows only and hotpatch is only implemented for x86 and aarch64 | ||
#[cfg(all( | ||
target_os = "windows", | ||
any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64") | ||
))] | ||
{ | ||
let output = rustc() | ||
.input("main.rs") | ||
.arg("-g") | ||
.arg("-Zhotpatch") | ||
.crate_name("hotpatch_pdb") | ||
.crate_type("bin") | ||
.run(); | ||
|
||
let pdbutil_output = llvm::llvm_pdbutil() | ||
.arg("dump") | ||
.arg("-symbols") | ||
.input("hotpatch_pdb.pdb") | ||
.run() | ||
.stdout_utf8(); | ||
|
||
llvm::llvm_filecheck().patterns("main.rs").stdin_buf(&pdbutil_output).run(); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this warn/error if both conditions aren't true?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, yeah I think we could add a check somewhere else to error/warn when hotpatch is used to compiler for platforms other than x86 or aarch64. For the latter we don't need to add this attribute as it already is inherently hotpatchable.