def vinst2ARM(self, iv):
     """
     Analize instruction (ARM)
     :param iv: instruction tuple
     """
     instr = iv[1]
     if instr[0].upper().startswith('MOVW'): self.ARMmovs.append(iv[0])
     if isinstance(instr, Types.DoubleInstr):
         if isinstance(instr[1], Types.TBExp):
             self.insert_text(instr[1].base,
                              int(instr[1].base.split('x')[1], 16))
             self.insert_text(instr[1].dest,
                              int(instr[1].dest.split('x')[1], 16))
             return instr
         return Types.DoubleInstr(
             (instr[0], self.v_exp2(instr[1], instr, None,
                                    False), instr[2], instr[3]))
     if isinstance(instr, Types.TripleInstr):
         if instr[0].startswith('vldr') and isinstance(
                 instr[2], Types.Const):
             self.ARMvldrtargets.append(instr[2])
         return Types.TripleInstr(
             (instr[0], instr[1], self.v_exp2(instr[2], instr, None,
                                              True), instr[3], instr[4]))
     return instr
 def vinst2(self, f, instr):
     """
     Analize instruction (x86)
     :param f: unsused
     :param instr: instruction tuple
     """
     if isinstance(instr, Types.SingleInstr): return instr
     elif isinstance(instr, Types.DoubleInstr):
         return Types.DoubleInstr(
             (instr[0], self.v_exp2(instr[1], instr, f,
                                    False), instr[2], instr[3]))
     elif isinstance(instr, Types.TripleInstr):
         is_test = instr[0].upper() in ['TEST', 'TESTL', 'TESTW', 'TESTB']
         return Types.TripleInstr(
             (instr[0], self.v_exp2(instr[1], instr, f, is_test),
              self.v_exp2(instr[2], instr, f, is_test), instr[3], instr[4]))
     elif isinstance(instr, Types.FourInstr):
         return Types.FourInstr(
             (instr[0], instr[1], self.v_exp2(instr[2], instr, f, False),
              self.v_exp2(instr[3], instr, f, False) if instr[0][0].upper()
              == 'V' else instr[3], instr[4], instr[5]))
     elif isinstance(instr, Types.FiveInstr):
         return Types.FiveInstr(
             (instr[0], instr[1], instr[2],
              self.v_exp2(instr[3], instr, f,
                          False), instr[4], instr[5], instr[6]))
     return instr
Beispiel #3
0
 def scan(self):
     """
     Scan instruction list and modify PC relative code with labels
     """
     i = 0
     inlen = len(self.instrs) - 1
     while i < inlen:
         h1 = self.instrs[i]
         if get_loc(h1).loc_addr >= self.funcs[self.curr_func][1]:
             # It can be assumed that the base register is set only inside a single function
             self.curr_func += 1
             self.curr_regs.clear()
         if isinstance(h1, Types.TripleInstr) and (self.match_get_pc_thunk(h1) \
           or (h1[0].upper() == 'MOV' and isinstance(h1[2], Types.RegClass) \
           and h1[2].upper() in self.curr_regs and isinstance(h1[1], Types.RegClass))):
             # .got.plt address can also be copied to more than one register
             self.curr_regs.add(h1[1].upper())
         elif len(self.curr_regs) > 0:
             if isinstance(h1, Types.DoubleInstr):
                 self.instrs[i] = Types.DoubleInstr((h1[0], self.v_exp(h1[1]), h1[2], h1[3]))
             elif not isinstance(h1, Types.SingleInstr):
                 if isinstance(h1, Types.TripleInstr):
                     self.instrs[i] = Types.TripleInstr((h1[0], self.v_exp(h1[1]), self.v_exp(h1[2]), h1[3], h1[4]))
                 elif isinstance(h1, Types.FourInstr):
                     self.instrs[i] = Types.FourInstr((h1[0], h1[1], self.v_exp(h1[2]), h1[3], h1[4], h1[5]))
                 if isinstance(h1[1], Types.RegClass) and h1[1].upper() in self.curr_regs:
                     # Remove if overridden
                     self.curr_regs.remove(h1[1].upper())
         i += 1
