Yep, here it is. The logic of R_WORDMAP is:
- If the number of entries ≥ 16, divide in half until it’s less than 16. (Not relevant here.)
- Do a linear search through the table, looking at the first two bytes of each four-byte block. If none of them match, return true.
- Load the two-byte word immediately after the matching address.
- If it’s zero, return false.
- If it’s ≤ the maximum object ID, push it and return true.
- Go to that address and unpack the list, pushing each value in turn. Then return true. (Not relevant here.)
And a datatable address that’s greater than 0x8000 will always be lower than the maximum object ID, because this is a signed comparison! This also needs to check if the address is less than zero.