In a huge ELF binary, I find some functions which use some kind of (string) constant. The constant itself seems to be stored inside the binary itself but I can't figure out, how to resolve IDA's disassembly result:

.text:096B3D58 lea     eax, (stru_8199A2C.st_shndx+1 - 96B3D47h)[ebx]
.text:096B3D5E push    eax             ; char *
.text:096B3D5F push    edx             ; this
.text:096B3D60 call    _ZN11NameDB7resolveEPKc ; NameDB::resolve(char const*)

My problem is to understand the source of the LEA instruction. For me it reads like "the symbol at 0x96B3D47 bytes prior to the symbol table index". Strangely enough, the position 096B3D47 is just a few lines above the above excerpt...

up vote 1 down vote accepted

Strangely enough, the position 096B3D47 is just a few lines above the above excerpt...

... and the instruction before that address is a call instruction. Right?

This kind of instructions is used for position-independend code: The code can be loaded into another address and it will work the same way without modifications. Typically it works like this:

    call some_address                         ; 1
some_address:
    pop ebx                                   ; 2
    lea eax, (some_text - some_address)[ebx]  ; 3
    ...
some_text:
    ...
  1. After the call instruction the address of the instruction after the call instruction will have been pushed to the stack. This means that the address some_address is now on the stack.
  2. Using pop we read the address of some_address from the stack (and remove it from there).
  3. This instruction will calculate some_text - some_address + someaddress so the instruction has the same effect as lea eax, [some_text].

The distance some_text - some_address is always the same when the executable file is loaded into different memory addresses. Therefore the lea instruction will work independently on the location (address) where the program is executed.

The same is true for the call instruction because the argument of the call instruction is stored PC-relative.

The argument of the instruction lea eax, [some_text] however would be an absolute (not a PC-relative) address so you would have to exchange it when executing the program at another address.

For me it reads like "the symbol at 0x96B3D47 bytes prior to the symbol table index".

If there is a relocation table entry for the lea instruction the disassembler could take the information from the relocation table.

In your case this seems to be different:

Your disassembler seems also to be intelligent enough to see that ebx contains the address 096B3D47 at this point. Therefore it will know that the instruction lea eax, XYZ[ebx] will result in a value of 096B3D47+XYZ in the eax register.

Therefore it will disassemble the instruction as lea eax, ((XYZ+096B3D47)-096B3D47)[ebx] and tries to find out what symbol the address XYZ+096B3D47 is.

Many disassemblers I know however only guess here; they assume that the address belongs to the last symbol before that address. And in your case the symbol stru_8199A2C.st_shndx seems to be that symbol.

Obviously your disassembler does not only evaluate symbols but also debugging information such as "Dwarf" debugging data (which contains information used by debuggers).

  • Quite easy to understand. Thanks. But then, I don't have the opportunity to find the location of "some_text" without starting a debug session, do I? – oxident Feb 18 at 15:16

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.