Beispiel #4
0
 def translate_it_block(block):
     """
     Translate IT block using normal branches
     :param block: instruction list of IT block
     :return: instruction list with normal branches
     """
     itloc = get_loc(block[0])
     res = [
         Types.DoubleInstr(
             ('b' + block[0][1], Types.Label('.LIT_%X.T' % itloc.loc_addr),
              itloc, False))
     ]
     branches = {'t': [], 'e': []}
     for i in xrange(1, len(block[0][0])):
         op = block[i][0].split('.')
         op[0] = op[0][:-2]
         instr = type(block[i])(('.'.join(op), ) + block[i][1:])
         branches[block[0][0][i]].append(instr)
     endloc = get_loc(block[-1])
     branches['e'].append(
         Types.DoubleInstr(('b', Types.Label(
             ('.LIT_%X.E' % itloc.loc_addr)), endloc, False)))
     branches['t'][0][-2].loc_label += '.LIT_%X.T: ' % itloc.loc_addr
     res += branches['e'] + branches['t']
     res.append(
         set_loc(
             block[-1],
             Types.Loc('.LIT_%X.E: ' % itloc.loc_addr, endloc.loc_addr,
                       True)))
     return res
Beispiel #5
0
def perform(instrs, funcs):
    # Do stuff to the instruction list
    if not ELF_utils.elf_arm():
        instrs.append(
            Types.TripleInstr(('mov', Types.RegClass('eax'),
                               Types.RegClass('eax'), Types.Loc('', 0,
                                                                True), False)))
    return instrs
Beispiel #6
0
 def __init__(self):
     self.looking_for_cfd = False
     self.text_secs = []
     self.locs = []
     self.up_bound = Types.Loc('', 0, True)
     self.low_bound = Types.Loc('', 0, True)
     self.trim_tbl = {}
     self.five_q = simple_queue()
Beispiel #7
0
 def __init__(self):
     self.cfg_table = {}
     self.cfg_bdiv_table = {}
     self.found_entry = False
     self.skip_entry = False
     self.entry_loc = Types.Loc('', 0, True)
     self.last_loc = Types.Loc('', 0, True)
     self.entry_instr = Types.SingleInstr(('NOP', Types.Loc('', 0,
                                                            True), None))
     self.bb_list = []
     self.bl = []
     self.bl_sort = []
Beispiel #8
0
 def get_framecookiecheck(curr_instr, funcID):
     """
     Get code block for frame cookie check
     :param curr_instr: indirect branch instruction
     :param funcID: generated function ID
     :return: frame cookie check instruction list
     """
     loc = get_loc(curr_instr)
     tmp = list(framecookiecheck)
     tmp[3][2] = Types.Normal(funcID)
     tmp[3] = Types.TripleInstr(tmp[3])
     return set_inlineblocklocation(loc, tmp) + \
            [set_loc(curr_instr, Types.Loc('', loc.loc_addr, loc.loc_visible))]
Beispiel #9
0
 def get_framecookiehead(curr_instr, funcID):
     """
     Get function header code block for frame cookie insertion
     :param curr_instr: function entry instruction
     :param funcID: generated function ID
     :return: frame cookie insertion instruction list
     """
     loc = get_loc(curr_instr)
     tmp = list(framecookiehead)
     tmp[5][2] = Types.Normal(funcID)
     tmp[5] = Types.TripleInstr(tmp[5])
     return set_inlineblocklocation(loc, returnenc + tmp) + \
            [set_loc(curr_instr, Types.Loc('', loc.loc_addr, loc.loc_visible))]
