Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect default segment picked for CALLF instruction when indirect address uses the BP register #7968

Open
Wall-AF opened this issue Mar 31, 2025 · 1 comment

Comments

@Wall-AF
Copy link

Wall-AF commented Mar 31, 2025

Describe the bug
If unspecified, far calls in x86 use default segments and it depends upon the base register used to identify the indirect address as to which is used. For SP&BP relative offsets the default is SP, otherwise it is DS.

The current definition is

:CALLF addr16 is vexMode=0 & addrsize=0 & opsize=0 & byte=0xff; addr16 & reg_opcode=3 ... { local ptr:$(SIZE) = segment(DS,addr16); local addrptr:$(SIZE) = segment(*:2 (ptr+2),*:2 ptr);

but this fails to pick up the segment SS for a BP relative address.
In my local copy of ia.sinc I've replaced line 2899 with
:CALLF seg16^addr16 is vexMode=0 & addrsize=0 & opsize=0 & byte=0xff; seg16 & addr16 & reg_opcode=3 ... { local ptr:$(SIZE) = segment(seg16,addr16); local addrptr:$(SIZE) = segment(*:2 (ptr+2),*:2 ptr);
which proves this as the below shows
10a0:0c4d ff 5e e8 046 - 4 CALLF DS:=>local_1a[BP + -0x18]
this leads to the calling function address being wildly incorrect, producing a call (based incorrectly upon the data segment)

      (*(code *)((char *)"Use SaveAs for new users" + 7))
                (idVocab,numWords,pszPhrase,nSize,paIdUtterances,param_6,pTrainStatus,paLengths);

instead of something like

     *local_1a (idVocab,numWords,pszPhrase,nSize,paIdUtterances,param_6,pTrainStatus,paLengths);

To Reproduce
Steps to reproduce similar behavior from a small app:

  1. Unzip and load into Ghidra the attached PROJ0000.EXE.gzf.zip file
  2. Look at functions Test at 1000:0ff7 and Test2 at 1000:10a7 (original source in header) - only difference is Test has calls to two print functions that use Borlands internal function F_SPUSH@ (see Compiler generated function to copy a structure onto the stack (PUSH for an object) interfers with later analysis #5702) to place the parmeter onto the stack
  3. See that within Test2 the values 3000000 & 125 are correctly assigned to the appropriate fields of the local variable xb
  4. Go back to Test and see that initially the numbers above aren't assigned correctly
  5. Now, import the [email protected] (unzipped) into the Specification Extensions for the Options for 'PROJ0000.EXE' (under the main Editmenu) and modify the function to use thatcallfixup`
  6. See some changes
  7. Set the now visible local_16 to the type XB and rename to xb
  8. See that there's still some incorrect data wrt the use of F_SPUSH@
  9. If you then remove the callfixup notice the local variable xb remains, but that hasn't fixed the stack push either

Expected behavior
Correct segments to be used at all times, and then a better understanding of segmentation can build on this.

Screenshots
N/A.

Attachments
PROJ0000.EXE.gzf.zip
[email protected]

Environment (please complete the following information):

  • OS: Windows 11
  • Java Version: openjdk 21.0.3
  • Ghidra Version: 11.4-DEV
  • Ghidra Origin: locally built

Additional context
16-bit protected mode applications.

@Wall-AF
Copy link
Author

Wall-AF commented Apr 1, 2025

FYI, you can change local_16 from the Listing:Panel, before step 5 above, but it isn't shown in the Decompile:Panel until after messing with the callfixup. This has been an effect since Ghidra version 10.? when changing variable types/names in the Decompile:Panel ceased being reflected in the Listing:Panel! (The change occurred around the fix for #4533.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant