Change to combine restoration prologue with coverage register spill (#1029)

Co-authored-by: Your Name <you@example.com>
This commit is contained in:
WorksButNotTested 2023-02-01 03:41:56 +00:00 committed by GitHub
parent 2a88a776bf
commit d0b4c39acd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -85,33 +85,36 @@ impl CoverageRuntime {
dynasm!(ops dynasm!(ops
; .arch aarch64 ; .arch aarch64
// Store the context // Store the context
; stp x0, x1, [sp, #-0xa0] ; b >start
; stp x16, x17, [sp, -0x90]!
; start:
// Load the previous_pc // Load the previous_pc
; ldr x1, >previous_loc ; ldr x17, >previous_loc
; ldr x1, [x1] ; ldr x17, [x17]
// Caltulate the edge id // Caltulate the edge id
; ldr x0, >loc ; ldr x16, >loc
; eor x0, x1, x0 ; eor x16, x17, x16
// Load the map byte address // Load the map byte address
; ldr x1, >map_addr ; ldr x17, >map_addr
; add x0, x1, x0 ; add x16, x17, x16
// Update the map byte // Update the map byte
; ldrb w1, [x0] ; ldrb w17, [x16]
; add w1, w1, #1 ; add w17, w17, #1
; add x1, x1, x1, lsr #8 ; add x17, x17, x17, lsr #8
; strb w1, [x0] ; strb w17, [x16]
// Update the previous_pc value // Update the previous_pc value
; ldr x0, >loc_shr ; ldr x16, >loc_shr
; ldr x1, >previous_loc ; ldr x17, >previous_loc
; str x0, [x1] ; str x16, [x17]
// Restore the context // Restore the context
; ldp x0, x1, [sp, #-0xa0] ; ldp x16, x17, [sp], #0x90
// Skip the data // Skip the data
; b >end ; b >end
@ -184,6 +187,24 @@ impl CoverageRuntime {
pub fn emit_coverage_mapping(&mut self, address: u64, output: &StalkerOutput) { pub fn emit_coverage_mapping(&mut self, address: u64, output: &StalkerOutput) {
let h64 = xxh3_rrmxmx_mixer(address); let h64 = xxh3_rrmxmx_mixer(address);
let writer = output.writer(); let writer = output.writer();
// Since the AARCH64 instruction set requires that a register be used if
// performing a long branch, if the Stalker engine is unable to use a near
// branch to transition between branches, then it spills some registers
// into the stack beyond the red-zone so that it can use them to perform
// the branch. Accordingly each block is transparently prefixed with an
// instruction to restore these registers. If however a near branch can
// be used, then this instruction is simply skipped and Stalker simply
// branches to the second instruction in the block.
//
// Since we also need to spill some registers in order to update our
// coverage map, in the event of a long branch, we can simply re-use
// these spilt registers. This, however, means we need to retard the
// code writer so that we can overwrite the so-called "restoration
// prologue".
let pc = writer.pc();
writer.reset(pc - 4);
let code = self.generate_inline_code(h64 & (MAP_SIZE as u64 - 1)); let code = self.generate_inline_code(h64 & (MAP_SIZE as u64 - 1));
writer.put_bytes(&code); writer.put_bytes(&code);
} }