Page MenuHomePhabricator

[UnwindAssembly/x86] Add support for "lea imm(%ebp), %esp" pattern

Authored by labath on Jun 28 2017, 7:09 AM.



The instruction pattern:
and $-16, %esp
sub $imm, %esp
lea imm(%ebp), %esp

appears when the compiler is realigning the stack (for example in
main(), or almost everywhere with -mstackrealign switch). The "and"
instruction is very difficult to model, but that's not necessary, as
these frames are always %ebp-based (the compiler also needs a way to
restore the original %esp). Therefore the plans we were generating for
these function were almost correct already. The only place we were doing
it wrong were the last instructions of the epilogue (usually just
"ret"), where we had to revert to %esp-based unwinding, as the %ebp had
been popped already.

This was wrong because our "distance of esp from cfa" counter had picked
up the "sub" instruction (and incremented the counter) but it had not
seen that the register was reset by the "lea" instruction.

This patch fixes that shortcoming, and adds a test for handling
functions like this.

I have not been able to tickle the compiler into producing a 64-bit
function with this pattern, but I don't see a reason why it couldn't
produce it, if it chose to, so I add a x86_64 test as well.

Diff Detail


Event Timeline

labath created this revision.Jun 28 2017, 7:09 AM
tberghammer accepted this revision.Jun 28 2017, 8:37 AM

Looks good with one possible question

875–876 ↗(On Diff #104411)

Shouldn't you change the unwind information for the CFA here? For me saying CFA=rbp seems like an incorrect thing to do, but not sure what would be the correct value (Undefined? IsSame?). The impact is if an other register (or a local variable) have a location specified as CFA+off then after this instruction it will point to bogus location.

This revision is now accepted and ready to land.Jun 28 2017, 8:37 AM
labath added inline comments.Jun 28 2017, 8:46 AM
875–876 ↗(On Diff #104411)

I think there has been some misunderstanding, as the your comment makes no sense to me. :)

This code only fires if CFA=rbp+offset, and that remains valid even after this instruction -- lea does not change the value of the rbp register, so any register rule that was valid before this instruction will remain valid after it. This only begins to make a difference after we process the pop %rbp instruction -- then we will update the CFA rule to read CFA=rsp+current_sp_bytes_offset_from_cfa.

tberghammer added inline comments.Jun 28 2017, 9:37 AM
875–876 ↗(On Diff #104411)

You are right, please ignore my comment. I somehow assumed the lea instruction will change the value of rbp as well not just rsp.

This revision was automatically updated to reflect the committed changes.
jasonmolenda edited edge metadata.Jun 29 2017, 8:31 PM

Yeah, looks good. You'll only see this on i386 because the SysV ABI require 4-byte stack alignment. On x86_64 it's 16-byte so the compiler doesn't need to emit the AND instruction to realign it. On darwin we required 16 byte alignment on i386 too so we never saw this problem there.