Ejemplo n.º 1
0
    def __init__(
        self,
        rom_start,
        rom_end,
        type,
        name,
        vram_start,
        extract,
        given_subalign,
        given_is_overlay,
        given_dir,
        args,
        yaml,
    ):
        super().__init__(
            rom_start,
            rom_end,
            type,
            name,
            vram_start,
            extract,
            given_subalign,
            given_is_overlay,
            given_dir,
            args,
            yaml,
        )

        self.rodata_syms: Dict[int, List[Symbol]] = {}

        # TODO: move this to CommonSegCode
        self.section_boundaries = OrderedDict(
            (s_name, Range()) for s_name in options.get_section_order())
        self.subsegments = self.parse_subsegments(yaml)
Ejemplo n.º 2
0
    def __init__(
        self,
        rom_start: RomAddr,
        rom_end: RomAddr,
        type: str,
        name: str,
        vram_start: Any,
        extract: bool = True,
        given_subalign: int = options.get_subalign(),
        exclusive_ram_id: Optional[str] = None,
        given_dir: Path = Path(),
        symbol_name_format: str = options.get_symbol_name_format(),
        symbol_name_format_no_rom: str = options.get_symbol_name_format_no_rom(),
        args=[],
        yaml={},
    ):
        self.rom_start = rom_start
        self.rom_end = rom_end
        self.type = type
        self.name = name
        self.vram_start = vram_start
        self.extract = extract

        self.given_subalign = given_subalign
        self.exclusive_ram_id = exclusive_ram_id
        self.given_dir = given_dir
        self.given_seg_symbols: Dict[
            int, List[Symbol]
        ] = {}  # Symbols known to be in this segment
        self.given_section_order: List[str] = options.get_section_order()

        self.given_symbol_name_format = symbol_name_format
        self.given_symbol_name_format_no_rom = symbol_name_format_no_rom

        self.parent: Optional[Segment] = None
        self.sibling: Optional[Segment] = None

        self.args: List[str] = args
        self.yaml = yaml

        if self.rom_start == "auto":
            self.extract = False

        if self.type.startswith("."):
            self.extract = False

        self.warnings: List[str] = []
        self.did_run = False

        if isinstance(self.rom_start, int) and isinstance(self.rom_end, int):
            if self.rom_start > self.rom_end:
                log.error(
                    f"Error: segments out of order - ({self.name} starts at 0x{self.rom_start:X}, but next segment starts at 0x{self.rom_end:X})"
                )
Ejemplo n.º 3
0
    def add(self, segment: Segment):
        entries = segment.get_linker_entries()
        self.entries.extend(entries)

        self._begin_segment(segment)

        seg_name = get_segment_cname(segment)

        section_labels = [
            LinkerSection(l) for l in options.ld_section_labels()
            if l in options.get_section_order()
        ]

        force_new_section = False
        cur_section = None

        for i, entry in enumerate(entries):
            cur_section = entry.section

            if cur_section == "linker":  # TODO: isinstance is preferable
                self._end_block()
                self._begin_segment(entry.segment)
                continue
            elif cur_section == "linker_offset":
                self._write_symbol(
                    f"{get_segment_cname(entry.segment)}_OFFSET",
                    f". - {get_segment_cname(segment)}_ROM_START",
                )
                continue

            for i, section in enumerate(section_labels):
                if not section.started and section.name == cur_section:
                    if i > 0:
                        if not section_labels[i - 1].ended:
                            section_labels[i - 1].ended = True
                            self._write_symbol(
                                f"{seg_name}{section_labels[i - 1].name.upper()}_END",
                                ".",
                            )
                    section.started = True
                    self._write_symbol(
                        f"{seg_name}{section.name.upper()}_START", ".")

            if options.enable_ld_alignment_hack():
                start = entry.segment.rom_start
                if isinstance(start, int):
                    # Create new sections for non-subalign alignment (hack)
                    if start % 0x10 != 0 and i != 0 or force_new_section:
                        self._end_block()
                        self._begin_segment(entry.segment, mid_segment=True)
                        force_new_section = False

                    if start % 0x10 != 0 and i != 0:
                        force_new_section = True

            if (entry.object_path and cur_section == ".data"
                    and entry.segment.type != "lib"):
                path_cname = re.sub(
                    r"[^0-9a-zA-Z_]",
                    "_",
                    str(entry.segment.dir / entry.segment.name) +
                    ".".join(entry.object_path.suffixes[:-1]),
                )
                self._write_symbol(path_cname, ".")

            # Write out manual entries for images inside .data segments
            seg = entry.segment
            if isinstance(seg, CommonSegData):
                for subseg in seg.subsegments:
                    if isinstance(subseg, N64SegImg):
                        self._write_symbol(get_segment_cname(subseg),
                                           f"0x{subseg.rom_start:X}")

            self._writeln(f"{entry.object_path}({cur_section});")

        for section in section_labels:
            if section.started and not section.ended:
                self._write_symbol(
                    f"{seg_name}_{dotless_type(section.name).upper()}_END",
                    ".")

        self._end_segment(segment)
