Skip to content

dos: keep a hunk file's 32-bit relocations with its seglist (GSLI_68KRELOCS) - #1855

Merged
Kalamatee merged 2 commits into
aros-development-team:masterfrom
terminills:m68k-1-dos
Oct 31, 2026
Merged

Kalamatee merged 2 commits into
aros-development-team:masterfrom
terminills:m68k-1-dos

Conversation

@terminills

@terminills terminills commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

This touches dos.library, so it needs your call; the m68kemu pull requests that follow build on it.

On a non-68k host LoadSeg() relocates a hunk file to the addresses of its own segments, and nothing can run it there. m68kemu copies the segments into its own memory and has to relocate them again, which needs the relocations the loader applied. This records the 32-bit relocations as the file groups them, one group per relocation block and target hunk (hunk, target, kind, and the offsets), in the seglist's segdata node, in the same allocation, and hands the table out through a new GetSegListInfo() tag, GSLI_68KRELOCS. The cost is four bytes a relocation plus a group header per block, for the life of the seglist, on the hosts where a hunk file can only be run through an emulator. A failed allocation marks the table lost instead of handing out a partial one. On 68k nothing is recorded and the tag is not answered. Nothing changes for callers that do not ask for the tag.

The structures and the three kinds are in dos/doshunks.h next to the hunk types; the tag stays in dos/dostags.h with the other GetSegListInfo() tags, and the autodoc describes it.

Two commits. The first is a one-line loader fix the test found: the 16-bit relocation count of a HUNK_RELOC32SHORT, HUNK_DREL32 or HUNK_ABSRELOC16 block was byte-swapped as a longword, so on a little-endian host it read as zero and the block could not be parsed. The second is the table.

Test: developer/debug/test/dos/seglistrelocs writes a two-hunk file with one relocation of each kind (HUNK_RELOC32, HUNK_ABSRELOC16, HUNK_RELRELOC32), loads it, checks the three relocated longwords against the segment addresses and the table against the file, on 68k that the tag is not answered, and that a relocation count the table cannot hold (above 2^31, and above 2^30 where the allocation size would overflow) fails the load instead of hanging it. pc-x86_64 in QEMU (alpha18c5 image with this dos.library): all twelve checks pass, SEGLISTRELOCS PASS; the changed files also compile for pc-i386.

JJDSNT added a commit to JJDSNT/AROS that referenced this pull request Oct 27, 2026
Record the three kinds of programs, the per-run ownership rule for
system-friendly programs that use the chipset (display, Paula, CIAs,
interrupts, input), and the concrete points to agree with the high-level
pull request series aros-development-team#1855-aros-development-team#1859.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014XzsDvVVNZd96oEtyVMjbi
JJDSNT added a commit to JJDSNT/AROS that referenced this pull request Oct 27, 2026
…ries

