# Path: cle/backends/pe/relocation/pereloc.py
# class PEReloc(Relocation):
#     AUTO_HANDLE_NONE = True
# 
#     def __init__(self, owner, symbol, addr, resolvewith=None):   # pylint: disable=unused-argument
#         super().__init__(owner, symbol, addr)
# 
#         self.resolvewith = resolvewith
#         if self.resolvewith is not None:
#             self.resolvewith = self.resolvewith.lower()
# 
#     def resolve_symbol(self, solist, bypass_compatibility=False, extern_object=None, **kwargs):
#         if not bypass_compatibility:
#             solist = [x for x in solist if self.resolvewith == x.provides]
#         super().resolve_symbol(solist, bypass_compatibility=bypass_compatibility, extern_object=extern_object, **kwargs)
# 
#         if self.resolvedby is None:
#             return
# 
#         # handle symbol forwarders
#         newsym = self.resolvedby.resolve_forwarder()
#         if newsym is None:
#             new_symbol = extern_object.make_extern(self.symbol.name, sym_type=self.symbol.type)
#             self.resolvedby.resolvedby = new_symbol
#             self.resolve(new_symbol)
#             return
# 
#         self.resolvedby = newsym
#         self.symbol.resolvedby = newsym
# 
#     def relocate(self):
#         if self.symbol is None:  # relocation described in the DIRECTORY_ENTRY_BASERELOC table
#             value = self.value
#             if value is None:
#                 l.debug('Unresolved relocation with no symbol.')
#                 return
#             self.owner.memory.store(self.relative_addr, value)
#         else:
#             super().relocate()
# 
#     @property
#     def value(self):
#         if self.resolved:
#             return self.resolvedby.rebased_addr
# 
#     @property
#     def is_base_reloc(self):
#         """
#         These relocations are ignored by the linker if the executable
#         is loaded at its preferred base address. There is no associated
#         symbol with base relocations.
#         """
#         return True if self.symbol is None else False
# 
#     @property
#     def is_import(self):
#         return not self.is_base_reloc
# 
# Path: cle/address_translator.py
# AT = AddressTranslator


import struct
import logging
from .pereloc import PEReloc
from ....address_translator import AT

l = logging.getLogger(name=__name__)

class DllImport(PEReloc):
    """
    There's nothing special to be done for DLL imports but this class
    provides a unique name to the relocation type.
    """
    pass

class IMAGE_REL_BASED_ABSOLUTE(PEReloc):
    def relocate(self):
        pass

class IMAGE_REL_BASED_HIGHADJ(PEReloc):
    def __init__(self, owner, addr, next_rva):
        super().__init__(owner, None, addr)
        self.next_rva = next_rva
    @property
    def value(self):
        """
        In all the other cases, we can ignore the relocation difference part of the
        calculation because we simply use to_mva() to get our rebased address. In this
        case, however, we have to adjust the un-rebased address first.
        """
        org_bytes = self.owner.memory.load(self.relative_addr, 2)
        org_value = struct.unpack('<I', org_bytes)[0]
        adjusted_value = (org_value << 16) + self.next_rva

# Path: cle/backends/pe/relocation/pereloc.py
# class PEReloc(Relocation):
#     AUTO_HANDLE_NONE = True
# 
#     def __init__(self, owner, symbol, addr, resolvewith=None):   # pylint: disable=unused-argument
#         super().__init__(owner, symbol, addr)
# 
#         self.resolvewith = resolvewith
#         if self.resolvewith is not None:
#             self.resolvewith = self.resolvewith.lower()
# 
#     def resolve_symbol(self, solist, bypass_compatibility=False, extern_object=None, **kwargs):
#         if not bypass_compatibility:
#             solist = [x for x in solist if self.resolvewith == x.provides]
#         super().resolve_symbol(solist, bypass_compatibility=bypass_compatibility, extern_object=extern_object, **kwargs)
# 
#         if self.resolvedby is None:
#             return
# 
#         # handle symbol forwarders
#         newsym = self.resolvedby.resolve_forwarder()
#         if newsym is None:
#             new_symbol = extern_object.make_extern(self.symbol.name, sym_type=self.symbol.type)
#             self.resolvedby.resolvedby = new_symbol
#             self.resolve(new_symbol)
#             return
# 
#         self.resolvedby = newsym
#         self.symbol.resolvedby = newsym
# 
#     def relocate(self):
#         if self.symbol is None:  # relocation described in the DIRECTORY_ENTRY_BASERELOC table
#             value = self.value
#             if value is None:
#                 l.debug('Unresolved relocation with no symbol.')
#                 return
#             self.owner.memory.store(self.relative_addr, value)
#         else:
#             super().relocate()
# 
#     @property
#     def value(self):
#         if self.resolved:
#             return self.resolvedby.rebased_addr
# 
#     @property
#     def is_base_reloc(self):
#         """
#         These relocations are ignored by the linker if the executable
#         is loaded at its preferred base address. There is no associated
#         symbol with base relocations.
#         """
#         return True if self.symbol is None else False
# 
#     @property
#     def is_import(self):
#         return not self.is_base_reloc
# 
# Path: cle/address_translator.py
# AT = AddressTranslator


# Path: cle/backends/pe/relocation/generic.py
import struct
import logging
from .pereloc import PEReloc
from ....address_translator import AT


l = logging.getLogger(name=__name__)

class DllImport(PEReloc):
    """
    There's nothing special to be done for DLL imports but this class
    provides a unique name to the relocation type.
    """
    pass

class IMAGE_REL_BASED_ABSOLUTE(PEReloc):
    def relocate(self):
        pass

class IMAGE_REL_BASED_HIGHADJ(PEReloc):
    def __init__(self, owner, addr, next_rva):
        super().__init__(owner, None, addr)
        self.next_rva = next_rva
    @property
    def value(self):
        """
        In all the other cases, we can ignore the relocation difference part of the
        calculation because we simply use to_mva() to get our rebased address. In this
        case, however, we have to adjust the un-rebased address first.
        """
        org_bytes = self.owner.memory.load(self.relative_addr, 2)
        org_value = struct.unpack('<I', org_bytes)[0]
        adjusted_value = (org_value << 16) + self.next_rva

        adjusted_value = (AT.from_lva(adjusted_value, self.owner) & 0xffff0000) >> 16