EF_MIPS_ARCH_32R2=0x70000000
EF_MIPS_ARCH_64R2=0x80000000
+ EF_RISCV_RVC=0x00000001
+ EF_RISCV_FLOAT_ABI=0x00000006
+ EF_RISCV_FLOAT_ABI_SOFT=0x00000000
+ EF_RISCV_FLOAT_ABI_SINGLE=0x00000002
+ EF_RISCV_FLOAT_ABI_DOUBLE=0x00000004
+ EF_RISCV_FLOAT_ABI_QUAD=0x00000006
+ EF_RISCV_RVE=0x00000008
+ EF_RISCV_TSO=0x00000010
+
class E_FLAGS_MASKS(object):
"""Masks to be used for convenience when working with E_FLAGS
ENUM_D_TAG, ENUM_E_VERSION, ENUM_P_TYPE_BASE, ENUM_SH_TYPE_BASE,
ENUM_RELOC_TYPE_i386, ENUM_RELOC_TYPE_x64,
ENUM_RELOC_TYPE_ARM, ENUM_RELOC_TYPE_AARCH64, ENUM_RELOC_TYPE_PPC64,
- ENUM_RELOC_TYPE_MIPS, ENUM_ATTR_TAG_ARM, ENUM_DT_FLAGS, ENUM_DT_FLAGS_1)
+ ENUM_RELOC_TYPE_MIPS, ENUM_ATTR_TAG_ARM, ENUM_ATTR_TAG_RISCV,
+ ENUM_DT_FLAGS, ENUM_DT_FLAGS_1)
from .constants import (
P_FLAGS, RH_FLAGS, SH_FLAGS, SUNW_SYMINFO_FLAGS, VER_FLAGS)
from ..common.utils import bytes2hex
else:
return _DESCR_ATTR_TAG_ARM[tag] + d_entry[val]
+def describe_attr_tag_riscv(tag, val, extra):
+ idx = ENUM_ATTR_TAG_RISCV[tag] - 1
+ d_entry = _DESCR_ATTR_VAL_RISCV[idx]
+
+ if d_entry is None:
+ s = _DESCR_ATTR_TAG_RISCV[tag]
+ s += '"%s"' % val if val else ''
+ return s
+
+ else:
+ return _DESCR_ATTR_TAG_RISCV[tag] + d_entry[val]
+
+
def describe_note_gnu_property_x86_feature_1(value):
descs = []
EM_BLACKFIN='Analog Devices Blackfin',
EM_PPC='PowerPC',
EM_PPC64='PowerPC64',
+ EM_RISCV='RISC-V',
RESERVED='RESERVED',
)
PT_AARCH64_ARCHEXT='AARCH64_ARCHEXT',
PT_AARCH64_UNWIND='AARCH64_UNWIND',
PT_TLS='TLS',
- PT_MIPS_ABIFLAGS='ABIFLAGS'
+ PT_MIPS_ABIFLAGS='ABIFLAGS',
+ PT_RISCV_ATTRIBUTES='RISCV_ATTRIBUT',
)
SHT_ARM_PREEMPTMAP='ARM_PREEMPTMAP',
SHT_ARM_ATTRIBUTES='ARM_ATTRIBUTES',
SHT_ARM_DEBUGOVERLAY='ARM_DEBUGOVERLAY',
+ SHT_RISCV_ATTRIBUTES='RISCV_ATTRIBUTES',
SHT_MIPS_LIBLIST='MIPS_LIBLIST',
SHT_MIPS_DEBUG='MIPS_DEBUG',
SHT_MIPS_REGINFO='MIPS_REGINFO',
TAG_MPEXTENSION_USE_OLD='Tag_MPextension_use_old: ',
)
-
_DESCR_ATTR_VAL_ARM = [
None, #1
None, #2
1: 'Allowed',
},
]
+
+_DESCR_ATTR_TAG_RISCV = dict(
+ TAG_FILE='File Attributes',
+ TAG_SECTION='Section Attributes:',
+ TAG_SYMBOL='Symbol Attributes:',
+ TAG_STACK_ALIGN='Tag_RISCV_stack_align: ',
+ TAG_ARCH='Tag_RISCV_arch: ',
+ TAG_UNALIGNED='Tag_RISCV_unaligned_access: ',
+)
+
+_DESCR_ATTR_VAL_RISCV = [
+ None, #1
+ None, #2
+ None, #3
+ { #4 TAG_RISCV_stack_align
+ 4: '4-bytes',
+ 16: '16-bytes',
+ },
+ None, #5 TAG_RISCV_arch
+ { #6 TAG_RISCV_unaligned_access
+ 0: 'Not Allowed',
+ 1: 'Allowed',
+ },
+]
from .sections import (
Section, StringTableSection, SymbolTableSection,
SymbolTableIndexSection, SUNWSyminfoTableSection, NullSection,
- NoteSection, StabSection, ARMAttributesSection)
+ NoteSection, StabSection, ARMAttributesSection, RISCVAttributesSection)
from .dynamic import DynamicSection, DynamicSegment
from .relocation import (RelocationSection, RelocationHandler,
RelrRelocationSection)
return StabSection(section_header, name, self)
elif sectype == 'SHT_ARM_ATTRIBUTES':
return ARMAttributesSection(section_header, name, self)
+ elif sectype == 'SHT_RISCV_ATTRIBUTES':
+ return RISCVAttributesSection(section_header, name, self)
elif sectype == 'SHT_HASH':
return self._make_elf_hash_section(section_header, name)
elif sectype == 'SHT_GNU_HASH':
SHT_ARM_ATTRIBUTES=0x70000003,
SHT_ARM_DEBUGOVERLAY=0x70000004))
+ENUM_SH_TYPE_RISCV = merge_dicts(
+ ENUM_SH_TYPE_BASE,
+ dict(SHT_RISCV_ATTRIBUTES=0x70000003))
+
ENUM_SH_TYPE_MIPS = merge_dicts(
ENUM_SH_TYPE_BASE,
dict(
ENUM_P_TYPE_BASE,
dict(PT_MIPS_ABIFLAGS=0x70000003))
+ENUM_P_TYPE_RISCV = merge_dicts(
+ ENUM_P_TYPE_BASE,
+ dict(PT_RISCV_ATTRIBUTES=0x70000003))
+
# st_info bindings in the symbol header
ENUM_ST_INFO_BIND = dict(
STB_LOCAL=0,
TAG_MPEXTENSION_USE_OLD=70,
)
+ENUM_ATTR_TAG_RISCV = dict(
+ TAG_FILE=1,
+ TAG_SECTION=2,
+ TAG_SYMBOL=3,
+ TAG_STACK_ALIGN=4,
+ TAG_ARCH=5,
+ TAG_UNALIGNED_ACCESS=6,
+)
+
# https://openpowerfoundation.org/wp-content/uploads/2016/03/ABI64BitOpenPOWERv1.1_16July2015_pub4.pdf
# See 3.5.3 Relocation Types Table.
ENUM_RELOC_TYPE_PPC64 = dict(
self.stream.seek(offset)
yield stabs
-
-class ARMAttribute(object):
- """ ARM attribute object - representing a build attribute of ARM ELF files.
+class Attribute(object):
+ """ Attribute object - representing a build attribute of ELF files.
"""
- def __init__(self, structs, stream):
- self._tag = struct_parse(structs.Elf_Attribute_Tag, stream)
+ def __init__(self, tag):
+ self._tag = tag
self.extra = None
- if self.tag in ('TAG_FILE', 'TAG_SECTION', 'TAG_SYMBOL'):
- self.value = struct_parse(structs.Elf_word('value'), stream)
-
- if self.tag != 'TAG_FILE':
- self.extra = []
- s_number = struct_parse(structs.Elf_uleb128('s_number'), stream)
-
- while s_number != 0:
- self.extra.append(s_number)
- s_number = struct_parse(structs.Elf_uleb128('s_number'),
- stream
- )
-
- elif self.tag in ('TAG_CPU_RAW_NAME', 'TAG_CPU_NAME', 'TAG_CONFORMANCE'):
- self.value = struct_parse(structs.Elf_ntbs('value',
- encoding='utf-8'),
- stream)
-
- elif self.tag == 'TAG_COMPATIBILITY':
- self.value = struct_parse(structs.Elf_uleb128('value'), stream)
- self.extra = struct_parse(structs.Elf_ntbs('vendor_name',
- encoding='utf-8'),
- stream)
-
- elif self.tag == 'TAG_ALSO_COMPATIBLE_WITH':
- self.value = ARMAttribute(structs, stream)
-
- if type(self.value.value) is not str:
- nul = struct_parse(structs.Elf_byte('nul'), stream)
- elf_assert(nul == 0,
- "Invalid terminating byte %r, expecting NUL." % nul)
-
- else:
- self.value = struct_parse(structs.Elf_uleb128('value'), stream)
-
@property
def tag(self):
return self._tag['tag']
def __repr__(self):
- s = '<ARMAttribute (%s): %r>' % (self.tag, self.value)
+ s = '<%s (%s): %r>' % \
+ (self.__class__.__name__, self.tag, self.value)
s += ' %s' % self.extra if self.extra is not None else ''
return s
-class ARMAttributesSubsubsection(object):
- """ Subsubsection of an ELF .ARM.attributes section's subsection.
+class AttributesSubsubsection(Section):
+ """ Subsubsection of an ELF attribute section's subsection.
"""
- def __init__(self, stream, structs, offset):
+ def __init__(self, stream, structs, offset, attribute):
self.stream = stream
self.offset = offset
self.structs = structs
+ self.attribute = attribute
- self.header = ARMAttribute(self.structs, self.stream)
+ self.header = self.attribute(self.structs, self.stream)
self.attr_start = self.stream.tell()
self.stream.seek(self.attr_start)
while self.stream.tell() != end:
- yield ARMAttribute(self.structs, self.stream)
+ yield self.attribute(self.structs, self.stream)
def __repr__(self):
- s = "<ARMAttributesSubsubsection (%s): %d bytes>"
- return s % (self.header.tag[4:], self.header.value)
+ s = "<%s (%s): %d bytes>"
+ return s % (self.__class__.__name__,
+ self.header.tag[4:], self.header.value)
-class ARMAttributesSubsection(object):
- """ Subsection of an ELF .ARM.attributes section.
+class AttributesSubsection(Section):
+ """ Subsection of an ELF attributes section.
"""
- def __init__(self, stream, structs, offset):
+ def __init__(self, stream, structs, offset, header, subsubsection):
self.stream = stream
self.offset = offset
self.structs = structs
+ self.subsubsection = subsubsection
- self.header = struct_parse(self.structs.Elf_Attr_Subsection_Header,
- self.stream,
- self.offset
- )
+ self.header = struct_parse(header, self.stream, self.offset)
self.subsubsec_start = self.stream.tell()
self.stream.seek(self.subsubsec_start)
while self.stream.tell() != end:
- subsubsec = ARMAttributesSubsubsection(self.stream,
- self.structs,
- self.stream.tell())
+ subsubsec = self.subsubsection(self.stream,
+ self.structs,
+ self.stream.tell())
self.stream.seek(self.subsubsec_start + subsubsec.header.value)
yield subsubsec
return self.header[name]
def __repr__(self):
- s = "<ARMAttributesSubsection (%s): %d bytes>"
- return s % (self.header['vendor_name'], self.header['length'])
+ s = "<%s (%s): %d bytes>"
+ return s % (self.__class__.__name__,
+ self.header['vendor_name'], self.header['length'])
-class ARMAttributesSection(Section):
- """ ELF .ARM.attributes section.
+class AttributesSection(Section):
+ """ ELF attributes section.
"""
- def __init__(self, header, name, elffile):
- super(ARMAttributesSection, self).__init__(header, name, elffile)
+ def __init__(self, header, name, elffile, subsection):
+ super(AttributesSection, self).__init__(header, name, elffile)
+ self.subsection = subsection
fv = struct_parse(self.structs.Elf_byte('format_version'),
self.stream,
- self['sh_offset']
- )
+ self['sh_offset'])
elf_assert(chr(fv) == 'A',
- "Unknown attributes version %s, expecting 'A'." % chr(fv)
- )
+ "Unknown attributes version %s, expecting 'A'." % chr(fv))
self.subsec_start = self.stream.tell()
self.stream.seek(self.subsec_start)
while self.stream.tell() != end:
- subsec = ARMAttributesSubsection(self.stream,
- self.structs,
- self.stream.tell())
+ subsec = self.subsection(self.stream,
+ self.structs,
+ self.stream.tell())
self.stream.seek(self.subsec_start + subsec['length'])
yield subsec
+
+
+class ARMAttribute(Attribute):
+ """ ARM attribute object - representing a build attribute of ARM ELF files.
+ """
+ def __init__(self, structs, stream):
+ super(ARMAttribute, self).__init__(
+ struct_parse(structs.Elf_Arm_Attribute_Tag, stream))
+
+ if self.tag in ('TAG_FILE', 'TAG_SECTION', 'TAG_SYMBOL'):
+ self.value = struct_parse(structs.Elf_word('value'), stream)
+
+ if self.tag != 'TAG_FILE':
+ self.extra = []
+ s_number = struct_parse(structs.Elf_uleb128('s_number'), stream)
+
+ while s_number != 0:
+ self.extra.append(s_number)
+ s_number = struct_parse(structs.Elf_uleb128('s_number'),
+ stream)
+
+ elif self.tag in ('TAG_CPU_RAW_NAME', 'TAG_CPU_NAME', 'TAG_CONFORMANCE'):
+ self.value = struct_parse(structs.Elf_ntbs('value',
+ encoding='utf-8'),
+ stream)
+
+ elif self.tag == 'TAG_COMPATIBILITY':
+ self.value = struct_parse(structs.Elf_uleb128('value'), stream)
+ self.extra = struct_parse(structs.Elf_ntbs('vendor_name',
+ encoding='utf-8'),
+ stream)
+
+ elif self.tag == 'TAG_ALSO_COMPATIBLE_WITH':
+ self.value = ARMAttribute(structs, stream)
+
+ if type(self.value.value) is not str:
+ nul = struct_parse(structs.Elf_byte('nul'), stream)
+ elf_assert(nul == 0,
+ "Invalid terminating byte %r, expecting NUL." % nul)
+
+ else:
+ self.value = struct_parse(structs.Elf_uleb128('value'), stream)
+
+
+class ARMAttributesSubsubsection(AttributesSubsubsection):
+ """ Subsubsection of an ELF .ARM.attributes section's subsection.
+ """
+ def __init__(self, stream, structs, offset):
+ super(ARMAttributesSubsubsection, self).__init__(
+ stream, structs, offset, ARMAttribute)
+
+
+class ARMAttributesSubsection(AttributesSubsection):
+ """ Subsection of an ELF .ARM.attributes section.
+ """
+ def __init__(self, stream, structs, offset):
+ super(ARMAttributesSubsection, self).__init__(
+ stream, structs, offset,
+ structs.Elf_Attr_Subsection_Header,
+ ARMAttributesSubsubsection)
+
+
+class ARMAttributesSection(AttributesSection):
+ """ ELF .ARM.attributes section.
+ """
+ def __init__(self, header, name, elffile):
+ super(ARMAttributesSection, self).__init__(
+ header, name, elffile, ARMAttributesSubsection)
+
+
+class RISCVAttribute(Attribute):
+ """ Attribute of an ELF .riscv.attributes section.
+ """
+ def __init__(self, structs, stream):
+ super(RISCVAttribute, self).__init__(
+ struct_parse(structs.Elf_RiscV_Attribute_Tag, stream))
+
+ if self.tag in ('TAG_FILE', 'TAG_SECTION', 'TAG_SYMBOL'):
+ self.value = struct_parse(structs.Elf_word('value'), stream)
+
+ if self.tag != 'TAG_FILE':
+ self.extra = []
+ s_number = struct_parse(structs.Elf_uleb128('s_number'), stream)
+
+ while s_number != 0:
+ self.extra.append(s_number)
+ s_number = struct_parse(structs.Elf_uleb128('s_number'),
+ stream)
+
+ elif self.tag == 'TAG_ARCH':
+ self.value = struct_parse(structs.Elf_ntbs('value',
+ encoding='utf-8'),
+ stream)
+
+ else:
+ self.value = struct_parse(structs.Elf_uleb128('value'), stream)
+
+
+class RISCVAttributesSubsubsection(AttributesSubsubsection):
+ """ Subsubsection of an ELF .riscv.attributes subsection.
+ """
+ def __init__(self, stream, structs, offset):
+ super(RISCVAttributesSubsubsection, self).__init__(
+ stream, structs, offset, RISCVAttribute)
+
+
+class RISCVAttributesSubsection(AttributesSubsection):
+ """ Subsection of an ELF .riscv.attributes section.
+ """
+ def __init__(self, stream, structs, offset):
+ super(RISCVAttributesSubsection, self).__init__(
+ stream, structs, offset,
+ structs.Elf_Attr_Subsection_Header,
+ RISCVAttributesSubsubsection)
+
+
+class RISCVAttributesSection(AttributesSection):
+ """ ELF .riscv.attributes section.
+ """
+ def __init__(self, header, name, elffile):
+ super(RISCVAttributesSection, self).__init__(
+ header, name, elffile, RISCVAttributesSubsection)
self._create_gnu_property()
self._create_note(e_type)
self._create_stabs()
+ self._create_attributes_subsection()
self._create_arm_attributes()
+ self._create_riscv_attributes()
self._create_elf_hash()
self._create_gnu_hash()
p_type_dict = ENUM_P_TYPE_AARCH64
elif self.e_machine == 'EM_MIPS':
p_type_dict = ENUM_P_TYPE_MIPS
+ elif self.e_machine == 'EM_RISCV':
+ p_type_dict = ENUM_P_TYPE_RISCV
if self.elfclass == 32:
self.Elf_Phdr = Struct('Elf_Phdr',
sh_type_dict = ENUM_SH_TYPE_AMD64
elif self.e_machine == 'EM_MIPS':
sh_type_dict = ENUM_SH_TYPE_MIPS
+ if self.e_machine == 'EM_RISCV':
+ sh_type_dict = ENUM_SH_TYPE_RISCV
self.Elf_Shdr = Struct('Elf_Shdr',
self.Elf_word('sh_name'),
self.Elf_word('n_value'),
)
- def _create_arm_attributes(self):
+ def _create_attributes_subsection(self):
# Structure of a build attributes subsection header. A subsection is
# either public to all tools that process the ELF file or private to
# the vendor's tools.
encoding='utf-8')
)
- # Structure of a build attribute tag.
- self.Elf_Attribute_Tag = Struct('Elf_Attribute_Tag',
+ def _create_arm_attributes(self):
+ # Structure of an ARM build attribute tag.
+ self.Elf_Arm_Attribute_Tag = Struct('Elf_Arm_Attribute_Tag',
+ Enum(self.Elf_uleb128('tag'),
+ **ENUM_ATTR_TAG_ARM)
+ )
+
+ def _create_riscv_attributes(self):
+ # Structure of a RISC-V build attribute tag.
+ self.Elf_RiscV_Attribute_Tag = Struct('Elf_RiscV_Attribute_Tag',
Enum(self.Elf_uleb128('tag'),
- **ENUM_ATTR_TAG_ARM)
+ **ENUM_ATTR_TAG_RISCV)
)
def _create_elf_hash(self):
self.elffile = ELFFile(file)
self.output = output
self._dwarfinfo = self.elffile.get_dwarf_info()
- arches = {"EM_386": "i386", "EM_X86_64": "x86-64", "EM_ARM": "littlearm", "EM_AARCH64": "littleaarch64", "EM_LOONGARCH64": "loongarch64"}
+ arches = {"EM_386": "i386", "EM_X86_64": "x86-64", "EM_ARM": "littlearm", "EM_AARCH64": "littleaarch64", "EM_LOONGARCH64": "loongarch64", "EM_RISCV": "littleriscv"}
arch = arches[self.elffile['e_machine']]
bits = self.elffile.elfclass
self._emitline("%s: file format elf%d-%s" % (filename, bits, arch))
describe_symbol_type, describe_symbol_bind, describe_symbol_visibility,
describe_symbol_shndx, describe_reloc_type, describe_dyn_tag,
describe_dt_flags, describe_dt_flags_1, describe_ver_flags, describe_note,
- describe_attr_tag_arm, describe_symbol_other
+ describe_attr_tag_arm, describe_attr_tag_riscv, describe_symbol_other
)
from elftools.elf.constants import E_FLAGS
from elftools.elf.constants import E_FLAGS_MASKS
if (flags & E_FLAGS.EF_MIPS_ARCH) == E_FLAGS.EF_MIPS_ARCH_64:
description += ", mips64"
+ elif self.elffile['e_machine'] == "EM_RISCV":
+ if flags & E_FLAGS.EF_RISCV_RVC:
+ description += ", RVC"
+ if (flags & E_FLAGS.EF_RISCV_RVE):
+ description += ", RVE"
+ if (flags & E_FLAGS.EF_RISCV_TSO):
+ description += ", TSO"
+ if (flags & E_FLAGS.EF_RISCV_FLOAT_ABI) == E_FLAGS.EF_RISCV_FLOAT_ABI_SOFT:
+ description += ", soft-float ABI"
+ if (flags & E_FLAGS.EF_RISCV_FLOAT_ABI) == E_FLAGS.EF_RISCV_FLOAT_ABI_SINGLE:
+ description += ", single-float ABI"
+ if (flags & E_FLAGS.EF_RISCV_FLOAT_ABI) == E_FLAGS.EF_RISCV_FLOAT_ABI_DOUBLE:
+ description += ", double-float ABI"
+ if (flags & E_FLAGS.EF_RISCV_FLOAT_ABI) == E_FLAGS.EF_RISCV_FLOAT_ABI_QUAD:
+ description += ", quad-float ABI"
+
return description
def display_program_headers(self, show_heading=True):
"""
if self.elffile['e_machine'] == 'EM_ARM':
self._display_arch_specific_arm()
+ elif self.elffile['e_machine'] == 'EM_RISCV':
+ self._display_arch_specific_riscv()
def display_hex_dump(self, section_spec):
""" Display a hex dump of a section. section_spec is either a section
last = range_list[-1]
self._emitline(' %08x <End of list>' % (last.entry_offset + last.entry_length if ver5 else first.entry_offset))
- def _display_arch_specific_arm(self):
- """ Display the ARM architecture-specific info contained in the file.
+ def _display_attributes(self, attr_sec, descriptor):
+ """ Display the attributes contained in the section.
"""
- attr_sec = self.elffile.get_section_by_name('.ARM.attributes')
-
for s in attr_sec.iter_subsections():
self._emitline("Attribute Section: %s" % s.header['vendor_name'])
for ss in s.iter_subsubsections():
h_val = "" if ss.header.extra is None else " ".join("%d" % x for x in ss.header.extra)
- self._emitline(describe_attr_tag_arm(ss.header.tag, h_val, None))
+ self._emitline(descriptor(ss.header.tag, h_val, None))
for attr in ss.iter_attributes():
self._emit(' ')
- self._emitline(describe_attr_tag_arm(attr.tag,
- attr.value,
- attr.extra))
+ self._emitline(descriptor(attr.tag, attr.value, attr.extra))
+
+ def _display_arch_specific_arm(self):
+ """ Display the ARM architecture-specific info contained in the file.
+ """
+ attr_sec = self.elffile.get_section_by_name('.ARM.attributes')
+ self._display_attributes(attr_sec, describe_attr_tag_arm)
+
+ def _display_arch_specific_riscv(self):
+ """ Display the RISC-V architecture-specific info contained in the file.
+ """
+ attr_sec = self.elffile.get_section_by_name('.riscv.attributes')
+ self._display_attributes(attr_sec, describe_attr_tag_riscv)
def _emit(self, s=''):
""" Emit an object to output
--- /dev/null
+#-------------------------------------------------------------------------------
+# elftools tests
+#
+# Ricardo Barbedo (ricardo@barbedo.me)
+# This code is in the public domain
+#-------------------------------------------------------------------------------
+import unittest
+import os
+
+from elftools.elf.elffile import ELFFile
+
+class TestRISCVSupport(unittest.TestCase):
+ def test_hello(self):
+ with open(os.path.join('test', 'testfiles_for_unittests',
+ 'simple_gcc.elf.riscv'), 'rb') as f:
+ elf = ELFFile(f)
+ self.assertEqual(elf.get_machine_arch(), 'RISC-V')
+
+ # Check some other properties of this ELF file derived from readelf
+ self.assertEqual(elf['e_entry'], 0x10116)
+ self.assertEqual(elf.num_sections(), 13)
+ self.assertEqual(elf.num_segments(), 3)
+
+ def test_build_attributes(self):
+ with open(os.path.join('test', 'testfiles_for_unittests',
+ 'simple_gcc.elf.riscv'), 'rb') as f:
+ elf = ELFFile(f)
+
+ sec = elf.get_section_by_name('.riscv.attributes')
+ self.assertEqual(sec['sh_type'], 'SHT_RISCV_ATTRIBUTES')
+ self.assertEqual(sec.num_subsections, 1)
+
+ subsec = sec.subsections[0]
+ self.assertEqual(subsec.header['vendor_name'], 'riscv')
+ self.assertEqual(subsec.num_subsubsections, 1)
+
+ subsubsec = subsec.subsubsections[0]
+ self.assertEqual(subsubsec.header.tag, 'TAG_FILE')
+
+ for i in subsubsec.iter_attributes('TAG_STACK_ALIGN'):
+ self.assertEqual(i.value, 16)
+
+ for i in subsubsec.iter_attributes('TAG_ARCH'):
+ self.assertEqual(i.value, 'rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0_v1p0_zfh1p0_zfhmin1p0_zba1p0_zbb1p0_zbc1p0_zbs1p0_zve32f1p0_zve32x1p0_zve64d1p0_zve64f1p0_zve64x1p0_zvl128b1p0_zvl32b1p0_zvl64b1p0')
+
+if __name__ == '__main__':
+ unittest.main()
--- /dev/null
+/*
+ * Compiled using https://github.com/riscv-collab/riscv-gnu-toolchain with
+ * multilib support enabled.
+ *
+ * riscv64-unknown-elf-gcc -march=rv64gcv_zba_zbb_zbc_zbs_zfh simple_gcc.riscv.c -o simple_gcc.elf.riscv
+ */
+
+int main()
+{
+ return 42;
+}