News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Environment issue? Simple or not so simple?

Started by Nate523, September 13, 2024, 07:03:43 AM

Previous topic - Next topic

TimoVJL

Quote from: jj2007 on September 20, 2024, 05:59:31 PM
Quote from: Nate523 on September 20, 2024, 03:43:25 AMit works both with and without the "sub rsp, 28h"

Not aligning the stack correctly is a recipe for disaster. Many Windows APIs work just fine, but every now and then you will get mysterious crashes...

some people don't like facts and now it is very well proved.
If even depends.exe show, that program crash, who are those people ?
May the source be with you

zedd151

Quote from: TimoVJL on September 20, 2024, 11:09:13 PM... who are those people ?
New members that do not yet fully understand the concept of stack alignment, shadow space, etc. and other specs in the 64 bit ABI.

You should not assume that everyone knows what 'depends.exe' is or or what it does. New members often need a lot of help understanding the "how" and "why" things must be done a certain way, in words that they (as newbies) can understand.

NoCforMe

I've never heard of depends.exe. What and where is it?

(Doesn't have anything to do with diapers, does it?)
Assembly language programming should be fun. That's why I do it.

Nate523

Quote from: TimoVJL on September 20, 2024, 11:09:13 PM
Quote from: jj2007 on September 20, 2024, 05:59:31 PM
Quote from: Nate523 on September 20, 2024, 03:43:25 AMit works both with and without the "sub rsp, 28h"

Not aligning the stack correctly is a recipe for disaster. Many Windows APIs work just fine, but every now and then you will get mysterious crashes...

some people don't like facts and now it is very well proved.
If even depends.exe show, that program crash, who are those people ?

Actually, being the newbie, I missed the last line of your depends.exe export that it crashed when loading ntdll.dll when not aligning the stack, thank you for providing that, I will have to download on my personal computer and learn how to use depends.exe because my work computer (which I was having the issue with) didn't like depends.exe. I will definitely say I think I used the word "work" incorrectly. I was trying to just say that that when I use either the stack alignment way, or not, it runs and I get the exit code I was expecting and no longer getting the exception I was running into with the Visual Studio environment. I think I understand that doesn't mean it worked, and what you showed definitely shows it didn't. Sorry for the confusion.

Still reading up on stack alignment and trying to grasp it, I will take you're word with your experience that it is a bad thing to not do.

NoCforMe

#49
Stack alignment is pretty damn important to any computer system.

Probably the worst that can happen is that a subroutine return address gets lost or trashed. Think about how the CALL instruction works, which is how you access a function: the first thing it does is push the return address (the address of whatever instruction immediately follows the CALL on the stack. Then it jumps to the entry point of the subroutine and starts executing it.

So let's say that in the meantime, while the code in the subroutine is running, the stack pointer (RSP in 64 bit) gets somehow changed. When the subroutine code hits its RET instruction, it pops the stack and retrieves the return address that was pushed on the stack. But if the wrong thing gets popped, then the return will be to somewhere in never-neverland, and you'll get an exception.

Just one of the many ways you can get into trouble with code ...
Assembly language programming should be fun. That's why I do it.

Nate523

Makes sense when you say it, but I'm only sorta familiar with pointers and stacked lists in C++, and even though it seems similar, CPU hardware stack seems more complex. No book or source so far with assembly that I have acquired has said "Hey align the stack before you do any programming", alignment is at the end of one of them so I am reading up on it, so I appreciate a forum like this that can tell me to do so  :biggrin:

Umm and I know I'm a newbie but is this a typo and you meant 32 bit? :

Quote from: NoCforMe on September 21, 2024, 03:09:07 PM... the stack pointer (ESP in 64 bit)

Cause I am reading about the registers and I got a table here that says the RSP register is the 64 bit stack pointer, and ESP is the 32-bit portion of that register? Once again thanks for the explanation!

NoCforMe

RSP, sorry. Typo.

Stacks: Better to have some pictures to illustrate, but follow my description and you should get the idea. It's not rocket surgery.

A stack is a structure implemented in computer memory. It's an area of memory set aside for this use. (Nothing special about that memory: it's the same memory used for your program's code and data. It's just used as a stack.)

So what is a stack? The classic illustration is something that we old folks were familiar with but you youngsters probably aren't: in cafeterias, when you went to get your food the first stop was at the dish stack. This was literally a stack of dishes that had a big spring underneath it so as people took plates off the top it would stay at the same level. (Do they still use those things? I don't remember seeing one of those in a long while.)

What you had here was what's called a LIFO stack, meaning "last in-first out". Imagine instead of taking a dish off this stack, you put a dish on top of the stack--let's say it's your favorite dish and you want to make sure you get it off the stack. Then when you want the dish, you take it off the stack.

Moving to computer usage here, putting the dish on the stack is called a "push".
Taking a dish off the stack is called a "pop".

So why use a stack? what's the point?

Well, it's a very useful data storage scheme. Let's say you're coding a routine that uses some registers--let's call them A, B and C. But in that routine you need to call some other routine that, unfortunately, trashes those registers. What to do?

Well, you could set up some variables to store those registers in, say SaveA, SaveB and SaveC, move the registers to those variables, call the trashing routine, then when it returns restore the registers from those variables.

That would work fine. But using the stack is much easier. Because the processor has instructions designed specifically to deal with the stack. Like the dish example, there are two instructions:
  • PUSH pushes a value (register, variable or immediate value) on the stack
  • POP pops the top of the stack into a register or variable

So in the example with the trashing routine, you'd do this to save those registers (this is pseudocode for some imaginary processor):
    PUSH  A
    PUSH  B
    PUSH  C
    CALL  TrashingRoutine
    POP  C
    POP  B
    POP  A

