Some structures used in Tomb Raider 5 (whose definitions are available in the TYPES.H and SPECTYPES.H headers for most of them) contain bit-fields, i.e. various different fields that each occupy 1 or 2 bits. Example from COLL_INFO
struct (only the bit-field is shown):
struct COLL_INFO
{
unsigned short slopes_are_walls : 2; // offset=132.0
unsigned short slopes_are_pits : 1; // offset=132.2
unsigned short lava_is_pit : 1; // offset=132.3
unsigned short enable_baddie_push : 1; // offset=132.4
unsigned short enable_spaz : 1; // offset=132.5
unsigned short hit_ceiling : 1; // offset=132.6
};
Here, all of the fields above fit in a single short
(16-bit signed integer), and the number after the colon represents the number of bits that the field occupies. On a little-endian architecture, the fields above will be stored in the order of their definition (although it is not mandatory by the C standard; the compiler is free to choose any arrangement, but that is the most common case you will stumble open).
The problem is that in IDA Pro, and most other decompilers, bit-fields are not handled correctly, but instead treated as a whole:
- in IDA Pseudocode, they will be shown as
bf_XX
(XX is the offset of the field in hex) and handled as a standalone field) - in MIPS assembly, the field will be treated the same way as the pseudocode, but will be "referenced" with the offset of the bit-field.
Therefore, operations on bit-fields are mostly bitwise ANDs and ORs (for clearing and setting a field, respectively). Determining which "part" of the bit-field is being cleared or set takes time, it implies converting the instruction value to its binary representation and finding which bits corresponds to which field. Thus, here is a cheatsheet of common bit-fields operations.
Structure | Operation | Value | Result |
---|---|---|---|
ITEM_INFO | And assign | 0xFFF9 | item.status = 0; |
0xFFF7 | item.gravity_status = 0; | ||
Or assign | 2 | item.status = 1; | |
lara_info | And check | 0x40 | lara.CanMonkeySwing |
0x20 | lara.IsMoving | ||
And assign | 0xFFFB | lara.look = 0; | |
0xDFFF | lara.Busy = 0; |
||
COLL_INFO | And assign | 0xFFCF | coll.enable_spaz = 0; coll.enable_baddie_push = 0; |
0xFFDF | coll.enable_spaz = 0; | ||
0xFFEF | coll.enable_baddie_push = 0; | ||
Or assign | 0x10 | coll.enable_baddie_push = 1; |