One solution is to use the program published at COMPUTE! ISSUE 76 / SEPTEMBER 1986 / PAGE 100 :
http://www.atarimagazines.com/compute/issue76/AtariML.php
The program heavily utilizes the BASIC "self-programming trick".
First, let's explain the trick. An example - dynamically allocating a string of variable length - is located starting with line 31570:
PH 31570 GRAPHICS 0:POSITION 2,4:PRINT "31750 DIM TEMP$(";FILSIZ;"):RETURN"
FK 31580 PRINT "CONT":POSITION 2,0:POKE 842,13:STOP
FK 31590 POKE 842,12:GOSUB 31750
31570:
- clear screen (
GRAPHICS 0
).
- position the cursor leaving a little room above (
POSITION 2,4
)
- Output the text of the program line that is to be added/changed. In this case, that's creation (or on subsequent runs overwrite) of line 31750 which contains a subroutine, allocating space for a new variable, and returning.
31580:
- In the next line, output the command
CONT
- this command makes sense only in immediate context - used in a program it would trigger 'already running' error.
- Position the cursor at the topmost line of the screen.
- Perform a "magical"
POKE 842,13
- I'm not sure what's 'behind the scenes' - 842 is the ICAX1 register, but I only managed to find the meaning of its 2 and 3 (device open for read and write); not bit 0 which is toggled here.
- Perform 'STOP'. This is mostly equivalent to pressing BREAK - aborting the activity of the program, in a way that is resumable by the CONT instruction.
The moment the "Magical Poke" is executed Atari begins outputting the Return key repeatedly. The program is aborted before the cursor reaches the text on screen, so when it does, the computer is in immediate mode, but with "jammed Return". Whatever lines the cursor rides through, are executed as if they were typed in. In that case, that's the line preceded by the number - which gets written into the program - and then, the line CONT, which resumes execution from the next command after STOP. Which happens to be...
31590:
POKE 842,12
to cancel the cursor madness
GOSUB 31750
- execute the newly entered line.
Now, what the program actually does:
- open the binary file for reading. (31540)
- obtain file size (31560)
- allocate a string of length corresponding to the binary length (using the self-programming trick) (31570)
- load the binary into the memory location of the allocated string (31600)
- output the contents of the string, wrapped in context of new program lines and variable assignments. (31610)
- Enter them using the self-programming trick (31720),
- Erase self from memory, using the self-programming trick. (31720)
It's up to the user to save the remaining program containing the gibberish strings of machine code.
ax
/bx
/etc register names when you meaneax
/ebx
and so on, and judiciously sprinkle withdb 66h
anddb 67h
when you need to change operand and/or effective address sizes of the next instruction to 16 bits.