Saving XMM register state lazarus / 62-General ---------------------------------------------------------------------- Madoc · 2023-11-24 22:22 Hello, just started migrating a very large Delphi project to FPC/Lazarus (because I found out FPC has vectorcall!) and I'm running into some problems with saving XMM register state. Previously I would do this:   movdqa   [rsp-24], xmm6  // When entering the function   movdqa   xmm6, [rsp-24]  // When exiting the function But with FPC this causes an access violation. I guess FPC handles the stack differently from Delphi and this is why I'm running into problems (I do have  {$MODE Delphi} and {$asmmode intel} set). Any idea what the differences in the stack are and how I can fix this? Also, I'm assuming I need to preserve the state of the same registers as I would in Delphi or MSVC? (xmm6-15, RDI, RSI, RBX, RBP, RSP, R12, R13, R14, R15)? Thanks! ---------------------------------------------------------------------- Madoc · 2023-11-24 22:30 Another somewhat related question. Can I somehow declare global constants and variables that are 16 byte aligned? ---------------------------------------------------------------------- marcov · 2023-11-24 23:00 Like in Delphi you shouldn't directly save but let the compiler do it. Your example is somewhat weird since it addresses the stack at -24 which is not a multiple of 16 byte. Of course that can still be ok, but better be sure. Unfortunately, the Delphi and FPC ways to dealing with this are different. Delphi has the .pushnv pseudo instructions, and FPC uses an ASM block with a register list to save in the END[ block. For a source that does both see http://www.stack.nl/~marcov/rot8x8.txt ---------------------------------------------------------------------- jamie · 2023-11-24 23:48 the standard stuff don't work for you? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Function Test(A:Integer):Integer; Assembler; Var{$ASMMODE INTEL}   I:Integer; ASm   movdqa I, xmm6;   movdqa xmm6, I; end;                   Put a break point on that and see what you have. A Stack is generated so you can store your variable as you can see there. ---------------------------------------------------------------------- runewalsh · 2023-11-25 00:04 First, you can add “assembler; nostackframe” procedure directives so your stack pointer will be at 16N + 8. By subtracting another 16N + 8, you will have aligned pointer again. This is because the stack is aligned (by convention) before the call, so pushing the return address itself misaligns it by 8. Without nostackframe, there is also an implicit push rbp so your stack is aligned right away and subtracting anything but 16N misaligns it (at least without local variables). Second, you should not access [rsp − N]. First subtract N, then access non-negative offsets. At least on Windows, all memory below rsp is volatile and can change at any time. Quote from: Madoc on November 24, 2023, 11:30:31 pmAnother somewhat related question. Can I somehow declare global constants and variables that are 16 byte aligned? Either try https://www.freepascal.org/daily/doc/prog/progsu9.html but beware of bugs, or, better, use align modifier for records. ---------------------------------------------------------------------- Madoc · 2023-11-25 07:19 Quote from: runewalsh on November 25, 2023, 01:04:01 amFirst, you can add “assembler; nostackframe” procedure directives so your stack pointer will be at 16N + 8. By subtracting another 16N + 8, you will have aligned pointer again. Thanks, adding nostackframe seems to have solved my problem, and indeed 16+8 = 24. Delphi generally does this automatically for leaf functions without local variables. Quote from: runewalsh on November 25, 2023, 01:04:01 amSecond, you should not access [rsp − N]. First subtract N, then access non- negative offsets. At least on Windows, all memory below rsp is volatile and can change at any time. Hmm... My understanding is that this is perfectly safe in practice for leaf functions, microsoft claims it's not and the red zone is only 16 bytes, but this is based on hypotheticals and as long as you don't go too far and you know what your code is doing you shouldn't actually run into any issues. Anyway, thanks for the help. Now to figure out why the debugger keeps giving me range and overflow check errors despite these being disabled... ---------------------------------------------------------------------- Jonas Maebe · 2023-11-25 10:15 QuoteHmm... My understanding is that this is perfectly safe in practice for leaf functions, microsoft claims it's not and the red zone is only 16 bytes, but this is based on hypotheticals and as long as you don't go too far and you know what your code is doing you shouldn't actually run into any issues. Unless you can guarantee that your code will never be interrupted while it is using data beyond the red zone (which you can't in a pre- emptive multitasking OS), and you can guarantee that it will never execute when the stack is right at the end of a memory page, you are guaranteed to run into issues at some point. ---------------------------------------------------------------------- Madoc · 2023-11-25 13:10 Quote from: Jonas Maebe on November 25, 2023, 11:15:59 amUnless you can guarantee that your code will never be interrupted while it is using data beyond the red zone (which you can't in a pre-emptive multitasking OS), and you can guarantee that it will never execute when the stack is right at the end of a memory page, you are guaranteed to run into issues at some point. I don't think this is true, only an old style debugger running on your same thread or things that you are in control of could interrupt execution and modify your stack space. Another thread can't do this.