2018-04-18 02:57:45 +00:00
|
|
|
#
|
2021-01-27 08:03:24 +00:00
|
|
|
# Copyright 2021 Espressif Systems (Shanghai) CO LTD
|
2018-04-18 02:57:45 +00:00
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
#
|
|
|
|
|
|
|
|
import collections
|
2021-01-26 02:49:01 +00:00
|
|
|
import fnmatch
|
2018-04-18 02:57:45 +00:00
|
|
|
import itertools
|
2021-01-27 08:00:19 +00:00
|
|
|
from collections import namedtuple
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-01-27 08:00:19 +00:00
|
|
|
from entity import Entity
|
|
|
|
from fragments import Mapping, Scheme, Sections
|
2019-04-13 00:59:32 +00:00
|
|
|
from ldgen_common import LdGenFailure
|
2021-02-03 10:19:09 +00:00
|
|
|
from output_commands import AlignAtAddress, InputSectionDesc, SymbolAtAddress
|
2021-01-27 08:00:19 +00:00
|
|
|
|
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
class Placement():
|
2021-01-27 08:00:19 +00:00
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
def __init__(self, node, sections, target, flags, explicit, force=False, dryrun=False):
|
|
|
|
self.node = node
|
|
|
|
self.sections = sections
|
|
|
|
self.target = target
|
|
|
|
self.flags = flags
|
2021-01-27 08:00:19 +00:00
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
self.exclusions = set()
|
|
|
|
self.subplacements = set()
|
2021-01-27 08:00:19 +00:00
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
# Force this placement to be output
|
|
|
|
self.force = force
|
2021-01-27 08:00:19 +00:00
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
# This placement was created from a mapping
|
|
|
|
# fragment entry.
|
|
|
|
self.explicit = explicit
|
|
|
|
|
|
|
|
# Find basis placement. A basis placement is a placement
|
|
|
|
# on the parent (or parent's parent and so on and so forth)
|
|
|
|
# that operates on the same section as this one.
|
|
|
|
parent = node.parent
|
|
|
|
candidate = None
|
|
|
|
while parent:
|
|
|
|
try:
|
|
|
|
candidate = parent.placements[sections]
|
|
|
|
except KeyError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
if candidate and candidate.is_significant():
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
parent = parent.parent
|
|
|
|
|
|
|
|
self.basis = candidate
|
|
|
|
|
|
|
|
if self.is_significant() and not dryrun and self.basis:
|
|
|
|
self.basis.add_exclusion(self)
|
|
|
|
|
|
|
|
def is_significant(self):
|
|
|
|
# Check if the placement is significant. Significant placements
|
|
|
|
# are the end of a basis chain (not self.basis) or a change
|
|
|
|
# in target (self.target != self.basis.target)
|
|
|
|
#
|
|
|
|
# Placement can also be a basis if it has flags
|
|
|
|
# (self.flags) or its basis has flags (self.basis.flags)
|
|
|
|
return (not self.basis or
|
|
|
|
self.target != self.basis.target or
|
|
|
|
(self.flags and not self.basis.flags) or
|
|
|
|
(not self.flags and self.basis.flags) or
|
|
|
|
self.force)
|
|
|
|
|
|
|
|
def force_significant(self):
|
|
|
|
if not self.is_significant():
|
|
|
|
self.force = True
|
|
|
|
if self.basis:
|
|
|
|
self.basis.add_exclusion(self)
|
|
|
|
|
|
|
|
def add_exclusion(self, exclusion):
|
|
|
|
self.exclusions.add(exclusion)
|
|
|
|
|
|
|
|
def add_subplacement(self, subplacement):
|
|
|
|
self.subplacements.add(subplacement)
|
|
|
|
|
|
|
|
|
|
|
|
class EntityNode():
|
|
|
|
|
|
|
|
def __init__(self, parent, name):
|
2021-01-27 08:00:19 +00:00
|
|
|
self.children = []
|
|
|
|
self.parent = parent
|
|
|
|
self.name = name
|
2021-02-03 10:19:09 +00:00
|
|
|
self.child_t = EntityNode
|
2021-01-27 08:00:19 +00:00
|
|
|
self.entity = None
|
2021-02-03 10:19:09 +00:00
|
|
|
self.placements = dict()
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-01-27 08:00:19 +00:00
|
|
|
def add_child(self, entity):
|
|
|
|
child_specificity = self.entity.specificity.value + 1
|
|
|
|
assert(child_specificity <= Entity.Specificity.SYMBOL.value)
|
|
|
|
name = entity[Entity.Specificity(child_specificity)]
|
|
|
|
assert(name and name != Entity.ALL)
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-01-27 08:00:19 +00:00
|
|
|
child = [c for c in self.children if c.name == name]
|
|
|
|
assert(len(child) <= 1)
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-01-27 08:00:19 +00:00
|
|
|
if not child:
|
2021-02-03 10:19:09 +00:00
|
|
|
child = self.child_t(self, name)
|
2021-01-27 08:00:19 +00:00
|
|
|
self.children.append(child)
|
|
|
|
else:
|
|
|
|
child = child[0]
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-01-27 08:00:19 +00:00
|
|
|
return child
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-01-27 08:00:19 +00:00
|
|
|
def get_output_commands(self):
|
|
|
|
commands = collections.defaultdict(list)
|
|
|
|
|
|
|
|
def process_commands(cmds):
|
|
|
|
for (target, commands_list) in cmds.items():
|
|
|
|
commands[target].extend(commands_list)
|
|
|
|
|
|
|
|
# Process the commands generated from this node
|
|
|
|
node_commands = self.get_node_output_commands()
|
|
|
|
process_commands(node_commands)
|
|
|
|
|
|
|
|
# Process the commands generated from this node's children
|
|
|
|
# recursively
|
|
|
|
for child in sorted(self.children, key=lambda c: c.name):
|
|
|
|
children_commands = child.get_output_commands()
|
|
|
|
process_commands(children_commands)
|
|
|
|
|
|
|
|
return commands
|
|
|
|
|
|
|
|
def get_node_output_commands(self):
|
|
|
|
commands = collections.defaultdict(list)
|
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
for sections in self.get_output_sections():
|
|
|
|
placement = self.placements[sections]
|
|
|
|
if placement.is_significant():
|
|
|
|
assert(placement.node == self)
|
|
|
|
|
|
|
|
keep = False
|
|
|
|
sort = None
|
|
|
|
surround = []
|
|
|
|
|
|
|
|
placement_flags = placement.flags if placement.flags is not None else []
|
|
|
|
|
|
|
|
for flag in placement_flags:
|
|
|
|
if isinstance(flag, Mapping.Keep):
|
|
|
|
keep = True
|
|
|
|
elif isinstance(flag, Mapping.Sort):
|
|
|
|
sort = (flag.first, flag.second)
|
|
|
|
else: # emit or align
|
|
|
|
surround.append(flag)
|
|
|
|
|
|
|
|
for flag in surround:
|
|
|
|
if flag.pre:
|
|
|
|
if isinstance(flag, Mapping.Emit):
|
|
|
|
commands[placement.target].append(SymbolAtAddress('_%s_start' % flag.symbol))
|
|
|
|
else: # align
|
|
|
|
commands[placement.target].append(AlignAtAddress(flag.alignment))
|
|
|
|
|
|
|
|
# This is for expanded object node and symbol node placements without checking for
|
|
|
|
# the type.
|
|
|
|
placement_sections = frozenset(placement.sections)
|
|
|
|
command_sections = sections if sections == placement_sections else placement_sections
|
|
|
|
|
|
|
|
command = InputSectionDesc(placement.node.entity, command_sections, [e.node.entity for e in placement.exclusions], keep, sort)
|
|
|
|
commands[placement.target].append(command)
|
|
|
|
|
|
|
|
# Generate commands for intermediate, non-explicit exclusion placements here, so that they can be enclosed by
|
|
|
|
# flags that affect the parent placement.
|
|
|
|
for subplacement in placement.subplacements:
|
|
|
|
if not subplacement.flags and not subplacement.explicit:
|
|
|
|
command = InputSectionDesc(subplacement.node.entity, subplacement.sections,
|
|
|
|
[e.node.entity for e in subplacement.exclusions], keep, sort)
|
|
|
|
commands[placement.target].append(command)
|
|
|
|
|
|
|
|
for flag in surround:
|
|
|
|
if flag.post:
|
|
|
|
if isinstance(flag, Mapping.Emit):
|
|
|
|
commands[placement.target].append(SymbolAtAddress('_%s_end' % flag.symbol))
|
|
|
|
else: # align
|
|
|
|
commands[placement.target].append(AlignAtAddress(flag.alignment))
|
2021-01-27 08:00:19 +00:00
|
|
|
|
|
|
|
return commands
|
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
def self_placement(self, sections, target, flags, explicit=True, force=False):
|
|
|
|
placement = Placement(self, sections, target, flags, explicit, force)
|
|
|
|
self.placements[sections] = placement
|
|
|
|
return placement
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
def child_placement(self, entity, sections, target, flags, sections_db):
|
|
|
|
child = self.add_child(entity)
|
|
|
|
child.insert(entity, sections, target, flags, sections_db)
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
def insert(self, entity, sections, target, flags, sections_db):
|
|
|
|
if self.entity.specificity == entity.specificity:
|
|
|
|
# Since specificities match, create the placement in this node.
|
|
|
|
self.self_placement(sections, target, flags)
|
|
|
|
else:
|
|
|
|
# If not, create a child node and try to create the placement there.
|
|
|
|
self.child_placement(entity, sections, target, flags, sections_db)
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
def get_output_sections(self):
|
|
|
|
return sorted(self.placements.keys(), key=' '.join)
|
2018-04-18 02:57:45 +00:00
|
|
|
|
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
class SymbolNode(EntityNode):
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
def __init__(self, parent, name):
|
|
|
|
EntityNode.__init__(self, parent, name)
|
|
|
|
self.entity = Entity(self.parent.parent.name, self.parent.name)
|
2018-04-18 02:57:45 +00:00
|
|
|
|
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
class ObjectNode(EntityNode):
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
def __init__(self, parent, name):
|
|
|
|
EntityNode.__init__(self, parent, name)
|
|
|
|
self.child_t = SymbolNode
|
2021-01-27 08:00:19 +00:00
|
|
|
self.entity = Entity(self.parent.name, self.name)
|
2021-02-03 10:19:09 +00:00
|
|
|
self.subplacements = list()
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
def child_placement(self, entity, sections, target, flags, sections_db):
|
|
|
|
child = self.add_child(entity)
|
|
|
|
sym_placement = Placement(child, sections, target, flags, True, dryrun=True)
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
# The basis placement for sym_placement can either be
|
|
|
|
# an existing placement on this node, or nonexistent.
|
|
|
|
if sym_placement.is_significant():
|
2021-01-27 08:00:19 +00:00
|
|
|
try:
|
2021-02-03 10:19:09 +00:00
|
|
|
obj_sections = self.placements[sections].sections
|
2021-01-27 08:00:19 +00:00
|
|
|
except KeyError:
|
2021-02-03 10:19:09 +00:00
|
|
|
obj_sections = None
|
|
|
|
|
|
|
|
if not obj_sections or obj_sections == sections:
|
|
|
|
# Expand this section for the first time
|
|
|
|
found_sections = sections_db.get_sections(self.parent.name, self.name)
|
|
|
|
obj_sections = []
|
2021-01-27 08:00:19 +00:00
|
|
|
for s in sections:
|
2021-02-03 10:19:09 +00:00
|
|
|
obj_sections.extend(fnmatch.filter(found_sections, s))
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
if obj_sections:
|
|
|
|
symbol = entity.symbol
|
2021-01-27 08:00:19 +00:00
|
|
|
remove_sections = [s.replace('.*', '.%s' % symbol) for s in sections if '.*' in s]
|
2021-02-03 10:19:09 +00:00
|
|
|
filtered_sections = [s for s in obj_sections if s not in remove_sections]
|
|
|
|
|
|
|
|
if set(filtered_sections) != set(obj_sections):
|
|
|
|
if sym_placement.basis:
|
|
|
|
subplace = False
|
|
|
|
try:
|
|
|
|
# If existing placement exists, make sure that
|
|
|
|
# it is emitted.
|
|
|
|
obj_placement = self.placements[sections]
|
|
|
|
except KeyError:
|
|
|
|
# Create intermediate placement.
|
|
|
|
obj_placement = self.self_placement(sections, sym_placement.basis.target, None, False)
|
|
|
|
if obj_placement.basis.flags:
|
|
|
|
subplace = True
|
|
|
|
|
|
|
|
if subplace:
|
|
|
|
obj_placement.basis.add_subplacement(obj_placement)
|
|
|
|
self.subplacements.append(sections)
|
|
|
|
else:
|
|
|
|
obj_placement.force_significant()
|
|
|
|
|
|
|
|
obj_placement.sections = filtered_sections
|
|
|
|
sym_placement.basis = obj_placement
|
|
|
|
|
|
|
|
sym_placement.sections = remove_sections
|
|
|
|
child.placements[sections] = sym_placement
|
|
|
|
|
|
|
|
def get_output_sections(self):
|
|
|
|
output_sections = [key for key in self.placements if key not in self.subplacements]
|
|
|
|
return sorted(output_sections, key=' '.join)
|
|
|
|
|
|
|
|
|
|
|
|
class ArchiveNode(EntityNode):
|
|
|
|
|
|
|
|
def __init__(self, parent, name):
|
|
|
|
EntityNode.__init__(self, parent, name)
|
|
|
|
self.child_t = ObjectNode
|
2021-01-27 08:00:19 +00:00
|
|
|
self.entity = Entity(self.name)
|
2018-04-18 02:57:45 +00:00
|
|
|
|
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
class RootNode(EntityNode):
|
2021-01-27 08:00:19 +00:00
|
|
|
def __init__(self):
|
2021-02-03 10:19:09 +00:00
|
|
|
EntityNode.__init__(self, None, Entity.ALL)
|
|
|
|
self.child_t = ArchiveNode
|
2021-01-27 08:00:19 +00:00
|
|
|
self.entity = Entity('*')
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2018-12-04 12:46:48 +00:00
|
|
|
|
2021-01-27 08:00:19 +00:00
|
|
|
class Generation:
|
2018-12-04 12:46:48 +00:00
|
|
|
"""
|
2021-02-03 10:19:09 +00:00
|
|
|
Implements generation of placement based on collected sections, scheme and mapping fragment.
|
2018-12-04 12:46:48 +00:00
|
|
|
"""
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-01-27 08:00:19 +00:00
|
|
|
# Processed mapping, scheme and section entries
|
2021-02-03 10:19:09 +00:00
|
|
|
EntityMapping = namedtuple('EntityMapping', 'entity sections_group target flags')
|
2021-01-27 08:00:19 +00:00
|
|
|
|
2020-04-29 10:26:52 +00:00
|
|
|
def __init__(self, check_mappings=False, check_mapping_exceptions=None):
|
2018-04-18 02:57:45 +00:00
|
|
|
self.schemes = {}
|
2021-02-03 10:19:09 +00:00
|
|
|
self.placements = {}
|
2018-04-18 02:57:45 +00:00
|
|
|
self.mappings = {}
|
|
|
|
|
2020-04-29 10:26:52 +00:00
|
|
|
self.check_mappings = check_mappings
|
|
|
|
|
|
|
|
if check_mapping_exceptions:
|
|
|
|
self.check_mapping_exceptions = check_mapping_exceptions
|
|
|
|
else:
|
|
|
|
self.check_mapping_exceptions = []
|
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
def _prepare_scheme_dictionary(self):
|
2018-04-18 02:57:45 +00:00
|
|
|
scheme_dictionary = collections.defaultdict(dict)
|
|
|
|
|
|
|
|
# Collect sections into buckets based on target name
|
|
|
|
for scheme in self.schemes.values():
|
|
|
|
sections_bucket = collections.defaultdict(list)
|
|
|
|
|
|
|
|
for (sections_name, target_name) in scheme.entries:
|
|
|
|
# Get the sections under the bucket 'target_name'. If this bucket does not exist
|
|
|
|
# is is created automatically
|
|
|
|
sections_in_bucket = sections_bucket[target_name]
|
|
|
|
|
|
|
|
try:
|
2021-02-03 10:19:09 +00:00
|
|
|
sections = self.placements[sections_name]
|
2018-04-18 02:57:45 +00:00
|
|
|
except KeyError:
|
2021-01-27 08:00:19 +00:00
|
|
|
message = GenerationException.UNDEFINED_REFERENCE + " to sections '" + sections_name + "'."
|
2018-04-18 02:57:45 +00:00
|
|
|
raise GenerationException(message, scheme)
|
|
|
|
|
|
|
|
sections_in_bucket.append(sections)
|
|
|
|
|
|
|
|
scheme_dictionary[scheme.name] = sections_bucket
|
|
|
|
|
|
|
|
# Search for and raise exception on first instance of sections mapped to multiple targets
|
|
|
|
for (scheme_name, sections_bucket) in scheme_dictionary.items():
|
|
|
|
for sections_a, sections_b in itertools.combinations(sections_bucket.values(), 2):
|
|
|
|
set_a = set()
|
|
|
|
set_b = set()
|
|
|
|
|
|
|
|
for sections in sections_a:
|
|
|
|
set_a.update(sections.entries)
|
|
|
|
|
|
|
|
for sections in sections_b:
|
|
|
|
set_b.update(sections.entries)
|
|
|
|
|
|
|
|
intersection = set_a.intersection(set_b)
|
|
|
|
|
|
|
|
# If the intersection is a non-empty set, it means sections are mapped to multiple
|
|
|
|
# targets. Raise exception.
|
|
|
|
if intersection:
|
|
|
|
scheme = self.schemes[scheme_name]
|
2021-01-26 02:49:01 +00:00
|
|
|
message = 'Sections ' + str(intersection) + ' mapped to multiple targets.'
|
2018-04-18 02:57:45 +00:00
|
|
|
raise GenerationException(message, scheme)
|
|
|
|
|
|
|
|
return scheme_dictionary
|
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
def _prepare_entity_mappings(self, scheme_dictionary, entities):
|
|
|
|
# Prepare entity mappings processed from mapping fragment entries.
|
|
|
|
def get_section_strs(section):
|
|
|
|
s_list = [Sections.get_section_data_from_entry(s) for s in section.entries]
|
|
|
|
return frozenset([item for sublist in s_list for item in sublist])
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
entity_mappings = dict()
|
2018-04-18 02:57:45 +00:00
|
|
|
|
|
|
|
for mapping in self.mappings.values():
|
2019-03-19 06:35:47 +00:00
|
|
|
archive = mapping.archive
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-01-27 08:00:19 +00:00
|
|
|
for (obj, symbol, scheme_name) in mapping.entries:
|
|
|
|
entity = Entity(archive, obj, symbol)
|
|
|
|
|
|
|
|
# Check the entity exists
|
|
|
|
if (self.check_mappings and
|
|
|
|
entity.specificity.value > Entity.Specificity.ARCHIVE.value and
|
|
|
|
mapping.name not in self.check_mapping_exceptions):
|
|
|
|
if not entities.check_exists(entity):
|
|
|
|
message = "'%s' not found" % str(entity)
|
|
|
|
raise GenerationException(message, mapping)
|
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
if (obj, symbol, scheme_name) in mapping.flags.keys():
|
|
|
|
flags = mapping.flags[(obj, symbol, scheme_name)]
|
|
|
|
# Check if all section->target defined in the current
|
|
|
|
# scheme.
|
|
|
|
for (s, t, f) in flags:
|
|
|
|
if (t not in scheme_dictionary[scheme_name].keys() or
|
|
|
|
s not in [_s.name for _s in scheme_dictionary[scheme_name][t]]):
|
2021-01-27 08:00:19 +00:00
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
message = "%s->%s not defined in scheme '%s'" % (s, t, scheme_name)
|
|
|
|
raise GenerationException(message, mapping)
|
|
|
|
else:
|
|
|
|
flags = None
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
# Create placement for each 'section -> target' in the scheme.
|
|
|
|
for (target, sections) in scheme_dictionary[scheme_name].items():
|
|
|
|
for section in sections:
|
|
|
|
# Find the applicable flags
|
|
|
|
_flags = []
|
|
|
|
|
|
|
|
if flags:
|
|
|
|
for (s, t, f) in flags:
|
|
|
|
if (s, t) == (section.name, target):
|
|
|
|
_flags.extend(f)
|
|
|
|
|
|
|
|
sections_str = get_section_strs(section)
|
|
|
|
|
|
|
|
key = (entity, section.name)
|
|
|
|
|
|
|
|
try:
|
|
|
|
existing = entity_mappings[key]
|
|
|
|
except KeyError:
|
|
|
|
existing = None
|
|
|
|
|
|
|
|
if not existing:
|
|
|
|
entity_mappings[key] = Generation.EntityMapping(entity, sections_str, target, _flags)
|
|
|
|
else:
|
|
|
|
# Check for conflicts.
|
|
|
|
if (target != existing.target):
|
|
|
|
raise GenerationException('Sections mapped to multiple targets.', mapping)
|
|
|
|
|
|
|
|
# Combine flags here if applicable, to simplify
|
|
|
|
# insertion logic.
|
|
|
|
if (_flags or existing.flags):
|
|
|
|
if ((_flags and not existing.flags) or (not _flags and existing.flags)):
|
|
|
|
_flags.extend(existing.flags)
|
|
|
|
entity_mappings[key] = Generation.EntityMapping(entity,
|
|
|
|
sections_str,
|
|
|
|
target, _flags)
|
|
|
|
elif (_flags == existing.flags):
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
raise GenerationException('Conflicting flags specified.', mapping)
|
|
|
|
|
|
|
|
# Sort the mappings by specificity, so as to simplify
|
|
|
|
# insertion logic.
|
|
|
|
res = list(entity_mappings.values())
|
|
|
|
res.sort(key=lambda m: m.entity)
|
|
|
|
return res
|
|
|
|
|
|
|
|
def generate(self, entities):
|
|
|
|
scheme_dictionary = self._prepare_scheme_dictionary()
|
|
|
|
entity_mappings = self._prepare_entity_mappings(scheme_dictionary, entities)
|
2021-01-27 08:00:19 +00:00
|
|
|
root_node = RootNode()
|
|
|
|
for mapping in entity_mappings:
|
2021-02-03 10:19:09 +00:00
|
|
|
(entity, sections, target, flags) = mapping
|
2021-01-27 08:00:19 +00:00
|
|
|
try:
|
2021-02-03 10:19:09 +00:00
|
|
|
root_node.insert(entity, sections, target, flags, entities)
|
2021-01-27 08:00:19 +00:00
|
|
|
except ValueError as e:
|
|
|
|
raise GenerationException(str(e))
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-02-03 10:19:09 +00:00
|
|
|
# Traverse the tree, creating the placements
|
2021-01-27 08:00:19 +00:00
|
|
|
commands = root_node.get_output_commands()
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-01-27 08:00:19 +00:00
|
|
|
return commands
|
2018-04-18 02:57:45 +00:00
|
|
|
|
|
|
|
def add_fragments_from_file(self, fragment_file):
|
|
|
|
for fragment in fragment_file.fragments:
|
|
|
|
dict_to_append_to = None
|
|
|
|
|
2019-04-05 06:32:21 +00:00
|
|
|
if isinstance(fragment, Mapping) and fragment.deprecated and fragment.name in self.mappings.keys():
|
|
|
|
self.mappings[fragment.name].entries |= fragment.entries
|
2018-04-18 02:57:45 +00:00
|
|
|
else:
|
2019-04-05 06:32:21 +00:00
|
|
|
if isinstance(fragment, Scheme):
|
|
|
|
dict_to_append_to = self.schemes
|
|
|
|
elif isinstance(fragment, Sections):
|
2021-02-03 10:19:09 +00:00
|
|
|
dict_to_append_to = self.placements
|
2019-04-05 06:32:21 +00:00
|
|
|
else:
|
|
|
|
dict_to_append_to = self.mappings
|
|
|
|
|
|
|
|
# Raise exception when the fragment of the same type is already in the stored fragments
|
|
|
|
if fragment.name in dict_to_append_to.keys():
|
|
|
|
stored = dict_to_append_to[fragment.name].path
|
|
|
|
new = fragment.path
|
|
|
|
message = "Duplicate definition of fragment '%s' found in %s and %s." % (fragment.name, stored, new)
|
|
|
|
raise GenerationException(message)
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2019-04-05 06:32:21 +00:00
|
|
|
dict_to_append_to[fragment.name] = fragment
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2018-12-04 12:46:48 +00:00
|
|
|
|
2018-11-29 00:46:54 +00:00
|
|
|
class GenerationException(LdGenFailure):
|
2018-12-04 12:46:48 +00:00
|
|
|
"""
|
|
|
|
Exception for linker script generation failures such as undefined references/ failure to
|
|
|
|
evaluate conditions, duplicate mappings, etc.
|
|
|
|
"""
|
2018-04-18 02:57:45 +00:00
|
|
|
|
2021-01-26 02:49:01 +00:00
|
|
|
UNDEFINED_REFERENCE = 'Undefined reference'
|
2018-04-18 02:57:45 +00:00
|
|
|
|
|
|
|
def __init__(self, message, fragment=None):
|
|
|
|
self.fragment = fragment
|
|
|
|
self.message = message
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
if self.fragment:
|
|
|
|
return "%s\nIn fragment '%s' defined in '%s'." % (self.message, self.fragment.name, self.fragment.path)
|
|
|
|
else:
|
|
|
|
return self.message
|