Open vovaok opened 4 years ago
Your problem may have following cause:
There are two types of push/pop behavior. In x86, SP points to last occupied place: PUSH is (--SP)=reg, POP is reg=(SP++) In HCS08, SP points to first free space: PUSH is (SP--)=reg, POP is reg=(++SP)
But i didn't find, how this offet indicated in cspec files.
Your problem may have following cause:
There are two types of push/pop behavior. In x86, SP points to last occupied place: PUSH is (--SP)=reg, POP is reg=(SP++) In HCS08, SP points to first free space: PUSH is (SP--)=reg, POP is reg=(++SP)
But i didn't find, how this offet indicated in cspec files.
Yeah, you're right. And do you have any ideas how to explain it to GHIDRA? Is it a bug or I can adjust stack frame offset somehow?
<stackpointer register="name" space="space" growth="positive/negative" reversejustify="true/false"/>
I can't find online documentation for it so this is copypasta
Attributes and Children | ||
register |
Name of register to use as stack pointer | |
space |
Address space that will hold the stack | |
growth |
(Optional) negative or positive | |
reversejustify |
(Optional) true or false |
The <stackpointer>
tag informs Ghidra of the main
stack mechanism for the compiler. The register
attribute
gives the name of the register that holds the current offset into the
stack, and the space
attribute specifies the name of the
address space that holds the actual data. This tag triggers the
creation of a formal stack space. A separate stack
space exists virtually for each function being analyzed where offsets
are calculated relative to the incoming value of this register. This provides
a concrete storage location for a function's local variables
even though the true location is dynamically determined.
By default the stack is assumed to grow in the negative direction,
meaning that entries which are deeper on the stack are stored at larger offsets, and each
new entry pushed on the stack causes the stackpointer register to be decremented. But this
can be changed by setting the growth
attribute to positive,
which reverses the direction that new entries are pushed on the stack.
Stackpointer is defined as it should. The problem is that GHIDRA assumes the return address is at zero offset and locals may have negative offsets only. But at the same time I can define a local variable at any offset. The issue is I can't define multi-byte variable at offset -0x1. It seems that there is the boundary between negative and zero offsets and local variable can't overlay it. So I want to move the boundary between 0x0 and 0x1 offsets. Is there a way to perform this?
Stackpointer is defined as it should. The problem is that GHIDRA assumes the return address is at zero offset and locals may have negative offsets only. But at the same time I can define a local variable at any offset. The issue is I can't define multi-byte variable at offset -0x1. It seems that there is the boundary between negative and zero offsets and local variable can't overlay it. So I want to move the boundary between 0x0 and 0x1 offsets. Is there a way to perform this?
Oh. My apologies I misunderstood.
@astrelsky Andrew, I think this settings is not enough. Thanks for doc - I never seen it before (where it can be found in readable form? I only found raw xml ).
As I understand sources, reversejustify
applies only for variables, less than single stack change.
HCS8 (and STM8, which I am currently working on) doesnt have this issue - register size always equal to stack change. It seems that to describe correctly its stack feature, one needs to specify non equal stackshift and extrapop values in function prototype. I tried to do this, but failed.
Unfortunately, there is not enough examples.
@vovaok, when you set offset=1 for returnaddress, did you see changes in Stack Editor dialog? Looks like bug, that return address always located at zero offset.
No, there is no difference. It looks like changing the offset of returnaddress is useless. If you see at the bottom of the Stack Editor there is Return Address Offset field. It always shows 0x0 regardless of settings in the .cspec file.
If you assign byte
DataType to each stack frame entry it becomes clear what purpose has each byte of the frame with their default names (see picture below).
If I understand GHIDRA terminology correctly, the bytes at offsets 0x0 to 0x2 are considered as a result of the function, not even as return address. And I have no idea why there are 3 bytes, not 2. BTW this fact also doesn't depend on corresponding settings in .cspec.
And I have no idea why there are 3 bytes, not 2
It is because arguments, passed through the stack, started at offset=3. It is stated in .cspec, and it works.
I have some code for HCS-08 microcontroller. It has 8-bit big endian CPU. Inside a function the stack frame looks like this:
But I can't assign data type "word" to
local_16bit
variable, because "No new data type in the cycle group fits". I solve the issue temporarily by declaring two 8-bit variables at -0x1 and 0x0 offsets, but decompilation quality is poor. Also I tried to shift the return address in the .cspec file:But this action has no effect.