Ejemplo n.º 4
0
def parse_segment_section_order(segment: Union[dict, list]) -> List[str]:
    default = options.get_section_order()
    if isinstance(segment, dict):
        return segment.get("section_order", default)
    return default
Ejemplo n.º 5
0
    def parse_subsegments(self, segment_yaml) -> List[Segment]:
        base_segments: OrderedDict[str, Segment] = OrderedDict()
        ret = []
        prev_start: RomAddr = -1
        inserts: OrderedDict[
            str, int
        ] = (
            OrderedDict()
        )  # Used to manually add "all_" types for sections not otherwise defined in the yaml

        self.section_boundaries = OrderedDict(
            (s_name, Range()) for s_name in options.get_section_order()
        )

        found_sections = OrderedDict(
            (s_name, Range()) for s_name in self.section_boundaries
        )  # Stores yaml index where a section was first found
        found_sections.pop(".text")

        if "subsegments" not in segment_yaml:
            return []

        # Mark any manually added dot types
        cur_section = None

        for i, subsection_yaml in enumerate(segment_yaml["subsegments"]):
            # rompos marker
            if isinstance(subsection_yaml, list) and len(subsection_yaml) == 1:
                continue

            typ = Segment.parse_segment_type(subsection_yaml)
            if typ.startswith("all_"):
                typ = typ[4:]
            if not typ.startswith("."):
                typ = f".{typ}"

            if typ in found_sections:
                if cur_section is None:
                    # Starting point
                    found_sections[typ].start = i
                    cur_section = typ
                else:
                    if cur_section != typ:
                        # We're changing sections
                        if found_sections[cur_section].has_end():
                            log.error(
                                f"Section {cur_section} end encountered but was already ended earlier!"
                            )
                        if found_sections[typ].has_start():
                            log.error(
                                f"Section {typ} start encounted but has already started earlier!"
                            )

                        # End the current section
                        found_sections[cur_section].end = i

                        # Start the next section
                        found_sections[typ].start = i
                        cur_section = typ

        if cur_section is not None:
            found_sections[cur_section].end = -1

        inserts = self.find_inserts(found_sections)

        for i, subsection_yaml in enumerate(segment_yaml["subsegments"]):
            # rompos marker
            if isinstance(subsection_yaml, list) and len(subsection_yaml) == 1:
                continue

            typ = Segment.parse_segment_type(subsection_yaml)
            start = Segment.parse_segment_start(subsection_yaml)

            # Add dummy segments to be expanded later
            if typ.startswith("all_"):
                ret.append(Segment(start, "auto", typ, "", "auto"))
                continue

            segment_class = Segment.get_class_for_type(typ)

            end = self.get_next_seg_start(i, segment_yaml["subsegments"])

            if (
                isinstance(start, int)
                and isinstance(prev_start, int)
                and start < prev_start
            ):
                log.error(
                    f"Error: Group segment {self.name} contains subsegments which are out of ascending rom order (0x{prev_start:X} followed by 0x{start:X})"
                )

            vram = None
            if start != "auto":
                assert isinstance(start, int)
                vram = self.get_most_parent().rom_to_ram(start)

            segment: Segment = Segment.from_yaml(
                segment_class, subsection_yaml, start, end, vram
            )
            segment.sibling = base_segments.get(segment.name, None)
            segment.parent = self

            for i, section in enumerate(self.section_order):
                if not self.section_boundaries[section].has_start() and dotless_type(
                    section
                ) == dotless_type(segment.type):
                    if i > 0:
                        prev_section = self.section_order[i - 1]
                        self.section_boundaries[prev_section].end = segment.vram_start
                    self.section_boundaries[section].start = segment.vram_start

            ret.append(segment)

            # todo change
            if typ in CODE_TYPES:
                base_segments[segment.name] = segment

            prev_start = start

        # Add the automatic all_ sections
        orig_len = len(ret)
        for section in reversed(inserts):
            idx = inserts[section]

            if idx == -1:
                idx = orig_len

            # bss hack TODO maybe rethink
            if section == "bss" and self.vram_start is not None:
                rom_start = self.rom_end
                vram_start = self.vram_start + self.rom_end - self.rom_start
            else:
                rom_start = "auto"
                vram_start = "auto"

            ret.insert(
                idx,
                (
                    Segment(
                        rom_start,
                        "auto",
                        "all_" + section,
                        "",
                        vram_start,
                    )
                ),
            )

        check = True
        while check:
            check = self.handle_alls(ret, base_segments)

        # TODO why is this necessary?
        if (
            self.section_boundaries[".rodata"].has_start()
            and not self.section_boundaries[".rodata"].has_end()
        ):
            assert self.vram_end is not None
            self.section_boundaries[".rodata"].end = self.vram_end

        return ret