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:
...
- 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.
- Using
pop
we read the address of some_address
from the stack (and remove it from there).
- 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).