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.
:azn:

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 Today at 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.