Sign in to follow this  
nts

Assembly, EBP, ESP, R8-R15 and addressing

Recommended Posts

nts    968
Are there any usage restrictions on the EBP and ESP registers or can they be used exactly like the other registers? I kind of remember there being some restriction on them but haven't found anything. Same case with the x86-64 registers (R8-R15)? For addressing if it's possible to hard code a physical address would that be the best thing to do? For example..
MOV EAX, dword ptr[EBP + 10]
becomes...
MOV EAX, dword ptr[12345678]
Any benefit to keeping the address in the register? Readability isn't important as this will be compiled code and the physical addresses will be known at compile time. I also won't need to modify this address as the program runs. I'm guessing the second method will decode to a few less micro op's but performance difference should be negligible (potentially free register though). Thanks in advance

Share this post


Link to post
Share on other sites
bulgurmayo    114
It’s been a while since my last line of assembly but let me try to answer this.
I think you can use EBP like other registers, and potentially you could use it to store any value. As a kind of convention in languages like C/C++, EBP holds the stack base pointer which is used to
1. build the function calling / return mechanism
2. allocate variables on the stack.

ESP holds the stack current pointer so I would be careful not to mess with it.

So if you are not in 100% assembly program, like inside a C/C++ program, you should be very careful to save EBP’s value before messing with it, by pushing it on the stack and popping it later on.

Share this post


Link to post
Share on other sites
nts    968
Quote:
Original post by bulgurmayo
ESP holds the stack current pointer so I would be careful not to mess with it.
Good point, forgot about that.

Quote:
Original post by Evil Steve
I found This useful when I was doing x64 assembly stuff.
Thanks for the link.

Share this post


Link to post
Share on other sites
Rockoon1    104
The 16-bit BP register used to have restrictions (and benefits) on it

In the 32bit era and beyond, EBP/RBP is no longer so asymetric because CS = DS = ES = SS .. the old segment preferences and restrictions of some instructions/registers are no longer meaningful.

btw, a decent compiler (or asm programmer) NEVER uses a stack frame.. ever.. if you cant figure out where things are relative to ESP/RSP then you are probably already dead in the water

Share this post


Link to post
Share on other sites
Skizz    794
Quote:
Original post by Rockoon1
Tbtw, a decent compiler (or asm programmer) NEVER uses a stack frame.. ever.. if you cant figure out where things are relative to ESP/RSP then you are probably already dead in the water


That's not entirely true. It's not difficult to have a situation where the data pushed onto the stack is indeterminate, i.e. some data is only pushed is certain conditions are met.

The only real issue with using BP for memory access is the use of SS by default.

Skizz

Share this post


Link to post
Share on other sites
outRider    852
Quote:
Original post by Rockoon1
btw, a decent compiler (or asm programmer) NEVER uses a stack frame.. ever.. if you cant figure out where things are relative to ESP/RSP then you are probably already dead in the water


GCC does for x86 IIRC, even with -O#, because it allows some minimal debugging and tracing. You have to explicitly pass -fomit-frame-pointer if you don't want them.

As for the OP's question, having EBP free probably wont get you much anyway, internally the processor has many more unnamed registers and will use them to side step write-after-read stalls, so you might be better off setting stack frames and making debugging easier if that is a requirement.

Edit:

Forgot about your other question re: hard coding the address. Which one is better depends on the context. The version with the entire address hard coded in the instruction will obviously be longer, and will probably decode into more micro-ops that break the instruction into 2 (or more) steps, loading the address from just after opcode, then loading the value from that address.

Used sparingly you can make life easier on yourself by using the hard coded one, but inside a loop you would be better off loading the address once outside the loop and using the other one.

[Edited by - outRider on October 10, 2007 11:51:40 AM]

Share this post


Link to post
Share on other sites
Rockoon1    104
Quote:
Original post by Skizz
That's not entirely true.


its not?

Quote:
Original post by Skizz
It's not difficult to have a situation where the data pushed onto the stack is indeterminate, i.e. some data is only pushed is certain conditions are met.


pushes? heh... a really good compiler wont be doing that either.. especially under win64 where the stack should always be aligned to 16 byte boundaries

Allocate enough local space, aligned to the requirements, for the worst case at the start of the procedure.

stop thinking like a black-box compiler :)

Quote:
Original post by Skizz
The only real issue with using BP for memory access is the use of SS by default.


Thats not an issue. ss = ds under win32 and win64, and probably under linux as well.

Share this post


Link to post
Share on other sites
Rockoon1    104
Quote:
Original post by outRider
GCC does for x86 IIRC, even with -O#, because it allows some minimal debugging and tracing. You have to explicitly pass -fomit-frame-pointer if you don't want them.


gcc is not a good compiler.

it is great for what it is .. an open source cross-platform compiler .. but it is not intended to produce the tightest, fastest code on x86(-64) .. icc on the other hand only targets x86(-64) and a stack frame would be a rare exception even without optimizations ..

it is extra work that is not necessary, which also arbitrarily ties up a register .. doesnt that sum it up?

Share this post


Link to post
Share on other sites
Skizz    794
Quote:
Original post by Rockoon1
Quote:
Original post by Skizz
That's not entirely true.


its not?

Quote:
Original post by Skizz
It's not difficult to have a situation where the data pushed onto the stack is indeterminate, i.e. some data is only pushed is certain conditions are met.


pushes? heh... a really good compiler wont be doing that either.. especially under win64 where the stack should always be aligned to 16 byte boundaries

Allocate enough local space, aligned to the requirements, for the worst case at the start of the procedure.

stop thinking like a black-box compiler :)

You think too much like a Windows programmer. There are millions of IA32 systems out there that don't run Windows or *nix (VxWorks for example). My comments were really targeted to assembly programming and not compilers (I should have made that clear). Optimising compilers almost certainly allocate stack space for the worst case scenario. But this is not always a good thing to do, assembly code on limited resource systems would need to keep memory use to a minimum - unused memory is wasted after all, and so memory is only reserved if it is actually going to be used. In this case, SP relative addressing is not really an option. I agree that this scenario is not very common, but it can happen. As for the pushes issue, how about an assembly routine calling a C library function that takes va_args?

Quote:

Quote:
Original post by Skizz
The only real issue with using BP for memory access is the use of SS by default.


Thats not an issue. ss = ds under win32 and win64, and probably under linux as well.


As I said above, what about all the other systems you could be programming for? Making assumptions could lead to errors in the future when the assumptions are no longer valid. If you assume that [BP] == [DI] for BP == DI then you'll get a nasty surprise one day.

Skizz

Share this post


Link to post
Share on other sites
Rockoon1    104
Quote:
Original post by Skizz
You think too much like a Windows programmer. There are millions of IA32 systems out there that don't run Windows or *nix (VxWorks for example).


True.

However, there is a reason that Win64 has the calling convention it has along with all its restrictions.

They didnt decide to hamstring the world with a less performant calling convention.. its more performant.. the sort of thing you would have done on your own in x86 asm when performance was a concern. (Stack piece-wise aligned to a cache lines? check. The first parameters passed in registers? check. An extra register at your disposal? check.)

Quote:
Original post by Skizz
My comments were really targeted to assembly programming and not compilers (I should have made that clear). Optimising compilers almost certainly allocate stack space for the worst case scenario. But this is not always a good thing to do, assembly code on limited resource systems would need to keep memory use to a minimum - unused memory is wasted after all, and so memory is only reserved if it is actually going to be used. In this case, SP relative addressing is not really an option. I agree that this scenario is not very common, but it can happen.


All valid points.

Quote:
Original post by Skizz
As for the pushes issue, how about an assembly routine calling a C library function that takes va_args?


Not sure that this is valid. Surely the call site knows how many parameters are being passed and doesnt have to play the push until you got em all game.

Quote:
Original post by Skizz
As I said above, what about all the other systems you could be programming for? Making assumptions could lead to errors in the future when the assumptions are no longer valid. If you assume that [BP] == [DI] for BP == DI then you'll get a nasty surprise one day.

Skizz


Well most assemblers (such as masm) have specific directives (masm's assume) for describing these things .. I admit that they arent the most attractive thing in the world to use .. but we got by fine with them in the days of 16-bit x86.

Share this post


Link to post
Share on other sites
Rockoon1    104
Additional for the OP:

The R registers do not have the complete functionality of the EAX register .. you cannot access the second byte directly like you can with 'AH' for instance

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this