Skip to content

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
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

nebulark
Copy link
Contributor

@nebulark nebulark commented Dec 7, 2024

This PR adds an unstable hotpatch flag, which ensures the first instruction of a function being two bytes long, otherwise inserting a nop. This is needed for code hotpatching (such as Live++ or Recode) tools to work, so they can provide very quick iteration cycles for development.

This uses a LLVM feature that is only implemented on x86/x86_64. On aarch64 this is not needed as there are no 1 byte instructions.

Hotpatching also requires a linker argument (e.g. functionpadmin on link.exe/lld), which ensures a minimum padding between functions. This can not implemented in rustc as this is linker specific. However, we do mark functions to be hotpatchable when using the hotpatch flag, as the link.exe/lld need it for their functionpadmin flag to work.

Typical usage with cargo for hotpatching the would be "RUSTFLAGS=-Z hotpatch -C link-arg=-functionpadmin". This currently only works on Windows due to linker support. But there should be nothing blocking other linkers to implement a flag similar to functionpadmin.

There is a similar flag "patchable-function-entry". The main difference is that hotpatch + functionpadmin, should leave functions that are already hotpatchable, an extremely common case, untouched. This reduces bloat, but requires linker support.

This is a first step to establish a proof of concept for rust-lang/compiler-team#745. The follow up step would be to add support for lld (or another linker) so this also works on linux.

@rustbot
Copy link
Collaborator

rustbot commented Dec 7, 2024

r? @jieyouxu

rustbot has assigned @jieyouxu.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added A-run-make Area: port run-make Makefiles to rmake.rs S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 7, 2024
@rustbot
Copy link
Collaborator

rustbot commented Dec 7, 2024

These commits modify compiler targets.
(See the Target Tier Policy.)

The run-make-support library was changed

cc @jieyouxu

This PR modifies tests/run-make/. If this PR is trying to port a Makefile
run-make test to use rmake.rs, please update the
run-make port tracking issue
so we can track our progress. You can either modify the tracking issue
directly, or you can comment on the tracking issue and link this PR.

cc @jieyouxu

@jieyouxu
Copy link
Member

jieyouxu commented Dec 7, 2024

This is waiting on the MCP rust-lang/compiler-team#745, right?

@jieyouxu jieyouxu added S-waiting-on-MCP Status: PR has a compiler MCP and is waiting for the compiler MCP to complete. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 7, 2024
@nebulark
Copy link
Contributor Author

nebulark commented Dec 7, 2024

The MCP is stuck due to missing linux support, due to missing linker support.

Current plan to get the MCP approved would be to:

  1. Add this as an unstable flag, which as far as I was told does need need an MCP. So I am just doing it with this PR.
  2. Add support to some Linux/ELF linker (probably LLD as the Window/COFF version already supports it)

With this there would be a proof of concept that works on linux and would unstuck the MCP.
Sorry if this caused any confusion.

@jieyouxu
Copy link
Member

jieyouxu commented Dec 7, 2024

Ah okay, thanks for the clarifications!

@nebulark
Copy link
Contributor Author

nebulark commented Dec 7, 2024

So ... I think we should remove the "S-waiting-on-MCP" tag then and put it back to waiting on review?
Or is there action needed from my side?

@jieyouxu
Copy link
Member

jieyouxu commented Dec 7, 2024

This is waiting on the MCP because the MCP needs a second from a compiler team member. There's no action needed on your side.

@nebulark
Copy link
Contributor Author

nebulark commented Dec 7, 2024

As far as I understood getting a second will only happen when I have a poc that works on linux.
I have been told adding an unstable flag should not require an MCP. Only stabilizing that flag does.
So I am trying to add the unstable flag now.
Please correct me if I understood anything wrong.

Again sorry for the confusion and thank you for your time!

@jieyouxu
Copy link
Member

jieyouxu commented Dec 7, 2024

Let me go ask other compiler people about this and then get back to you.

@jieyouxu jieyouxu added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-MCP Status: PR has a compiler MCP and is waiting for the compiler MCP to complete. labels Dec 7, 2024
@nikic
Copy link
Contributor

nikic commented Dec 7, 2024

As far as I understood getting a second will only happen when I have a poc that works on linux. I have been told adding an unstable flag should not require an MCP. Only stabilizing that flag does. So I am trying to add the unstable flag now. Please correct me if I understood anything wrong.

I think there's been a misunderstanding here. That was my opinion on the MCP, not on whether it needs an MCP. Unstable flags usually do go through an MCP.

@jieyouxu jieyouxu added S-waiting-on-MCP Status: PR has a compiler MCP and is waiting for the compiler MCP to complete. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 8, 2024
@bors
Copy link
Collaborator

bors commented Jun 19, 2025

☔ The latest upstream changes (presumably #142689) made this pull request unmergeable. Please resolve the merge conflicts.

@bors bors added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jun 19, 2025
@@ -373,6 +373,15 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
to_add.push(llvm::CreateAttrString(cx.llcx, "use-sample-profile"));
}

