Skip to content

Commit

Permalink
[cocas] Move information about lower parts into ExternalEntry
Browse files Browse the repository at this point in the history
  • Loading branch information
cjvth committed Feb 18, 2024
1 parent 19ab6f7 commit 0bee9fd
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 31 deletions.
8 changes: 4 additions & 4 deletions cocas/assembler/targets/cdm8e/code_segments.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,8 @@ def add_ext_record(obj_rec: "ObjectSectionRecord", ext: str, s: "Section", val:
if seg.expr.byte_specifier == 'low':
obj_rec.external.setdefault(ext, []).append(ExternalEntry(offset, range(0, 1), full_bytes=False))
elif seg.expr.byte_specifier == 'high':
obj_rec.external.setdefault(ext, []).append(ExternalEntry(offset, range(1, 2), full_bytes=False))
obj_rec.lower_parts[offset] = obj_rec.lower_parts.get(offset, 0) + val_lo
entry = ExternalEntry(offset, range(1, 2), full_bytes=False, lower_part=val_lo)
obj_rec.external.setdefault(ext, []).append(entry)
else:
obj_rec.external.setdefault(ext, []).append(ExternalEntry(offset, range(0, 2), full_bytes=True))

Expand All @@ -276,7 +276,7 @@ def add_rel_record(obj_rec: "ObjectSectionRecord", s: "Section", val: int,
if seg.expr.byte_specifier == 'low':
obj_rec.relocatable.append(ExternalEntry(offset, range(0, 1), full_bytes=False))
elif seg.expr.byte_specifier == 'high':
obj_rec.relocatable.append(ExternalEntry(offset, range(1, 2), full_bytes=False))
obj_rec.lower_parts[offset] = obj_rec.lower_parts.get(offset, 0) + val_lo
entry = ExternalEntry(offset, range(1, 2), full_bytes=False, lower_part=val_lo)
obj_rec.relocatable.append(entry)
else:
obj_rec.relocatable.append(ExternalEntry(offset, range(0, 2), full_bytes=True))
45 changes: 23 additions & 22 deletions cocas/linker/linker.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,37 +130,38 @@ def link(objects: list[tuple[Any, ObjectModule]], image_size: Optional[int] = No
for loc_offset, location in asect.code_locations.items():
code_locations[loc_offset + image_begin] = location

lower_parts: dict[int, int] = {} # Won't be empty if two entries added together, currently targets don't do that
for rsect in rsects:
image_begin = sect_addresses[rsect.name]
image_end = image_begin + len(rsect.data)
image[image_begin:image_end] = rsect.data
entry_bytes: range
for offset, entry_bytes, sign in map(lambda x: x.as_tuple(), rsect.relocatable):
pos = image_begin + offset
lower_limit = 1 << 8 * entry_bytes.start
val = int.from_bytes(image[pos:pos + len(entry_bytes)], 'little', signed=False) * lower_limit
val += rsect.lower_parts.get(offset, 0)
val += image_begin * sign
val %= (1 << 8 * entry_bytes.stop)
if entry_bytes.start > 0:
rsect.lower_parts[pos] = val % lower_limit
image[pos:pos + len(entry_bytes)] = (val // lower_limit).to_bytes(len(entry_bytes), 'little', signed=False)
for entry in rsect.relocatable:
pos = image_begin + entry.offset
lower_limit = 1 << 8 * entry.entry_bytes.start
val = int.from_bytes(image[pos:pos + len(entry.entry_bytes)], 'little', signed=False) * lower_limit
val += entry.lower_part + lower_parts.get(entry.offset, 0)
val += image_begin * entry.sign
val %= (1 << 8 * entry.entry_bytes.stop)
if entry.entry_bytes.start > 0 and val % lower_limit != 0:
lower_parts[pos] = val % lower_limit
image[pos:pos + len(entry.entry_bytes)] = \
(val // lower_limit).to_bytes(len(entry.entry_bytes), 'little', signed=False)
for loc_offset, location in rsect.code_locations.items():
code_locations[loc_offset + image_begin] = location

for sect in asects + rsects:
for ext_name in sect.external:
for offset, entry_bytes, sign in map(lambda x: x.as_tuple(), sect.external[ext_name]):
pos = sect_addresses[sect.name] + offset
lower_limit = 1 << 8 * entry_bytes.start
val = int.from_bytes(image[pos:pos + len(entry_bytes)], 'little', signed=False) * lower_limit
val += sect.lower_parts.get(offset, 0)
val += ents[ext_name] * sign
val %= (1 << 8 * entry_bytes.stop)
image[pos:pos + len(entry_bytes)] = (val // lower_limit).to_bytes(len(entry_bytes), 'little',
signed=False)
if entry_bytes.start > 0:
sect.lower_parts[pos] = val % lower_limit
for entry in sect.external[ext_name]:
pos = sect_addresses[sect.name] + entry.offset
lower_limit = 1 << 8 * entry.entry_bytes.start
val = int.from_bytes(image[pos:pos + len(entry.entry_bytes)], 'little', signed=False) * lower_limit
val += entry.lower_part + lower_parts.get(entry.offset, 0)
val += ents[ext_name] * entry.sign
val %= (1 << 8 * entry.entry_bytes.stop)
image[pos:pos + len(entry.entry_bytes)] = \
(val // lower_limit).to_bytes(len(entry.entry_bytes), 'little', signed=False)
if entry.entry_bytes.start > 0 and val % lower_limit != 0:
lower_parts[pos] = val % lower_limit

return image, code_locations

Expand Down
3 changes: 3 additions & 0 deletions cocas/object_module/external_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ class ExternalEntry:
"""Should value be added or subtracted (not tested with -1)"""
full_bytes: bool = field(default=True)
"""Whether no bytes were excluded by entry_bytes. Used when exporting this to object file"""
lower_part: int = field(default=0)
"""If least significant bytes are not selected, the corresponding bytes of the constant value
are saved to check for possible overflows."""

def __str__(self):
s = f'{self.sign * self.offset:02x}'
Expand Down
5 changes: 0 additions & 5 deletions cocas/object_module/object_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,8 @@ class ObjectSectionRecord:
"""Mapping between addresses in binary image and locations in the source file"""
alignment: int = field(default=1)
"""If the relocatable section should get address that is a multiple of some number"""

external: defaultdict[str, list[ExternalEntry]] = field(default_factory=lambda: defaultdict(list))
"""List of places in section where some external label is used"""
lower_parts: dict[int, int] = field(default_factory=dict)
"""If there is an external record with some least significant bytes dropped, these
least significant bytes of a constant value are saved to check for possible overflows.
The key in dict equals the offset of the entry (i.e. the beginning of the entry)"""


@dataclass
Expand Down

0 comments on commit 0bee9fd

Please sign in to comment.