Example #1
0
def output_cfi_startstop(label, meta, asm_format):
    return symbol_with_type(label) \
        and meta.get('cfi') == 'yes' \
        and meta.get('compiler') == 'gcc' \
        and 'text' == section_type(label.section) \
        and asm_format in ['att_syntax binutils','intel_syntax','intel_syntax noprefix'] \
        and not '3.2.3' in meta.get('data', '')
Example #2
0
 def new(self, **props):
     label = self.s.find_symbol(section=self.section, **props)
     label.insert_bloc()
     if props.get('bind',None) != 'p2align' \
             and 'text' == section_type(self.section) \
             and self.section in self.b:
         self.b[self.section].set_nxt(label)
         self.b[self.section].set_cfg([label])
     self.b[self.section] = label
Example #3
0
def mk_asm_footer(label, meta, asm_format):
    if not symbol_with_type(label):
        return ''
    cfi = ''
    if output_cfi_startstop(label, meta, asm_format):
        cfi += '\t.cfi_endproc\n'
    if meta.get('compiler') == 'mingw':
        return cfi + ''
    elif meta.get('compiler') == 'clang' and hasattr(label, 'align'):
        return cfi + '\n'
    elif 'get_pc_thunk' in str(label):
        return cfi + ''
    elif 'text' == section_type(label.section):
        return cfi + '\t.size\t%s, .-%s\n' % (label.name, label.name)
    elif label.bind is not None:
        size = label.bytelen
        if size != getattr(label, 'size', size):
            import logging
            log = logging.getLogger("plasmasm")
            log.warning("For label %r, computed size is %s", label, size)
        return cfi + '\t.size\t%s, %s\n' % (label.name, size)
    NEVER