This saves those 3 registers on the stack, calls the routine, then restores the registers from the stack.

Notice something important: the POPs are in reverse order of the PUSHes. Think about why this is; think about the stack of dishes and the order they are in when you put 3 dishes on the stack and then take those 3 dishes off; what order do they appear in? (Hint: LIFO.)

So moving to computer programming, the stack is used a lot. You can use it as shown above to save and restore registers (or memory variables). It's used every time you call a function; the processor pushes the return address of the function, and some of the parameters (the values passed to the function).

Detail: how does the processor keep track of the stack? RSP is the key here. It's called the stack pointer, and it always points to the top of the stack. It gets changed as PUSHes and POPs are executed. That's why it's so important to make sure that this register is set correctly.

So does that make sense? If you think this through you'll see it's not that complicated.
Assembly language programming should be fun. That's why I do it.

TimoVJL

@Nate523
Just read what other users write, like sinsi said problem for you and i just tried to to give tool to everyone to check it.
Other users didn't do their best to support you, even they are masm programmers, what i am not.
May the source be with you

sinsi

Quote from: Nate523 on September 21, 2024, 02:26:02 PMStill reading up on stack alignment and trying to grasp it, I will take you're word with your experience that it is a bad thing to not do.
It's not just "a bad thing to not do", it's a requirement of the Win64 ABI.
In your code you can do what you want, but as soon as you talk to Windows you have to abide by their rules.
It is just easier to apply the rules even to your own internal code.

Nate523

Quote from: NoCforMe on September 21, 2024, 05:20:38 PMRSP, sorry. Typo.

Stacks: Better to have some pictures to illustrate, but follow my description and you should get the idea. It's not rocket surgery.

A stack is a structure implemented in computer memory. It's an area of memory set aside for this use. (Nothing special about that memory: ...


Thank you for taking the time to give me that detailed explanation. Took a bit to write I'm sure and I appreciate everyone's time in helping me with these things. I think I might have misunderstood that the solution sinsi gave to align the stack was a one time deal, after you're explanation its sounding more like its something I have to constantly do when using assembly and ensure that I don't say, take a sledgehammer to the stack and misalign everything?

Quote from: sinsi on September 21, 2024, 10:56:49 PM
Quote from: Nate523 on September 21, 2024, 02:26:02 PMStill reading up on stack alignment and trying to grasp it, I will take you're word with your experience that it is a bad thing to not do.
It's not just "a bad thing to not do", it's a requirement of the Win64 ABI.
In your code you can do what you want, but as soon as you talk to Windows you have to abide by their rules.
It is just easier to apply the rules even to your own internal code.


I missed that it was an absolute requirement when you posted about it earlier, sorry for that, appreciate the clarification. I'll note it as a do or die thing for right now, is the instruction that you gave:

sub RSP, 28h
The only way thing needs to be done to align the stack, or in the future will I have to align it in different ways based on how I am manipulating data?

sinsi

Quote from: Nate523 on September 22, 2024, 01:35:11 AMThe only way thing needs to be done to align the stack, or in the future will I have to align it in different ways based on how I am manipulating data?
The usual way is to allocate space for any WinAPI calls and align RSP to 16 on proc entry, then not alter RSP at all.
For example, CreateWindowEx takes 12 arguments, so you need to reserve 12*8 bytes, plus 8 for alignment.
Other functions might have less than 4 (GetProcessHeap for one) but you still must allocate 4*8 bytes as per the ABI.
The MASM64 include files have a custom prologue/epilogue which should take care of everything for you - I roll my own so I can't commment on its usefulness.

Nate523

Quote from: sinsi on September 22, 2024, 02:09:49 AM
Quote from: Nate523 on September 22, 2024, 01:35:11 AMThe only way thing needs to be done to align the stack, or in the future will I have to align it in different ways based on how I am manipulating data?
The usual way is to allocate space for any WinAPI calls and align RSP to 16 on proc entry, then not alter RSP at all.
For example, CreateWindowEx takes 12 arguments, so you need to reserve 12*8 bytes, plus 8 for alignment.
Other functions might have less than 4 (GetProcessHeap for one) but you still must allocate 4*8 bytes as per the ABI.
The MASM64 include files have a custom prologue/epilogue which should take care of everything for you - I roll my own so I can't commment on its usefulness.


Thank you for the clarification  :thup:

ognil

Hi Nate523,

Quoteby sinsi: The usual way is to allocate space for any WinAPI calls and align RSP to 16 on proc entry, then not alter RSP at all. For example, CreateWindowEx takes 12 arguments, so you need to reserve 12*8 bytes, plus 8 for alignment.

I agree with sinsi about "The Usual Way", but I use a trick from  university - "The Non-Usual Way".

1. Don't touch the stack - it's aligned from the start.
2. Forget about push, pop, invoke and macros, sub rsp, number, add rsp, number
3. Use ONLY global variables for arguments

I'm using this in my big Example64 project and will post the source code when I'm done.
"Not keeping emotions under control is another type of mental distortion."

NoCforMe

Quote from: ognil on September 22, 2024, 05:21:17 AM2. Forget about push, pop, invoke
So your solution is to never use PUSH, POP or INVOKE?
How quaint. Your programs must be marvels of ingenuity (not).
And you look down on us? Feh ...

OP: Don't pay any attention to this guy.
Assembly language programming should be fun. That's why I do it.

NoCforMe

Quote from: ognil on September 22, 2024, 05:21:17 AM3. Use ONLY global variables for arguments

So you must never write any recursive code, yes?
Do you even know what that is?
Assembly language programming should be fun. That's why I do it.