Beispiel #10
0
 def doublemovARM(self, instrs):
     """
     insert labels for double mov operations
       movw r0, #0x102c -> movw r0, #:lower16:S_0x2102c
       movt r0, #0x2    -> movt r0, #:upper16:S_0x2102c
     :param instrs: instruction list
     """
     for i in self.ARMmovs:
         mw = list(instrs[i])
         destreg = mw[1]
         tindex = 1
         while tindex < config.ARM_maxDoublemovDist:
             # GCC optimizations causes movw and movt not to be close to each other
             currinstr = instrs[i + tindex]
             if currinstr[0].upper() == 'MOV' and currinstr[2] == destreg:
                 # Sometimes GCC changes idea and picks another register to load the address
                 destreg = instrs[i + tindex][1]
             elif currinstr[1] == destreg:
                 if currinstr[0].upper().split('.')[0] == 'STR':
                     # Some other times GCC wants to have even more fun and changes register using the stack
                     tindex += 1
                     while tindex < config.ARM_maxDoublemovDist:
                         if instrs[i + tindex][2] == currinstr[2]:
                             destreg = instrs[tindex + i][1]
                             break
                         tindex += 1
                 else:
                     break
             tindex += 1
         if tindex >= config.ARM_maxDoublemovDist: continue
         tindex = i + tindex
         mt = list(instrs[tindex])
         if mt[0].upper().startswith('MOVT') and mt[1] == destreg:
             val = (mt[2] << 16) + (mw[2] & 0xffff)
             s = self.check_sec(val)
             if s is not None:
                 s_label = 'S_' + dec_hex(val)
                 self.insert_data(s.sec_name, val)
                 mw[2] = Types.Label('#:lower16:' + s_label)
                 mt[2] = Types.Label('#:upper16:' + s_label)
                 instrs[i] = type(instrs[i])(mw)
                 instrs[tindex] = type(instrs[tindex])(mt)
             if self.check_text(val):
                 val = val & (-2)
                 s_label = 'S_' + dec_hex(val)
                 self.insert_text(s_label, val)
                 mw[2] = Types.Label('#:lower16:' + s_label)
                 mt[2] = Types.Label('#:upper16:' + s_label)
                 instrs[i] = type(instrs[i])(mw)
                 instrs[tindex] = type(instrs[tindex])(mt)
     self.ARMmovs = []
Beispiel #11
0
 def get_returnenc(curr_instr, popcookie=False):
     """
     Get code block for return address encryption
     :param curr_instr: return instruction
     :param popcookie: True if also frame cookie must be removed
     :return: return encryption instruction list
     """
     pre = list(framecookietail) if popcookie else []
     loc = get_loc(curr_instr)
     if curr_instr[0].upper().startswith('POP'):
         # pop {...,pc}
         i = map(str.upper, curr_instr[1]).index('PC')
         rlist = curr_instr[1][:i] + ('lr', ) + curr_instr[1][i + 1:]
         pre.insert(
             0,
             Types.DoubleInstr(
                 (curr_instr[0], Types.RegList(rlist), None, False)))
         curr_instr = Types.DoubleInstr(
             ('bx', Types.RegClass('lr'), None, False))
     elif curr_instr[0].upper().startswith(
             'LDR') and curr_instr[1].upper() == 'PC':
         # ldr pc, [sp], #4
         pre.insert(
             0,
             type(curr_instr)((curr_instr[0], Types.RegClass('lr')) +
                              curr_instr[2:]))
         curr_instr = Types.DoubleInstr(
             ('bx', Types.RegClass('lr'), None, False))
     return set_inlineblocklocation(loc, pre + returnenc) + \
            [set_loc(curr_instr, Types.Loc('', loc.loc_addr, loc.loc_visible))]
Beispiel #12
0
 def vinst(self, i):
     loc = get_loc(i)
     if self.skip_entry:
         if loc.loc_addr == self.end_loc.loc_addr:
             bn = 'BB_' + str(cfg.counter)
             cfg.counter += 1
             b = Types.Bblock('', bn, loc, loc, i)
             self.bb_list.insert(0, b)
         else:
             self.entry_loc = loc
             self.entry_instr = i
             self.found_entry = True
             self.skip_entry = False
             self.last_loc = loc
             return self.help_exit(
                 i) if Opcode_utils.is_control_transfer_op(i[0],
                                                           i[1]) else i
     elif loc.loc_addr == self.end_loc.loc_addr:
         return self.help_exit(i)
     elif self.bb_entry(i):
         self.help_entry(i)
         return self.help_exit(i) if Opcode_utils.is_control_transfer_op(
             i[0], i[1]) else i
     elif isinstance(i, (Types.DoubleInstr,
                         Types.SingleInstr)) and self.bb_exit(i[0], i[1]):
         return self.help_exit(i)
     self.last_loc = loc
     return i
Beispiel #13
0
def set_inlineblocklocation(loc, block):
    """
    Set location for code block
    :param loc: location object
    :param block: list of instructions
    """
    return [set_loc(block[0], loc)] + \
        map(lambda i: set_loc(i, Types.Loc('', loc.loc_addr, loc.loc_visible)), block[1:])
Beispiel #14
0
 def get_returnenc(curr_instr, popcookie=False):
     """
     Get code block for return address encryption
     :param curr_instr: return instruction
     :param popcookie: True if also frame cookie must be removed
     :return: return encryption instruction list
     """
     loc = get_loc(curr_instr)
     return set_inlineblocklocation(loc, framecookietail + returnenc if popcookie else returnenc) + \
            [set_loc(curr_instr, Types.Loc('', loc.loc_addr, loc.loc_visible))]
Beispiel #15
0
 def unify_loc(self, instrs):
     last_label = ''
     for i in xrange(len(instrs)):
         lo = get_loc(instrs[i])
         if lo.loc_label != '' and lo.loc_label == last_label:
             instrs[i] = set_loc(instrs[i],
                                 Types.Loc('', lo.loc_addr, True))
         else:
             last_label = lo.loc_label
     return instrs
Beispiel #16
0
 def help_exit(self, i):
     loc = get_loc(i)
     if self.found_entry:
         self.last_loc = loc
         bn = 'BB_' + str(cfg.counter)
         cfg.counter += 1
         b = Types.Bblock('', bn, self.entry_loc, self.last_loc,
                          self.entry_instr)
         self.bb_list.insert(0, b)
         self.found_entry = False
         self.skip_entry = True
     elif loc.loc_addr == self.end_loc.loc_addr:
         bn = 'BB_' + str(cfg.counter)
         cfg.counter += 1
         b = Types.Bblock('', bn, loc, loc, i)
         self.bb_list.insert(0, b)
     else:
         self.last_loc = loc
     return i
Beispiel #17
0
 def pcreloffARM(self, instrs):
     """
     Trying to handle this mess
       ldr r7, label           -> ldr r7, label
       ...                     -> ...
       add r7,pc               -> add r7, #0
       ...                     -> ...
       ldr r1, [r7]            -> ldr r1, [r7]
       ...                     -> ...
       label: .word 0xoffset   -> label: .word (0xoffset + pc)
     :param instrs: instruction list
     """
     i = 0
     offsets = {}
     inlen = len(instrs)
     while i < inlen:
         hi = instrs[i]
         if isinstance(hi, Types.TripleInstr) \
           and hi[0].lower().startswith('ldr') \
           and isinstance(hi[2], Types.Point):
             j = i + 1
             while j - i < config.ARM_maxAddPcDist and j < inlen:
                 hj = instrs[j]
                 if isinstance(hj, Types.TripleInstr) \
                   and hj[0].lower().startswith('add') \
                   and hj[1] == hi[1] \
                   and isinstance(hj[2], Types.RegClass) \
                   and hj[2].lower() == 'pc':
                     offsets[hi[2]] = get_loc(hj).loc_addr + 4
                     instrs[j] = Types.TripleInstr(
                         (hj[0], hj[1], Types.Normal(0), hj[3], hj[4]))
                     break
                 j += 1
         elif isinstance(hi, Types.DoubleInstr) and isinstance(
                 hi[0], Types.InlineData):
             off = offsets.pop(get_loc(hi).loc_addr, None)
             if off:
                 instrs[i] = Types.DoubleInstr(
                     (hi[0], Types.Point((hi[1] + off) & 0xFFFFFFFF), hi[2],
                      hi[3]))
         i += 1
Beispiel #18
0
 def help_entry(self, i):
     if self.found_entry:
         bn = 'BB_' + str(cfg.counter)
         cfg.counter += 1
         b = Types.Bblock('', bn, self.entry_loc, self.last_loc,
                          self.entry_instr)
         self.bb_list.insert(0, b)
     self.found_entry = True
     self.entry_instr = i
     self.entry_loc = get_loc(i)
     self.last_loc = self.entry_loc
     return i
Beispiel #19
0
 def v_exp(self, e):
     """
     Check if PC relative expression and transform using labels
     :param e: expression
     :return: transformed expression if matching, original one otherwise
     """
     if isinstance(e, (Types.BinOP_PLUS, Types.BinOP_MINUS)):
         r1, addr = e
         if r1.upper() in self.curr_regs:
             addr = -addr if isinstance(e, Types.BinOP_MINUS) else addr
             des = self.gotaddr + addr
             s = self.check_sec(des)
             if s is not None:
                 self.label.append(des)
                 return Types.Label('S_' + dec_hex(des))
     return e
Beispiel #20
0
 def bswapsub(reg, loc):
     """
     Replace target register in bswap containing ret encoding bytes
     :param reg: bswapped register
     :param loc: instuction location
     :return: instruction list with replaced bswap
     """
     sub = Types.RegClass('edi' if reg[0].lower() == 'e' else 'rdi')
     substack = Types.RegClass('edi' if ELF_utils.elf_32() else 'rdi')
     return set_inlineblocklocation(loc, [
         Types.DoubleInstr(('push', substack, None, False)),
         Types.TripleInstr(('mov', sub, reg, None, False)),
         Types.DoubleInstr(('bswap', sub, None, False)),
         Types.TripleInstr(('mov', reg, sub, None, False)),
         Types.DoubleInstr(('pop', substack, None, False)),
     ])
Beispiel #21
0
 def aux(bnl, acc, i):
     if isinstance(i, Types.SingleInstr) and Opcode_utils.is_ret(
         (i[0], i[1])):
         bn = self.bbn_byloc(get_loc(i).loc_addr)
         acc.insert(0, (bn, (Types.J(), 'RET')))
     elif isinstance(i, Types.DoubleInstr):
         if Opcode_utils.is_indirect(i[1]):
             bn = self.bbn_byloc(get_loc(i).loc_addr)
             acc.insert(0, (bn, (Types.J(), 'T')))
         elif Opcode_utils.is_call(i[0]):
             bn = self.bbn_byloc(get_loc(i).loc_addr)
             bn1 = self.next_bb(bnl, bn)
             acc.insert(0, (bn, (Types.J(), bn1)))
             acc.insert(0, (bn, (Types.J(), 'INTER')))
         elif Opcode_utils.is_jmp(i[0]):
             bn = self.bbn_byloc(get_loc(i).loc_addr)
             if Opcode_utils.is_func(i[1]):
                 acc.insert(0, (bn, (Types.J(), 'INTER')))
             else:
                 en = recover_addr_from_label(p_exp(i[1]))
                 if en == -1:
                     acc.insert(0, (bn, (Types.J(), 'T')))
                 else:
                     dn = self.bbn_byloc(en)
                     acc.insert(0, (bn, (Types.J(), dn)))
         elif Opcode_utils.is_cond_jmp(i[0]):
             if not Opcode_utils.is_func(i[1]):
                 bn = self.bbn_byloc(get_loc(i).loc_addr)
                 sn = self.next_bb(bnl, bn)
                 acc.insert(0, (bn, (Types.F(), sn)))
             else:
                 assert (False)
     else:
         bn = self.bbn_byloc(get_loc(i).loc_addr)
         dn = self.next_bb(bnl, bn)
         acc.insert(0, (bn, (Types.F(), dn)))
     return acc
Beispiel #22
0
 def add_bblock_label(self, bbl, instrs):
     bbl1 = sorted(
         bbl, lambda b1, b2: b1.bblock_begin_loc.loc_addr - b2.
         bblock_begin_loc.loc_addr)
     i = 0
     j = 0
     while True:
         if i == len(instrs) and j < len(bbl1):
             raise Exception('failed to add block label')
         if j == len(bbl1): break
         hi = instrs[i]
         hb = bbl1[j]
         iloc = get_loc(hi)
         bloc = hb.bblock_begin_loc
         if bloc.loc_addr == iloc.loc_addr:
             iloc = Types.Loc(hb.bblock_name + ': ' + iloc.loc_label,
                              iloc.loc_addr, iloc.loc_visible)
             instrs[i] = set_loc(instrs[i], iloc)
             j += 1
         i += 1
     return instrs
Beispiel #23
0
"""
Templates for gfree return address encryption and frame cookie
"""

import config
from disasm import Types
from utils.ail_utils import ELF_utils, set_loc, get_loc

if ELF_utils.elf_64():
    # x86_64

    cslab = Types.Label(config.gfree_cookiestackvar + '@tpoff')

    returnenc = [
        Types.DoubleInstr(('pushq', Types.RegClass('rax'), None, False)),
        Types.TripleInstr(('movq', Types.RegClass('rax'),
                           Types.Label(config.gfree_xorkeyvar), None, False)),
        Types.TripleInstr(('xorq', Types.BinOP_PLUS(
            (Types.RegClass('rsp'), 8)), Types.RegClass('rax'), None, False)),
        Types.DoubleInstr(('popq', Types.RegClass('rax'), None, False)),
    ]

    framecookiehead = [
        Types.DoubleInstr(('pushq', Types.RegClass('rax'), None, False)),
        Types.DoubleInstr(('pushq', Types.RegClass('rbx'), None, False)),
        Types.TripleInstr(('addq', Types.SegRef(
            ('fs', cslab)), Types.Normal(1), None, False)),
        Types.TripleInstr(
            ('movq', Types.RegClass('rbx'), Types.SegRef(
                ('fs', cslab)), None, False)),
        Types.TripleInstr(
Beispiel #24
0
 def secmapper(l):
     items = l.split()
     return Types.Section(items[0], int(items[1], 16),
                          int(items[3], 16))
Beispiel #25
0
 def v_exp2(self, exp, instr, f, chk):
     """
     Analyze expression and determine if it represent an address.
     If so substitute if with a corresponding symbolic expression using labels
     :param exp: expression
     :param instr: instruction tuple to which the expression belongs to
     :param f: unused
     :param chk: True if instruction is TEST (x86)
     :return: modified expression if matching, original one otherwise
     """
     if isinstance(exp, Types.Const):
         if isinstance(exp, Types.Normal) and chk: return exp
         s = self.check_sec(exp)
         if s is not None:
             self.insert_data(s.sec_name, exp)
             return Types.Label(self.build_symbol(exp))
         if self.check_text(exp):
             if ELF_utils.elf_arm(): exp = type(exp)(exp & (-2))
             s_label = self.build_symbol(exp)
             self.insert_text(s_label, exp)
             return Types.Label(s_label)
         if self.check_plt(exp):
             return Types.Label(self.build_plt_symbol(exp))
     elif isinstance(exp, Types.Symbol):
         if isinstance(exp, Types.JumpDes):
             if self.check_text(exp):
                 s_label = 'S_' + dec_hex(exp)
                 self.insert_text(s_label, exp)
                 return Types.Label(s_label)
             elif self.check_plt(exp) and exp in self.plt_hash:
                 return Types.Label(self.plt_hash[exp])
         elif isinstance(exp, Types.StarDes):
             return Types.StarDes(self.v_exp2(exp.content, instr, f, chk))
         elif isinstance(exp, Types.CallDes):
             if exp.func_name.startswith('S_0'):
                 addr = int(exp.func_name[2:], 16)
                 if self.check_text(addr):
                     s_label = 'S_' + dec_hex(addr)
                     self.insert_text(s_label, addr)
                     return Types.Label(s_label)
                 elif self.check_plt(addr):
                     off = 0
                     while not self.plt_hash.get(addr - off, None):
                         off += 2
                     return Types.Label(self.plt_hash[addr - off])
             else:
                 self.symbol_list.insert(0, exp.func_begin_addr)
     elif isinstance(exp, Types.Ptr):
         if isinstance(exp, (Types.BinOP_PLUS, Types.BinOP_MINUS)):
             r, addr = exp
             s = self.check_sec(addr)
             if s is not None:
                 s_label = 'S_' + dec_hex(addr)
                 self.insert_data(s.sec_name, addr)
                 return Types.BinOP_PLUS_S((r, s_label)) \
                     if isinstance(exp, Types.BinOP_PLUS) \
                     else Types.BinOP_MINUS_S((r, s_label))
         elif isinstance(exp, (Types.FourOP_PLUS, Types.FourOP_MINUS)):
             r1, r2, off, addr = exp
             s = self.check_sec(addr)
             if s is not None:
                 s_label = 'S_' + dec_hex(addr)
                 self.insert_data(s.sec_name, addr)
                 return Types.FourOP_PLUS_S((r1,r2,off,s_label)) \
                     if isinstance(exp, Types.FourOP_PLUS) \
                     else Types.FourOP_MINUS_S((r1,r2,off,s_label))
         elif isinstance(exp, Types.JmpTable_PLUS):
             addr, r, off = exp
             s = self.check_sec(addr)
             if s is not None:
                 s_label = 'S_' + dec_hex(addr)
                 self.insert_data(s.sec_name, addr)
                 return Types.JmpTable_PLUS_S((s_label, r, off))
             if self.check_text(addr):
                 s_label = 'S_' + dec_hex(addr)
                 self.insert_text(s_label, addr)
                 return Types.JmpTable_PLUS_S((s_label, r, off))
         elif isinstance(exp, Types.JmpTable_MINUS):
             addr, r, off = exp
             s = self.check_sec(addr)
             if s is not None:
                 s_label = '-S_' + dec_hex(addr)
                 self.insert_data(s.sec_name, addr)
                 return Types.JmpTable_MINUS_S((s_label, r, off))
             if self.check_text(addr):
                 s_label = '-S_' + dec_hex(addr)
                 self.insert_text(s_label, addr)
                 return Types.JmpTable_MINUS_S((s_label, r, off))
     return exp