A short write-up for the author of the high-level m68kemu series
(aros-development-team#1855-aros-development-team#1859): where the two directions meet, the two designs for
system-friendly programs that use the chipset, and the points that would
help either way. RIGEL.md holds the details.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014XzsDvVVNZd96oEtyVMjbi
@Kalamatee

Copy link
Copy Markdown
Member

Blocking issues:

  • HUNK_RELRELOC32 relocations are not recorded. The description says it records every 32-bit relocation the loader applies. The loader patches 32-bit words in three places: HUNK_RELOC32, the shared block for RELOC32SHORT, DREL32 and ABSRELOC16, and HUNK_RELRELOC32. The PR hooks only the first two. RELRELOC32 stores the target hunk's base minus the patched hunk's own base, so the value depends on where both hunks sit. If an emulator copies the segments to new addresses without redoing these, every such word points to the wrong place, with no error. The fix needs a third kind in the table, because this formula fits neither of the two kinds the PR defines.
  • The m68k-amiga build breaks. arch/m68k-amiga/c/AROSBootstrap.c includes the same loadseg.h header and defines its own empty register_hunk with the old four-argument signature. Once the header declares six arguments, that file stops compiling with a conflicting-types error. The m68k loader also calls the function with six arguments. The PR was only built for pc-x86_64 and pc-i386. The empty stub in AROSBootstrap needs the new signature too.

@terminills

Copy link
Copy Markdown
Contributor Author

Both fixed, and the branch is rebased onto master past #1922.

  1. HUNK_RELRELOC32 is recorded as a third kind, HUNKRELOC_BASE: word = target base + original - base of the hunk holding the word. The m68kemu side in m68kemu.library: run SysInfo, ReAction programs, Directory Opus 5 and Blitz programs #1905 replays it with that formula. The description now names the three kinds and where each comes from.
  2. arch/m68k-amiga/c/AROSBootstrap.c's empty register_hunk() takes the six arguments, and loadseg.h includes <dos/dostags.h> so the struct is in scope there. I have no m68k toolchain on this machine, so that file is checked by reading only; the pc-x86_64 build and the m68kemu regression ran with the new dos.library.

@Kalamatee

Copy link
Copy Markdown
Member
  • Memory cost. Each relocation still takes 16 bytes and stays for the seglist's whole life. That applies to every hunk file loaded on a non-68k host, including data-only hunk files such as keymaps.
  • Header placement. The relocation structures and kind constants still live in dos/dostags.h rather than dos/doshunks.h, and GetSegListInfo's autodoc does not mention the new tag.
  • m68k answers the tag. On 68k builds the tag is still acknowledged with an empty table, which looks the same as a file with no relocations.

@terminills

Copy link
Copy Markdown
Contributor Author

All three, in the one commit (rebased on master):

  1. Memory: the table is now the file's own shape, one group per relocation block and target hunk with the 32-bit offsets, so a relocation costs four bytes plus a group header per block instead of sixteen, still in the segdata node's allocation and freed with the seglist. It is only kept where a hunk file can only run through an emulator, which is every non-68k host, so I did not add a switch; if you would rather have one, a LoadSeg tag is the obvious place.
  2. Placement: struct HunkRelocGroup, struct HunkRelocTable and the HUNKRELOC_* kinds are in dos/doshunks.h with the hunk types; GSLI_68KRELOCS stays in dos/dostags.h with the other tags, and GetSegListInfo()'s autodoc now lists the three tags and what each returns.
  3. 68k: nothing is recorded and the tag falls through to "not acknowledged", so a 68k caller gets 0, not an empty table. The m68k-amiga bootstrap stub takes the new argument.

Test: developer/debug/test/dos/seglistrelocs, a two-hunk file with one relocation of each kind, loaded and checked against the segment addresses and the table; it also checks the 68k behaviour when built for 68k. Its first run failed on the ABSRELOC16 relocation and showed a loader bug on master: the 16-bit count of a RELOC32SHORT/DREL32/ABSRELOC16 block goes through AROS_BE2LONG, so any count below 256 reads as zero and the block is misparsed from there. That is a one-word fix (AROS_BE2WORD) and is in this commit, since the test covers it; say if you want it on its own. pc-x86_64 in QEMU: all ten checks pass, SEGLISTRELOCS PASS; the three dos files and the test compile for pc-i386. m68kemu (#1905) reads the grouped table; its regression is unchanged.

@Kalamatee

Copy link
Copy Markdown
Member

Thanks, all three points are addressed. Built for amiga-m68k (dos.library, libloadseg, AROSBootstrap) and ran seglistrelocs on pc-x86_64 in QEMU: all ten checks pass. Against master the same test fails the ABSRELOC16 check, which confirms the RELOC32SHORT/DREL32/ABSRELOC16 count byte-swap bug. Please split that one-line loader fix into its own commit, as it is independent of the table.

One issue to fix before merging:

acc_room() can loop forever on a corrupt relocation count. The HUNK_RELOC32 count is a full 32-bit value from the file. If the first block claims more than 0x80000000 entries, "ncap *= 2" overflows to 0 and the while loop never ends, so LoadSeg() hangs where it used to fail at end of file. Counts between 0x40000000 and 0x80000000 overflow "ncap * elem" instead. Please cap the count (for example at the hunk size / 4) or check for overflow in acc_room() and mark the list lost.

Minor:

  • On m68k, internalloadseg_support.c warns "'struct HunkRelocList' declared inside parameter list", because internalloadseg.h only declares the struct for non-68k. A forward declaration outside the #ifndef __mc68000 block fixes it.
  • seglistrelocs is listed between readitem and readitemloop in mmakefile.src, out of alphabetical order.

The count that follows the first word of these blocks is a 16-bit
word, like the first one, but the loader byte-swapped it as a
longword. On a little-endian host that leaves zero, so the block's
relocations are not applied and the words that follow are parsed as
the next block. The seglistrelocs test added with the relocation table
fails its ABSRELOC16 check on master because of this.
…RELOCS)

On a non-68k host LoadSeg() relocates a hunk file to the addresses of
its own segments and nothing can run it there; an emulator copies the
segments into its own memory and needs to relocate them again. Record
the 32-bit relocations the loader applies, as the file groups them (one
group per relocation block and target hunk: hunk, target, kind, and the
offsets), in the seglist's segdata node, in the same allocation, and
hand the table out through a new GetSegListInfo() tag. The cost is four
bytes a relocation and a group header for each block, for the life of
the seglist, on the hosts where a hunk file can only be run through an
emulator. A failed allocation marks the table lost rather than handing
out a partial one. On 68k nothing is recorded and the tag is not
answered, as the segments run where they were loaded.

The three kinds are the three ways the loader patches a longword:
HUNK_RELOC32 and RELOC32SHORT add the target hunk's base; ABSRELOC16
adds it less the address of the longword; HUNK_RELRELOC32 adds it less
the base of the hunk holding the longword.

The structures and kinds are in dos/doshunks.h with the hunk types, the
tag in dos/dostags.h with the other GetSegListInfo() tags, which the
autodoc now describes. The m68k-amiga bootstrap has an empty
register_hunk() of its own, which takes the new argument too.

The test developer/debug/test/dos/seglistrelocs writes a two-hunk file
with one relocation of each kind, loads it, checks the relocated
longwords and the table, that 68k does not answer the tag, and that a
relocation count the table cannot hold fails the load instead of
hanging or overflowing it.
@terminills

Copy link
Copy Markdown
Contributor Author

Done, rebased on master, two commits:

  1. dos: read a RELOC32SHORT, DREL32 or ABSRELOC16 block's count as a word - the one-line loader fix on its own.
  2. dos: keep a hunk file's 32-bit relocations with its seglist (GSLI_68KRELOCS) - the table, with:
    • acc_room() checks used + need for wrap and against ~0UL / elem before it grows, and grows to exactly the wanted size once doubling would pass it, so neither the loop nor ncap * elem can overflow; a count the table cannot hold marks the list lost and the loader fails at end of file as before. seglistrelocs now also loads the same file with a HUNK_RELOC32 count of 0x80000001 and of 0x40000001 and checks that LoadSeg() fails both.
    • struct HunkRelocList; forward-declared outside the #ifndef __mc68000 block. I have no m68k toolchain here, so I checked it with the i386 compiler and -D__mc68000: internalloadseg_support.c warns with the previous header and not with this one.
    • seglistrelocs moved after seektest in the dos test mmakefile.

pc-x86_64 in QEMU (alpha18c5 image with this dos.library): all twelve checks pass, SEGLISTRELOCS PASS. With the previous dos.library the same test prints the first ten and hangs on the 2^31 count, as you said. The changed files also compile for pc-i386.

#1905 is rebased onto these two commits.

@Kalamatee
Kalamatee merged commit b634cb3 into aros-development-team:master Oct 31, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants