This is an archive of the discontinued LLVM Phabricator instance.

[x86] Fix issues with a realigned stack in MSVC compiled applications
ClosedPublic

Authored by aleksandr.urakov on Oct 19 2018, 7:10 AM.

Details

Summary

This patch fixes issues with a stack realignment.

MSVC maintains two frame pointers (ebx and ebp) for a realigned stack - one is used for access to function parameters, while another is used for access to locals. To support this the patch:

  • adds an alternative frame pointer (ebx);
  • considers stack realignment instructions (e.g. and esp, -32);
  • along with CFA (Canonical Frame Address) which point to the position next to the saved return address (or to the first parameter on the stack) introduces AFA (Aligned Frame Address) which points to the position of the stack pointer right after realignment. AFA is used for access to registers saved after the realignment (see the test);

Here is an example of the code with the realignment:

struct __declspec(align(256)) OverAligned {
  char c;
};

void foo(int foo_arg) {
  OverAligned oa_foo = { 1 };
  auto aaa_foo = 1234;
}

void bar(int bar_arg) {
  OverAligned oa_bar = { 2 };
  auto aaa_bar = 5678;
  foo(1111);
}

int main() {
  bar(2222);
  return 0;
}

and here is the bar disassembly:

push    ebx
mov     ebx, esp
sub     esp, 8
and     esp, -100h
add     esp, 4
push    ebp
mov     ebp, [ebx+4]
mov     [esp+4], ebp
mov     ebp, esp
sub     esp, 200h
mov     byte ptr [ebp-200h], 2
mov     dword ptr [ebp-4], 5678
push    1111            ; foo_arg
call    j_?foo@@YAXH@Z  ; foo(int)
add     esp, 4
mov     esp, ebp
pop     ebp
mov     esp, ebx
pop     ebx
retn

Btw, it seems that the code of x86AssemblyInspectionEngine has overgrown. I have some ideas how to refactor this, if you don't mind I can do it in the future?

D53086 also contains some discussion on the topic.

Diff Detail

Repository
rL LLVM

Event Timeline

Ping! Can you look at this, please?

Thanks for the ping aleksandr, I have somehow managed to set up my mail rules so I didn't see this. I'll try to look it over later today. Yes, the x86 instruction profiler has definitely overgrown over the years - the ARM64 instruction profiler is probably a better model, but this code is pretty stable so it hasn't been a priority to do anything to it.

Thanks Aleksandr, this all looks good. I'd like to see a definition of AFA (and we can say "CFA is DWARF's Canonical Frame Address" in the same spot) maybe in UnwindPlan.h, non-Windows people (ok, me) will not know what that is referring to. I was a little worried about and_rsp_pattern_p() but we're not recording the and'ed value. One long standing problem of the UnwindPlan intermediate representation is that it doesn't have any way to represent an alignment involved in the location computation (short of a DWARF expression). This is a problem on AArch32 / armv7 where the NEON registers are saved on higher alignment boundaries than the stack pointer on function call. (if the alignment is less-than or equal-to the stack frame, then there's no align instructions needed in the prologue.) But you're not doing anything like that, no worries.

source/Plugins/Process/Utility/RegisterContextLLDB.h
195 ↗(On Diff #170194)

Comment update, e.g. Get the Frame Address register for a given frame.

source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
399 ↗(On Diff #170194)

thanks for using with at&t syntax in these comments ;)

source/Symbol/UnwindPlan.cpp
202 ↗(On Diff #170194)

What do you think about only printing the AFA= entry if it is != LLDB_INVALID_ADDRESS?

jasonmolenda accepted this revision.Oct 29 2018, 4:11 PM
This revision is now accepted and ready to land.Oct 29 2018, 4:11 PM
aleksandr.urakov marked 2 inline comments as done.Oct 30 2018, 2:53 AM

Thank you! I'll update the patch.

source/Plugins/Process/Utility/RegisterContextLLDB.h
195 ↗(On Diff #170194)

Yes, thanks for pointing to that!

source/Symbol/UnwindPlan.cpp
202 ↗(On Diff #170194)

Yes, sure!

aleksandr.urakov marked 2 inline comments as done.

Update the patch according to comments.

This revision was automatically updated to reflect the committed changes.
This revision was automatically updated to reflect the committed changes.