Example #4
0
def mk_bin_file(symbols):
    import sys
    symbols.resolve()
    relocs = {}
    label_func = [
        label for label in symbols.symbols
        if getattr(label, 'type', None) == 'function'
    ]
    if len(label_func): relocs[".eh_frame"] = []
    for pos, label, r_type, section in symbols.list_relocs():
        if not section in relocs:
            relocs[section] = []
        relocs[section].append((pos, label, r_type))
    section_groups = []
    sections = [".text", ".data", ".bss"]
    for label in symbols.symbols:
        section = getattr(label, 'section', '')
        if section.startswith(".rodata") and not section in sections:
            sections.append(section)
    for label in symbols.symbols:
        section = getattr(label, 'section', '')
        if section.startswith(".data") and not section in sections:
            sections.append(section)
    for label in symbols.symbols:
        section = getattr(label, 'section', '')
        if section.startswith(".text.") and not section in sections:
            section_groups.append(section)
            if section in symbols.sections.asm_name:
                if 'comdat' in symbols.sections.asm_name[section]:
                    sections.insert(0, '.group')
            sections.append(section)
    sections += [".comment", ".note.GNU-stack"]
    if len(label_func): sections += [".eh_frame"]
    # Creates a relocatable ELF file
    CPU = symbols.arch.CPU
    if CPU == 'I386': CPU = '386'
    from elfesteem import elf, elf_init
    e = elf_init.ELF(e_type=elf.ET_REL,
                     e_machine=elf.__dict__['EM_' + CPU],
                     sections=sections,
                     relocs=relocs.keys())

    # The symbol table, first local and then global and weak
    # Local symbols begin with an empty symbol and the file name,
    # then sections until bss, then local object or func,
    # then other sections, with ".comment" at the end
    symtab = e.getsectionbyname(".symtab")
    symtab[0] = elf.Sym32(parent=symtab, name="")
    symtab_local_file = []
    symtab_local_symb = []
    symtab_globl_symb = []
    for label in symbols.symbols:
        bind = getattr(label, 'bind', None)
        if bind in [None, 'weak']:
            pass
        elif getattr(label, 'type', None) == 'endofsymbol':
            pass
        elif bind == 'file':
            symtab_local_file.append(label)
        elif bind == 'local':
            symtab_local_symb.append(label)
        elif bind == 'globl':
            symtab_globl_symb.append(label)
        else:
            FAIL
    symtab_sect = [[]]
    for v, s in enumerate(e.sh.shlist):
        if not s.sh.type in [elf.SHT_PROGBITS, elf.SHT_NOBITS]:
            continue
        if s.sh.name == '.comment':
            continue
        symtab_sect[-1].append(
            elf.Sym32(parent=symtab, info=elf.STT_SECTION, shndx=v))
        if s.sh.name == '.bss':
            symtab_sect.append([])
    symtab_sect.append([])
    v = e.sh.shlist.index(e.getsectionbyname(".comment"))
    symtab_sect[-1].append(
        elf.Sym32(parent=symtab, info=elf.STT_SECTION, shndx=v))
    for v, s in enumerate(e.sh.shlist):
        if s.sh.name != '.group': continue
        symtab_sect[-1].append(
            elf.Sym32(parent=symtab, info=elf.STT_SECTION, shndx=v))

    def get_props(label):
        props = {
            'shndx': 0,
            'size': getattr(label, 'size', 0),
            'value': 0,
        }
        props['info'] = {
            None: elf.STT_NOTYPE,
            'object': elf.STT_OBJECT,
            'function': elf.STT_FUNC,
            'tls_object': elf.STT_TLS,
        }[getattr(label, 'type', None)]
        props['other'] = {
            None: elf.STV_DEFAULT,
            'hidden': elf.STV_HIDDEN,
        }[getattr(label, 'visibility', None)]
        if not hasattr(label, 'section'):
            pass
        elif label.section == comm_symbol_section:
            props['shndx'] = elf.SHN_COMMON
            props['value'] = label.align
        elif label.section.startswith('__'):
            section = {
                '__TEXT,__text': '.text',
                '__DATA,__data': '.data',
            }[label.section]
            props['shndx'] = e.sh.shlist.index(e.getsectionbyname(section))
            props['value'] = label.address
        else:
            section = label.section.split(',')[0]
            props['shndx'] = e.sh.shlist.index(e.getsectionbyname(section))
            props['value'] = label.address
        return props

    idx = 1
    label_idx = {}
    for label in symtab_local_file:
        symtab[idx] = elf.Sym32(parent=symtab,
                                name=label.name,
                                info=elf.STT_FILE,
                                shndx=elf.SHN_ABS)
        idx += 1
    for sym in symtab_sect[0]:
        symtab[idx] = sym
        label_idx[e.sh.shlist[sym.shndx].sh.name] = idx
        idx += 1
    for label in symtab_local_symb:
        props = get_props(label)
        if props['info'] == elf.STT_NOTYPE: continue
        symtab[idx] = elf.Sym32(parent=symtab, name=label.name, **props)
        label_idx[label] = idx
        idx += 1
    for sym in symtab_sect[1]:
        symtab[idx] = sym
        label_idx[e.sh.shlist[sym.shndx].sh.name] = idx
        idx += 1
    for label in symtab_local_symb:
        props = get_props(label)
        if props['info'] != elf.STT_NOTYPE: continue
        symtab[idx] = elf.Sym32(parent=symtab, name=label.name, **props)
        label_idx[label] = idx
        idx += 1
    for sym in symtab_sect[2]:
        symtab[idx] = sym
        label_idx[e.sh.shlist[sym.shndx].sh.name] = idx
        idx += 1
    for label in symtab_globl_symb:
        props = get_props(label)
        props['info'] |= elf.STB_GLOBAL << 4
        symtab[idx] = elf.Sym32(parent=symtab, name=label.name, **props)
        label_idx[label] = idx
        idx += 1
    for label in symbols.symbols:
        if getattr(label, 'bind', None) is not None:
            continue
        if getattr(label, 'type', None) == 'padding':
            continue
        if not label.is_symbol():
            continue
        if label.name.endswith('@PLT') or label.name.endswith('@GOT') \
                or label.name.endswith('@GOTOFF'):
            continue
        if hasattr(label, 'reference'):
            continue
        info = elf.STB_GLOBAL << 4
        symtab[idx] = elf.Sym32(parent=symtab,
                                name=label.name,
                                info=info,
                                shndx=0,
                                size=0,
                                value=0)
        label_idx[label] = idx
        idx += 1

    meta = symbols.get_meta()
    if 'ident' in meta:
        s = e.getsectionbyname(".comment")
        s.content[0] = '\0' + meta['ident'] + '\0'

    # eh_frame data structure is quite complicated
    # here, we create a null eh_frame and ad hoc rel.eh_frame
    if len(label_func):
        s = e.getsectionbyname(".eh_frame")
        s.content[0] = '\0' * meta.get('eh_frame_size',
                                       0x18 + 0x20 * len(label_func))
    if 'eh_frame_relocs' in meta:
        eh_reloc = meta['eh_frame_relocs'].sortedkeys
    else:
        eh_reloc = [0x20 * (idx + 1) for idx in range(len(label_func))]
    for idx, pos in enumerate(eh_reloc):
        if ',' in section:
            section = label_func[idx].section.split(',')[0]
        relocs[".eh_frame"].append(
            (pos, section, (elf.EM_386, elf.R_386_PC32)))

    # Section relocations
    from plasmasm.symbols import section_type
    for section in relocs:
        s = e.getsectionbyname(".rel" + section)
        if s is None: continue
        for idx, (pos, label, r_type) in enumerate(relocs[section]):
            cpu, info = r_type
            # For some symbols, the relocation shall refer to the start of
            # the section, not to the symbol itself.
            l_sect = getattr(label, 'section', None)
            if (cpu, info) == (elf.EM_386, elf.R_386_GOTOFF):
                if section_type(section) == 'text' \
                        and getattr(label, 'bind', None) == 'local' \
                        and not label.name.startswith('.LC'):
                    label = l_sect
                elif not hasattr(label, 'bind'):
                    label = l_sect
            if (cpu, info) == (elf.EM_386, elf.R_386_32):
                if not getattr(label, 'bind', None) == 'globl':
                    label = l_sect
            if (cpu, info) == (elf.EM_386, elf.R_386_PC32):
                if not getattr(label, 'bind', 'globl') == 'globl':
                    label = l_sect
            if label in label_idx:
                info += label_idx[label] << 8
            s.content[8 * idx] = elf.Rel32(parent=s, offset=pos,
                                           info=info).pack()

    # Section alignment, does not mimic exactly GNU as
    align = {'.data': (4, 0), '.bss': (4, 0), '.rodata': (1, 0)}
    for label in symbols.symbols:
        section = getattr(label, 'section', None)
        if not section in align:
            continue
        value = getattr(label, 'align', getattr(label, 'size', 0))
        al, sz = align[section]
        for v in [4, 8, 32]:
            if label.address % v == 0 and al < v <= value:
                al = v
        align[section] = (al, sz + value)
    for section in align:
        s = e.getsectionbyname(section)
        if s is None: continue
        al, sz = align[section]
        if section == '.data' and al >= sz: continue
        s.sh.addralign = al

    # Section content
    for section in sections:
        if not section_type(section) in ["text", "data", "rodata", "bss"]:
            continue
        s = e.getsectionbyname(section)
        if s is None:
            continue
        if section in [
                '.text.__i686.get_pc_thunk.bx', '.text.__i686.get_pc_thunk.cx'
        ]:
            for label in symbols.symbols:
                if not getattr(label, 'section', '').startswith(section):
                    continue
                s.content[label.address] = label.pack()
        for o in symbols.object_list():
            label = o[0]
            if label.section != section:
                continue
            if hasattr(label, 'align'):
                end = len(s.content)
                if (end % label.align) != 0:
                    for c in range(label.align - (end % label.align)):
                        s.content += struct.pack("B", 0)
            data = struct.pack("")
            for bloc in o:
                data += bloc.pack()
            size = len(data)
            if hasattr(label, 'size') and label.size != size:
                log.warning("%s has size %d != %d", label, label.size, size)
                # This might be cause by p2align directives
            else:
                symbols.setattr(name=label.name, size=size)
            if not hasattr(label, 'address'):
                log.warning("%s has no address", label)
                # This should have been addressed by symbols.resolve()
                label.address = 0
                symbols.setattr(name=label.name, address=0)
            s.content[label.address] = data

    # Section groups
    for s in e.sh:
        if s.sh.type != elf.SHT_GROUP:
            continue
        ref = section_groups.pop(0)
        if 'comdat' in symbols.sections.asm_name.get(ref, ''):
            s.flags = elf.GRP_COMDAT
        shndx = e.sh.shlist.index(e.getsectionbyname(ref.split(',')[0]))
        s.sections = [shndx]
        if not ',' in ref:
            # TODO
            continue
        label = ref.split(',')[3]
        s.sh.info = symtab.symtab.index(symtab[label])

    return e.pack()
Example #5
0
def parse_asm_file(symbols, txt):
    txt = str(txt.decode('latin1'))  # Working with python >= 2.3
    bloc = current_blocs(symbols)
    # Local labels parsing is managed in a specific data structure
    # https://sourceware.org/binutils/docs-2.18/as/Symbol-Names.html
    symbols.set_meta(local_labels={})
    symbol_type = {}
    symbol_bind = {}
    symbol_size = {}
    cur_align = {}
    cur_proc = {}
    in_function = False
    # - We parse the file line by line, and we build basic blocs
    # - The end of a basic bloc is either caused by a label or by an
    #   instructions having an impact on the CFG
    # - In the latter case, a "virtual" numeric label is created
    lines = list(reversed(txt.split("\n")))  # reverse, to be able to pop/push
    idx = -1
    while len(lines):
        line = lines.pop()
        if line.endswith('\r'): line = line[:-1]  # e.g. mingw on Windows
        idx += 1
        #comment
        if re.match(r'\s*;\S*', line):
            continue
        if re.match(r'\s*//\S*', line):
            continue
        if re.match(r'\s*!\S*', line):
            continue
        if re.match(r'\s*#\S*', line):
            continue
        #comments put by MacOS X clang compiler
        r = re.match(r'([^"]*?)\s*(##|# NOREX|# TAILCALL)', line)
        if r:
            line = r.groups()[0]
        #empty
        if re.match(r'\s*$', line):
            continue
        #label
        r = re.match(r'\s*(\S+)\s*:(.*)', line)
        if r:
            symbol = r.groups()[0]
            lines.append(r.groups()[1])
            #labels to forget
            if re.match(r'\.LL?FB\d+', symbol):
                in_function = True
                bloc.set_data_props(LFB=symbol)
                continue
            if      re.match(r'\.LL?FE\d+', symbol) or \
                    re.match(r'\.Lfe\d+', symbol):
                in_function = False
                continue
            if      re.match(r'\.LL?CFI\d+', symbol) or \
                    re.match(r'\.LL?VL\d+', symbol) or \
                    re.match(r'\.LL?BB\d+', symbol) or \
                    re.match(r'\.LL?BE\d+', symbol) or \
                    re.match(r'\.LL?LST\d+', symbol) or \
                    re.match(r'\.LL?ASF\d+', symbol) or \
                    re.match(r'\.LL?e?text\d+', symbol) or \
                    re.match(r'\.LL?debug_[a-z]+\d+', symbol):
                # Symbols added for debugguer
                continue
            if symbol_type.get(symbol, '') == 'function':
                in_function = True
            if re.match(r'[0-9]+', symbol):
                # local labels: they are numeric labels, and the syntax nb or nf
                # is used to make reference to them
                # https://sourceware.org/binutils/docs-2.18/as/Symbol-Names.html
                # explains how local labels are converted by GNU as
                # we use the same technique
                local = symbols.meta['local_labels']
                if not symbol in local: local[symbol] = 0
                local[symbol] += 1
                symbol = '.L%s\02%d' % (symbol, local[symbol])
            props = {'name': symbol}
            if symbol in symbol_type: props['type'] = symbol_type[symbol]
            if symbol in symbol_bind: props['bind'] = symbol_bind[symbol]
            if symbol in symbol_size: props['size'] = symbol_size[symbol]
            if bloc.section in cur_align:
                props['align'] = cur_align[bloc.section]
            if bloc.section in cur_proc: props['proc'] = cur_proc[bloc.section]
            bloc.new(**props)
            continue
        #dollar label
        r = re.match(r'\s*([0-9]+)\s*\$', line)
        if r:
            # https://sourceware.org/binutils/docs-2.18/as/Symbol-Names.html
            symbol = r.groups()[0]
            symbol = '.L%s\01%d' % (symbol, len(symbols.symbols))
            raise ValueError("Dollar local label %r; not implemented" % symbol)
        #affect symbol
        r = re.match(r'\s*(\S+)\s+=\s+(\S+)\s*', line)
        if r:
            # seen with clang, rewritten into a .set directive
            arguments = r.groups()
            if len(arguments) == 2:
                dst = symbols.find_symbol(name=arguments[1])
                props = {'name': arguments[0]}
                if hasattr(dst, 'section'):
                    NON_REGRESSION_FOUND
                    props['section'] = dst.section
                props['data'] = {'set': dst}
                if props['name'] in symbol_bind:
                    NON_REGRESSION_FOUND
                    props['bind'] = symbol_bind[props['name']]
                symbols.find_symbol(**props)
                continue
        #directive
        if re.match(r'\s*\.', line):
            r = re.match(r'\s*\.(\S+)\s*(.*)', line)
            directive = r.groups()[0]
            rest = r.groups()[1]
            #sections
            if directive in ['section', 'text', 'data', 'bss']:
                if directive == 'section':
                    if rest.startswith('__TEXT'):
                        symbols.set_meta(container='Mach-O')
                        symbols.set_meta(compiler="clang")
                    if rest.startswith('__DATA'):
                        symbols.set_meta(container='Mach-O')
                        symbols.set_meta(compiler="clang")
                    bloc.section = symbols.sections.parse_attributes(rest)
                else:
                    bloc.section = '.%s' % directive
                cur_align.pop(bloc.section, None)
                continue
            #other attributes
            if directive in ['align']:
                arguments = re.split(r",\W*", rest)
                cur_align[bloc.section] = int(arguments[0])
                if symbols.meta.get('compiler') == 'clang':
                    cur_align[bloc.section] = 1 << cur_align[bloc.section]
                if len(arguments) > 1:
                    cur_align[bloc.section] = rest
                # fill = arguments[1]
                # max = arguments[2]
                continue
            if directive in binding_keywords.keys():
                symbol_bind[rest] = binding_keywords[directive]
                continue
            if directive in ['size']:
                r = re.match(r'([^,]+),\s*(.+)', rest)
                symbol = r.groups()[0]
                size = r.groups()[1]
                if 'text' == section_type(
                        bloc.section) and size != ".-%s" % symbol:
                    rsz = re.match(r'\.Lfe\d+-%s' % symbol, size)
                    if not rsz:
                        log.warning("Size of %r is %r instead of '.-%s'",
                                    symbol, size, symbol)
                cur_proc.pop(bloc.section, None)
                if 'text' == section_type(bloc.section):
                    in_function = False
                    continue
                #symbol_size[symbol] = int(size)
                continue
            if directive in ['type']:
                symbols.set_meta(container='ELF')
                r = re.match(r'([^,]+),\s*(.+)', rest)
                symbol = r.groups()[0]
                type_s = r.groups()[1]
                if type_s[0] in ['@', '#', '%']:
                    if type_s[0] == '#':
                        symbols.set_meta(format='sparc')
                    type_s = type_s[1:]
                elif type_s[0] == '"' and type_s[-1] == '"':
                    NON_REGRESSION_FOUND
                    type_s = type_s[1:-1]
                else:
                    log.error("line %r found in section %s", line,
                              bloc.section)
                if type_s in section_for_type \
                    and section_type(bloc.section) in section_for_type[type_s]:
                    if symbol in symbol_type and symbol_type[symbol] != type_s:
                        log.warning("Symbol %s has type %s, not set to %s",
                                    symbol, symbol_type[symbol], type_s)
                    else:
                        symbol_type[symbol] = type_s
                else:
                    log.warning("line %r found in section %s of type %s", line,
                                bloc.section, section_type(bloc.section))
                if not symbol in symbol_bind:
                    symbol_bind[symbol] = 'local'
                continue
            #data
            if directive in ['ascii', 'asciz', 'string', 'ustring']:
                value = line[line.find(r'"') + 1:line.rfind(r'"')]
                # Decode GNU as representation of strings into python string
                value = value.replace(r'\\', r'\B')
                for v in range(0, 4 * 8 * 8):
                    value = value.replace('\\%03o' % v, chr(v))
                for v in range(0, 8 * 8):
                    value = value.replace('\\%02o' % v, chr(v))
                for v in range(0, 8):
                    value = value.replace('\\%01o' % v, chr(v))
                value = value.replace(r'\b', '\b')
                value = value.replace(r'\t', '\t')
                value = value.replace(r'\n', '\n')
                value = value.replace(r'\f', '\f')
                value = value.replace(r'\r', '\r')
                value = value.replace(r'\"', '"')
                value = value.replace(r'\B', '\\')
                if directive in ['asciz', 'string', 'ustring']:
                    value += "\x00"
                if directive == 'ustring':
                    NON_REGRESSION_FOUND
                    value = "".join(map(lambda x: x + '\x00', value))
                # Convert to bytes, python2 and python3
                import struct
                value = struct.pack("B" * len(value), *[ord(_) for _ in value])
                data = ConstantStr(symbols, value, directive)
                if      bloc.section in bloc.b and \
                        bloc.section in cur_align and \
                        len(bloc.b[bloc.section].lines) > 0:
                    NON_REGRESSION_FOUND
                    bloc.new(align=cur_align[bloc.section])
                bloc.addline(data)
                cur_align.pop(bloc.section, None)
                continue
            if directive in constant_classes.keys():
                value = []
                for v in re.split(r",\W*", rest):
                    try:
                        v = int(v, 0)
                    except ValueError:
                        pass
                    value.append(v)
                data = constant_classes[directive](symbols, value)
                if      bloc.section in bloc.b and \
                        bloc.section in cur_align and \
                        len(bloc.b[bloc.section].lines) > 0:
                    bloc.new(align=cur_align[bloc.section])
                bloc.addline(data)
                cur_align.pop(bloc.section, None)
                continue
            if directive in ['zero', 'space']:
                r = re.match(r'([^,]+),\s*([^,]+)', rest)
                if r is None:
                    data = ConstantZero(symbols, int(rest))
                else:
                    # .space second argument is the padding value
                    r = r.groups()
                    size = r[0]
                    padding = r[1]
                    data = Constant1Byte(symbols, [int(padding)] * int(size))
                bloc.addline(data)
                cur_align.pop(bloc.section, None)
                continue
            if directive in ['comm', 'common', 'lcomm', 'tls_common']:
                r = re.match(r'([^,]+),\s*([^,]+),\s*(.+)', rest)
                if r is None:
                    r = re.match(r'([^,]+),\s*(.+)\s*# (\d+)', rest)
                    symbols.set_meta(compiler="mingw")
                if r is None:
                    r = re.match(r'([^,]+),\s*(.+)', rest)
                r = r.groups()
                symbol = r[0]
                size = int(r[1])
                if len(r) == 3:
                    align = int(r[2])
                    if symbols.meta.get('compiler') == 'clang':
                        align = 1 << align
                else:  # mingw
                    align = None
                bind = symbol_bind.get(symbol, 'globl')
                props = {
                    'section': comm_symbol_section,
                    'bind': bind,
                    'size': size,
                    'align': align
                }
                if directive == 'tls_common':
                    NON_REGRESSION_FOUND
                    props['type'] = 'tls_object'
                l = symbols.find_symbol(name=symbol, **props)
                l.insert_bloc()
                data = ConstantZero(symbols, size)
                l.addline(data)
                continue
            if directive == 'zerofill':
                rest = re.split(",", rest)
                if not rest[0] == '__DATA':
                    raise ValueError("zerofill not in __DATA but %s" % rest[0])
                section = "%s,%s" % (rest[0], rest[1])
                symbol = rest[2]
                bind = symbol_bind.get(symbol, 'local')
                size = int(rest[3])
                align = int(rest[4])
                # Note that the actual alignment is 2**align
                align = 1 << align
                props = {
                    'section': section,
                    'bind': bind,
                    'size': size,
                    'align': align
                }
                symbols.sections.set_asm_name(section, section + ",(zerofill)")
                l = symbols.find_symbol(name=symbol, **props)
                l.insert_bloc()
                data = ConstantZero(symbols, props['size'])
                l.addline(data)
                continue
            #other
            if directive == 'intel_syntax':
                if rest == '': format = 'intel_syntax'
                if rest == 'noprefix': format = 'intel_syntax noprefix'
                symbols.set_meta(format=format)
                continue
            if directive == 'file':
                if rest[0] == '"' and rest[-1] == '"':
                    rest = rest[1:-1]
                elif re.match(r'\d+ ".+"', rest):
                    # Info added for debugguer
                    continue
                else:
                    log.error("%s name %r is not between quotes", directive,
                              rest)
                symbols.find_symbol(name=rest, bind="file")
                continue
            if directive == 'ident':
                if rest[0] == '"' and rest[-1] == '"':
                    rest = rest[1:-1]
                else:
                    log.error("%s name %r is not between quotes", directive,
                              rest)
                symbols.set_meta(ident=rest)
                if rest.startswith("GCC: ") and symbols.get_meta().get(
                        'compiler', None) != 'mingw':
                    symbols.set_meta(compiler='gcc')
                continue
            if directive == 'def':
                symbols.set_meta(container='PE')
                symbols.set_meta(compiler="mingw")
                r = re.match(r'([^;]+);\s*(.+);\t.endef', rest)
                symbol = r.groups()[0]
                param = r.groups()[1]
                param = dict([x.split('\t') for x in param.split(';\t')])
                if '.type' in param and param['.type'] == '32':
                    symbol_type[symbol] = 'function'
                if '.scl' in param and param['.scl'] == '2':
                    symbol_bind[symbol] = 'globl'
                if '.scl' in param and param['.scl'] == '3':
                    symbol_bind[symbol] = 'local'
                props = {'name': symbol}
                if symbol in symbol_type: props['type'] = symbol_type[symbol]
                if symbol in symbol_bind: props['bind'] = symbol_bind[symbol]
                if symbol in symbol_size: props['size'] = symbol_size[symbol]
                symbols.find_symbol(**props)
                continue
            if directive == 'proc':
                cur_proc[bloc.section] = rest
                # SPARC only, unused
                continue
            if directive == 'loc':
                # Helper for debugging
                continue
            if directive == 'indirect_symbol':
                # Mach-O specific
                bloc.set_data_props(**{directive: rest})
                continue
            if directive == 'subsections_via_symbols':
                symbols.set_meta(compiler="clang")
                continue
            if directive == 'macosx_version_min':
                # Older versions of clang, e.g. clang-900
                symbols.set_meta(compiler="clang")
                r = re.match(r'([0-9]+),\s*([0-9]+)', rest)
                if r is not None:
                    r = r.groups()
                    osmaj = int(r[0])
                    osmin = int(r[1])
                    symbols.set_meta(os_minversion=(osmaj, osmin, 'vermin'))
                continue
            if directive == 'build_version':
                # Recent versions of clang, e.g. clang-1001
                symbols.set_meta(compiler="clang")
                r = re.match(r'macos, ([0-9]+),\s*([0-9]+)', rest)
                if r is not None:
                    r = r.groups()
                    osmaj = int(r[0])
                    osmin = int(r[1])
                    symbols.set_meta(os_minversion=(osmaj, osmin, 'bldver'))
                continue
            if directive in ('data_region', 'end_data_region'):
                # Recent versions of clang, e.g. clang-801
                symbols.set_meta(compiler="clang")
                continue
            if directive in [
                    'hidden', 'protected', 'internal', 'private_extern',
                    'weak_def_can_be_hidden'
            ]:
                symbols.find_symbol(name=rest)
                symbols.setattr(name=rest, visibility=directive)
                continue
            if directive.startswith('cfi_'):
                if directive in ['cfi_personality', 'cfi_lsda']:
                    bloc.set_data_props(**{directive: rest})
                if directive in ['cfi_sections']:
                    symbols.set_meta(**{directive: rest})
                symbols.set_meta(cfi='yes')
                continue
            if directive == 'p2align':
                if not in_function:
                    props = {'bind': 'p2align', 'type': 'padding'}
                    if bloc.section in cur_align:
                        props['align'] = cur_align[bloc.section]
                        cur_align.pop(bloc.section, None)
                    bloc.new(**props)
                line = ".p2align %s" % rest
                data = P2Align(symbols, line)
                bloc.addline(data)
                continue
            if directive == 'symver':
                # Syntax: weakref symbol, alias
                arguments = re.split(r",\W*", rest)
                if len(arguments) == 2:
                    dst = symbols.find_symbol(name=arguments[1])
                    props = {'name': arguments[0]}
                    props['data'] = {'symver': dst}
                    symbols.find_symbol(**props)
                continue
            if directive == 'weakref':
                # Syntax: weakref alias, symbol
                # Renames alias as symbol, that will be its external name
                arguments = re.split(r",\W*", rest)
                if len(arguments) == 2:
                    dst = symbols.find_symbol(name=arguments[0])
                    props = {'name': arguments[1]}
                    props['data'] = {'weakref': dst}
                    symbols.find_symbol(**props)
                continue
            if directive == 'set':
                # Syntax: set symbol, expression
                # Defines a new symbol, with an expression
                # Same symbol section, address and type
                # binding and size can be different
                arguments = re.split(r",\W*", rest)
                if len(arguments) == 2:
                    dst = symbols.find_symbol(name=arguments[1])
                    props = {'name': arguments[0]}
                    props['data'] = {'set': dst}
                    if props['name'] in symbol_bind:
                        props['bind'] = symbol_bind[props['name']]
                    symbols.find_symbol(**props)
                    continue
            if directive == 'linkonce':
                # The current section has a linkonce directive
                # Only for PE
                NON_REGRESSION_FOUND
                symbols.sections.add_attribute(
                    bloc.section, "\n\t.%s\t%s" % (directive, rest))
                continue
            raise ValueError("unknown directive %s" % str(directive))
        #code
        if ';' in line:
            lines.append(line[line.find(';') + 1:])
            line = line[:line.find(';')]
        data = Instruction(symbols).from_txt(line)
        bloc.addline(data)
        cur_align.pop(bloc.section, None)
    for name in symbol_bind:
        if not name in symbols.symbols_byname:
            symbols.find_symbol(name=name, bind=symbol_bind[name])
    if not 'compiler' in symbols.meta:
        # Heuristics to choose between gcc, mingw, clang
        if not len(symbols.symbols):
            symbols.set_meta(compiler='gcc')
        else:
            for label in symbols.symbols:
                if getattr(label, 'bind', None) != 'file' and \
                        not label.name.startswith('_'):
                    symbols.set_meta(compiler='gcc')
                    break
            else:
                symbols.set_meta(compiler='mingw')