// patchable-function is only implemented on x86 on LLVM
if cx.sess().opts.unstable_opts.hotpatch && cx.sess().target.is_x86() {
Copy link
Contributor

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?

@rustbot rustbot added the A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. label Jul 16, 2025
@rust-log-analyzer
Copy link
Collaborator

The job aarch64-gnu-llvm-19-1 failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
test [run-make] tests/run-make/foreign-exceptions ... ok
test [run-make] tests/run-make/foreign-rust-exceptions ... ok
test [run-make] tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu ... ignored, only executed when the target is x86_64-unknown-linux-gnu
test [run-make] tests/run-make/glibc-staticlib-args ... ok
test [run-make] tests/run-make/hotpatch ... FAILED
test [run-make] tests/run-make/hotpatch_pdb ... ok
test [run-make] tests/run-make/ice-dep-cannot-find-dep ... ignored, only executed when the architecture is x86_64
test [run-make] tests/run-make/hotpatch-unaffected ... ok
test [run-make] tests/run-make/import-macro-verbatim ... ignored, only executed when the operating system is windows (other platforms do not have Windows verbatim paths)
test [run-make] tests/run-make/ice-static-mir ... ok
test [run-make] tests/run-make/inaccessible-temp-dir ... ok
test [run-make] tests/run-make/include-bytes-deps ... ok
test [run-make] tests/run-make/include-all-symbols-linking ... ok
---
---- [run-make] tests/run-make/hotpatch stdout ----

error: rmake recipe failed to complete
status: exit status: 1
command: cd "/checkout/obj/build/aarch64-unknown-linux-gnu/test/run-make/hotpatch/rmake_out" && env -u RUSTFLAGS AR="ar" BUILD_ROOT="/checkout/obj/build/aarch64-unknown-linux-gnu" CARGO="/checkout/obj/build/aarch64-unknown-linux-gnu/stage1-tools-bin/cargo" CC="cc" CC_DEFAULT_FLAGS="-ffunction-sections -fdata-sections -fPIC" CXX="c++" CXX_DEFAULT_FLAGS="-ffunction-sections -fdata-sections -fPIC" HOST_RUSTC_DYLIB_PATH="/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/lib" LD_LIBRARY_PATH="/checkout/obj/build/aarch64-unknown-linux-gnu/bootstrap-tools/aarch64-unknown-linux-gnu/release/deps:/checkout/obj/build/aarch64-unknown-linux-gnu/stage0/lib/rustlib/aarch64-unknown-linux-gnu/lib" LD_LIB_PATH_ENVVAR="LD_LIBRARY_PATH" LLVM_BIN_DIR="/usr/lib/llvm-19/bin" LLVM_COMPONENTS="aarch64 aarch64asmparser aarch64codegen aarch64desc aarch64disassembler aarch64info aarch64utils aggressiveinstcombine all all-targets amdgpu amdgpuasmparser amdgpucodegen amdgpudesc amdgpudisassembler amdgpuinfo amdgputargetmca amdgpuutils analysis arm armasmparser armcodegen armdesc armdisassembler arminfo armutils asmparser asmprinter avr avrasmparser avrcodegen avrdesc avrdisassembler avrinfo binaryformat bitreader bitstreamreader bitwriter bpf bpfasmparser bpfcodegen bpfdesc bpfdisassembler bpfinfo cfguard codegen codegendata codegentypes core coroutines coverage debuginfobtf debuginfocodeview debuginfodwarf debuginfogsym debuginfologicalview debuginfomsf debuginfopdb demangle dlltooldriver dwarflinker dwarflinkerclassic dwarflinkerparallel dwp engine executionengine extensions filecheck frontenddriver frontendhlsl frontendoffloading frontendopenacc frontendopenmp fuzzercli fuzzmutate globalisel hexagon hexagonasmparser hexagoncodegen hexagondesc hexagondisassembler hexagoninfo hipstdpar instcombine instrumentation interfacestub interpreter ipo irprinter irreader jitlink lanai lanaiasmparser lanaicodegen lanaidesc lanaidisassembler lanaiinfo libdriver lineeditor linker loongarch loongarchasmparser loongarchcodegen loongarchdesc loongarchdisassembler loongarchinfo lto m68k m68kasmparser m68kcodegen m68kdesc m68kdisassembler m68kinfo mc mca mcdisassembler mcjit mcparser mips mipsasmparser mipscodegen mipsdesc mipsdisassembler mipsinfo mirparser msp430 msp430asmparser msp430codegen msp430desc msp430disassembler msp430info native nativecodegen nvptx nvptxcodegen nvptxdesc nvptxinfo objcarcopts objcopy object objectyaml option orcdebugging orcjit orcshared orctargetprocess passes perfjitevents powerpc powerpcasmparser powerpccodegen powerpcdesc powerpcdisassembler powerpcinfo profiledata remarks riscv riscvasmparser riscvcodegen riscvdesc riscvdisassembler riscvinfo riscvtargetmca runtimedyld sandboxir scalaropts selectiondag sparc sparcasmparser sparccodegen sparcdesc sparcdisassembler sparcinfo support symbolize systemz systemzasmparser systemzcodegen systemzdesc systemzdisassembler systemzinfo tablegen target targetparser textapi textapibinaryreader transformutils ve veasmparser vecodegen vectorize vedesc vedisassembler veinfo webassembly webassemblyasmparser webassemblycodegen webassemblydesc webassemblydisassembler webassemblyinfo webassemblyutils windowsdriver windowsmanifest x86 x86asmparser x86codegen x86desc x86disassembler x86info x86targetmca xcore xcorecodegen xcoredesc xcoredisassembler xcoreinfo xray xtensa xtensaasmparser xtensacodegen xtensadesc xtensadisassembler xtensainfo" LLVM_FILECHECK="/usr/lib/llvm-19/bin/FileCheck" NODE="/usr/bin/node" PYTHON="/usr/bin/python3" RUSTC="/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" RUSTDOC="/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustdoc" SOURCE_ROOT="/checkout" TARGET="aarch64-unknown-linux-gnu" TARGET_EXE_DYLIB_PATH="/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/lib/rustlib/aarch64-unknown-linux-gnu/lib" __RUSTC_DEBUG_ASSERTIONS_ENABLED="1" __STD_DEBUG_ASSERTIONS_ENABLED="1" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/run-make/hotpatch/rmake"
stdout: none
--- stderr -------------------------------
command failed at line 39
Command { cmd: "/usr/lib/llvm-19/bin/FileCheck" "lib.rs" "--check-prefix" "HOTPATCH", stdin_buf: Some([10, 108, 105, 98, 104, 111, 116, 112, 97, 116, 99, 104, 46, 114, 108, 105, 98, 40, 108, 105, 98, 46, 114, 109, 101, 116, 97, 41, 58, 9, 102, 105, 108, 101, 32, 102, 111, 114, 109, 97, 116, 32, 101, 108, 102, 54, 52, 45, 108, 105, 116, 116, 108, 101, 97, 97, 114, 99, 104, 54, 52, 10, 10, 108, 105, 98, 104, 111, 116, 112, 97, 116, 99, 104, 46, 114, 108, 105, 98, 40, 104, 111, 116, 112, 97, 116, 99, 104, 46, 104, 111, 116, 112, 97, 116, 99, 104, 46, 54, 97, 57, 48, 101, 102, 98, 49, 54, 97, 50, 101, 100, 97, 54, 52, 45, 99, 103, 117, 46, 48, 46, 114, 99, 103, 117, 46, 111, 41, 58, 9, 102, 105, 108, 101, 32, 102, 111, 114, 109, 97, 116, 32, 101, 108, 102, 54, 52, 45, 108, 105, 116, 116, 108, 101, 97, 97, 114, 99, 104, 54, 52, 10, 10, 68, 105, 115, 97, 115, 115, 101, 109, 98, 108, 121, 32, 111, 102, 32, 115, 101, 99, 116, 105, 111, 110, 32, 46, 116, 101, 120, 116, 46, 101, 109, 112, 116, 121, 95, 102, 110, 58, 10, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 60, 101, 109, 112, 116, 121, 95, 102, 110, 62, 58, 10, 32, 32, 32, 32, 32, 32, 32, 48, 58, 32, 100, 54, 53, 102, 48, 51, 99, 48, 32, 32, 32, 32, 32, 9, 114, 101, 116, 10]), stdin: None, stdout: None, stderr: None, drop_bomb: DropBomb { command: "/usr/lib/llvm-19/bin/FileCheck", defused: true, armed_location: Location { file: "/checkout/tests/run-make/hotpatch/rmake.rs", line: 35, column: 13 } }, already_executed: true }
output status: `exit status: 1`
=== STDOUT ===



=== STDERR ===
lib.rs:23:19: error: HOTPATCH-NEXT: expected string not found in input
// HOTPATCH-NEXT: 0: {{[0-9a-f][0-9a-f]}} {{[0-9a-f][0-9a-f]}} {{.*}}
                  ^
<stdin>:8:29: note: scanning from here
0000000000000000 <empty_fn>:
                            ^
<stdin>:9:2: note: possible intended match here
 0: d65f03c0 ret
 ^

Input file: <stdin>
Check file: lib.rs

-dump-input=help explains the following input dump.

Input was:
<<<<<<
           1:  
           2: libhotpatch.rlib(lib.rmeta): file format elf64-littleaarch64 
           3:  
           4: libhotpatch.rlib(hotpatch.hotpatch.6a90efb16a2eda64-cgu.0.rcgu.o): file format elf64-littleaarch64 
           5:  
           6: Disassembly of section .text.empty_fn: 
           7:  
           8: 0000000000000000 <empty_fn>: 
next:23'0                                 X error: no match found
           9:  0: d65f03c0 ret 
next:23'0     ~~~~~~~~~~~~~~~~~
next:23'1      ?                possible intended match
>>>>>>
------------------------------------------



Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. A-run-make Area: port run-make Makefiles to rmake.rs S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. S-waiting-on-MCP Status: PR has a compiler MCP and is waiting for the compiler MCP to complete. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants