English Amiga Board


Go Back   English Amiga Board > Coders > Coders. Asm / Hardware

 
 
Thread Tools
Old 03 May 2022, 22:48   #1
hop
Registered User
 
Join Date: Apr 2019
Location: UK
Posts: 172
vasm -pic with -Fbin

I'm trying to learning how to load and execute code from a bootblock and struggling to get the vasm -pic option to warn (error) when it detects absolute code.

The bootblock allocates memory and uses trackdisk IO request to load INCBIN'd code from a track on disk. The binary code is build from

Code:
	ORG 0

	; Infinite loop flashing the screen
	clr.w d0
loop:
	addq.w	#1,d0
	move.w	d0,$dff180	; flash screen
	cmp.w	#$fff,d0
	bne	loop
	clr.w	d0
	bra loop  ; OK: PC-relative branch

	jmp loop  ; BAD: Jump to absolute address. Not position independent code
with

Code:
vasmm68k_mot.exe -pic -Fbin -o intermediates/TrackdiskMain.bin -L %Build%/TrackdiskMain.list -Lall -wfail TrackdiskMain.asm
I was expecting -pic to catch that jmp instruction and warn and error due to -wfail.

I realise at some point I may have to assemble load files and fix up relocations in the loaded hunks, but for now I'd just like to be able to catch any non-position independent code at build time.

(Attached full source for more context)
Attached Files
File Type: 7z TrackdiskBootblock.7z (2.3 KB, 35 views)
hop is offline  
Old 03 May 2022, 23:27   #2
robinsonb5
Registered User
 
Join Date: Mar 2012
Location: Norfolk, UK
Posts: 1,153
What the -pic flag actually does is disallow relocations, not absolute addresses. Because you've specified the starting location with ORG, it knows exactly where in memory the label "loop" will be, so no relocation is required.

If you remove the ORG you'll see that there's still no error - but if you look at the generated code, the JMP has been replaced with an equivalent BRA in order to satisfy the -pic constraint.

If you place a large ds.b immediately before the jmp, so that the branch target is more than 32k away then you'll get an error message, since it now can't satisfy the -pic constraint.
robinsonb5 is offline  
Old 03 May 2022, 23:50   #3
hop
Registered User
 
Join Date: Apr 2019
Location: UK
Posts: 172
Thanks. I had tried removing the ORG and was surprised it didn't error then. I didn't realise the assembler was doing so much work silently behind the scenes!

While I'm learning these fundamentals it might be helpful if vasm didn't silently change my instructions for me and instead informed me if code is illegal. Is there an option for this?
hop is offline  
Old 04 May 2022, 00:03   #4
robinsonb5
Registered User
 
Join Date: Mar 2012
Location: Norfolk, UK
Posts: 1,153
Quote:
Originally Posted by hop View Post
While I'm learning these fundamentals it might be helpful if vasm didn't silently change my instructions for me and instead informed me if code is illegal. Is there an option for this?
I guess the easiest way would be the specify the -no-opt flag, so you get exactly the code you asked for. (Without it, the JMP will be turned into a BRA even without the -pic option just because it's faster and smaller code.)
robinsonb5 is offline  
Old 04 May 2022, 00:09   #5
hop
Registered User
 
Join Date: Apr 2019
Location: UK
Posts: 172
Code:
error 35 in line 14 of "TrackdiskMain.asm": relocation not allowed
>       jmp loop  ; BAD: Jump to absolute address. Not position independent code
That's more like it. Thank you very much.
hop is offline  
Old 04 May 2022, 01:08   #6
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by hop View Post
I realise at some point I may have to assemble load files and fix up relocations in the loaded hunks
If you want to do that, then there are simpler executable formats with relocations than the AmigaOS hunk format.

For example you could generate Atari TOS executables instead, which have a much simpler relocation table. Or use vlink to output "rawbin" or "rawseg" format with option -q, which will append a similar reloc table to a raw binary file. I did use "rawseg" in my games, because I wanted to support multiple segments (Chip and Fast). Otherwise "rawbin" is easier to use.
phx is offline  
Old 04 May 2022, 14:24   #7
hop
Registered User
 
Join Date: Apr 2019
Location: UK
Posts: 172
Thanks. I'll definitely give rawbin and rawseg a go, if I can overcome my fear of the linker scripts ;-).

I guess rawbin1 is the one to use and rawbin2 is aimed at another machine.

Now that I understand the hunk format, loaders, bootblocks and trackdisk, it might be a good exercise to write a tool to take a simple hunk load file and create a bootblock trackdisk loader disk image from it. It might be fun to try the reverse too and "one file" a disk with custom bootblock loader.
hop is offline  
Old 05 May 2022, 13:50   #8
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by hop View Post
Thanks. I'll definitely give rawbin and rawseg a go, if I can overcome my fear of the linker scripts ;-).
Fear not! With
rawbin
the default linker script should usually suffice (
rawseg
is another topic).
vlink -brawbin1 -q myobj.o
is all it needs for a first test.

Quote:
I guess rawbin1 is the one to use and rawbin2 is aimed at another machine.
The only difference is that
rawbin2
can output multiple files, when there are gaps larger than 16 bytes in your code (e.g. as a result from multiple
org
directives).
rawbin1
just fills the gaps with zero-bytes.
phx is offline  
Old 05 May 2022, 14:22   #9
hop
Registered User
 
Join Date: Apr 2019
Location: UK
Posts: 172
I've read the vlink rawbin1 docs, but I'm a little confused. My test program has a single section with a single reference to a label in the same section. I can see that when linking with with -q the file grows by 5 bytes: 00 00 00 01 08. This means that there is a single relocation at offset 8 - this matches the disassembly so great.

But how would I know the offset of the reloc table in the binary when I load it? I guess maybe this is the part of the explaination I don't understand.
You may reference it by using the __end symbol, which marks the end of the bss section.
I don't know how to get at a symbol when the binary is loaded, or what the "bss section" is (my code by definition is a single CODE section)?
hop is offline  
Old 05 May 2022, 15:57   #10
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by hop View Post
You may reference it by using the __end symbol, which marks the end of the bss section.
I don't know how to get at a symbol when the binary is loaded,
Maybe bad wording of a non-native speaker again. It just means that the default linker script automatically defines the symbol
__end
, which marks the address after your last byte. When you do the relocation in your startup code you can use this symbol to find the table. For example:
Code:
       xref    __end

       lea     __end,a0
       move.l  (a0)+,d0  ; reloc table size in bytes
       ...
Quote:
or what the "bss section" is (my code by definition is a single CODE section)?
In the rawbin default linker script "bss" is the last section. But it doesn't matter. When there is no "bss" then
__end
follows after "code", or whatever. In any case it should mark the end of your whole program.
phx is offline  
Old 05 May 2022, 16:17   #11
hop
Registered User
 
Join Date: Apr 2019
Location: UK
Posts: 172
Thanks but I'm still not quite there. This is the process I envisage. Please could you tell me where I am going wrong?

1. Write main.asm, the code that the bootblock will load, relocate and execute.
2. Build main.asm with -rawbin1 -q -o main.bin
3. Write bootblock.asm with INCBIN "main.bin" at f.ex offset of track 1
4. bootblock.asm boot code reads main.bin tracks from disk into memory (trackdisk IO)
5. Somehow access __end symbol from incbined main.bin to find relocation table
6. Apply relocations to loaded code
7. JMP to loaded code.

I cannot see how the __end symbol can be accessed from an incbined binary, so perhaps this is not the correct process. Thanks.

Last edited by hop; 05 May 2022 at 16:17. Reason: Formatting
hop is offline  
Old 05 May 2022, 16:51   #12
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Your envisioned procedure looks completely fine!

Quote:
Originally Posted by hop View Post
I cannot see how the __end symbol can be accessed from an incbined binary
It's not becoming clear where you want to access
__end
. Point 5 seems to me as if you want to access it from within the source code of main.asm. Which would be fine, and was shown in the example above.
But this last sentence seems as if you want to access
__end
within the source code of bootblock.asm? May I ask why? To keep main.bin shorter?

If you absolutely want to do that, then there are still two solutions:
  1. Use rawseg instead, which allows writing a separate relocation table file, which you also can INCBIN separately in your disk image.
  2. Write the size of main's code into the first longword of main.bin to help your bootblock code.
For the second option you could do the following at the first line of main.asm:
Code:
        dc.l    __end-*
Then your bootblock-code can use this offset to find the reloc table.
phx is offline  
Old 05 May 2022, 17:52   #13
hop
Registered User
 
Join Date: Apr 2019
Location: UK
Posts: 172
Quote:
Originally Posted by phx View Post
It's not becoming clear where you want to access
__end
. Point 5 seems to me as if you want to access it from within the source code of main.asm. Which would be fine, and was shown in the example above.
But this last sentence seems as if you want to access
__end
within the source code of bootblock.asm? May I ask why? To keep main.bin shorter?
EDIT: As you imply, bootblock.asm is the disk image assembly file.

Yes. I imagined bootblock.asm simply incbining main.bin and handling the relocations. It just seems to make sense for the loader (bootblock.asm) to do the loading using the relocation table, and the load file (main.asm) to simply be a payload (e.g. game code). I'm struggling to get my head around the load file containing code to relocate itself.

Quote:
Originally Posted by phx View Post
If you absolutely want to do that, then there are still two solutions:
  1. Use rawseg instead, which allows writing a separate relocation table file, which you also can INCBIN separately in your disk image.
  2. Write the size of main's code into the first longword of main.bin to help your bootblock code.
For the second option you could do the following at the first line of main.asm:
Code:
        dc.l    __end-*
Then your bootblock-code can use this offset to find the reloc table.
Thanks for these solutions. I'll try option 2 to prove this process out, because it seems like the loader vs loadfile separation of concerns is preserved this way.

However, I think rawseg is ultimately the way to go, because most (all) of my applications/executables will have multiple sections: at least CODE (any) and BSS/DATA (Chip). Do I have to use a linker script for this case? I think I saw you posted one in the Trackmo tech thread. Is that ready to go?

Last edited by hop; 05 May 2022 at 17:54. Reason: typo
hop is offline  
Old 05 May 2022, 21:06   #14
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by hop View Post
I'm struggling to get my head around the load file containing code to relocate itself.
The relocator would be at the beginning of the program and use PC-relative addressing modes. And if
lea  __end(pc),a0
doesn't work, because your program is larger than 32K, you can still store the offset as
dc.l __end-*
somewhere in reach.

Quote:
However, I think rawseg is ultimately the way to go, because most (all) of my applications/executables will have multiple sections: at least CODE (any) and BSS/DATA (Chip).
Agreed. You want to use rawseg for more than one segment.

Quote:
Do I have to use a linker script for this case?
Hmm. Maybe not. The default script for rawseg defines a "text" segment (with CODE) and a "data" segment (with DATA and BSS). So you could be fine.

Quote:
I think I saw you posted one in the Trackmo tech thread. Is that ready to go?
Glad that you found it. This one could work as well, although the "chip" segment only contains sections named "chipmem". So you either have to define you Chip-RAM sections like
section chipmem,data
or change the script. Note, that the section directive's "chip" attribute has no meaning when the output is not hunk-format.
An advantage over the default script is support for the small-data model, in case you need that.
phx is offline  
Old 05 May 2022, 21:28   #15
hop
Registered User
 
Join Date: Apr 2019
Location: UK
Posts: 172
Quote:
Originally Posted by phx View Post
The relocator would be at the beginning of the program and use PC-relative addressing modes.
Thanks. I’ll try this out. Does this count as naughty self modifying code? If the relocation code is potentially next to the relocated code, would any CPU instruction cache need to be flushed after the relocations are applied?
hop is offline  
Old 06 May 2022, 00:16   #16
phx
Natteravn
 
phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,496
Quote:
Originally Posted by hop View Post
Thanks. I’ll try this out. Does this count as naughty self modifying code?
No. This is absolutely necessary self modification.

Quote:
If the relocation code is potentially next to the relocated code, would any CPU instruction cache need to be flushed after the relocations are applied?
Yes, of course! For 68020+ you should always flush the data cache to memory and invalidate the instruction cache. No matter if doing the relocation from main.asm or from bootblock.asm.
phx is offline  
Old 14 May 2022, 10:23   #17
hop
Registered User
 
Join Date: Apr 2019
Location: UK
Posts: 172
Quote:
Originally Posted by phx View Post
Write the size of main's code into the first longword of main.bin to help your bootblock code ... do the following at the first line of main.asm:
Code:
        dc.l    __end-*
Then your bootblock-code can use this offset to find the reloc table.
I've been chipping away at this rawbin loader and got something working thanks. This is what I've come up with:

Code:
<bootblock header>
<use trackdisk to load rawbin file with prefixed reloc table offset>

	; apply the relocation table
	movea.l a4,a0       ; A0 <- address of loadfile

	; read reloc table offset
	; n.b: -rawbin1 -q still appends a relocation table to the binary even if there are no entries.
	; In that case the table size longword would just be $00000000
	move.l (a0),d0     ; D0 <- reloc table offset

	; Read first longword
	movea.l a4,a1       ; A1 <- address of loadfile
	adda.l d0,a1        ; A1 <- reloc table
	move.l (a1)+,d1     ; D1 <- reloc table size in bytes. A1 <- address of first byte in bytestream

	; Read bytestream and apply relocations
relocLoop
	tst.l d1             ; end of bytestream?
	beq relocLoopEnd     ; yes? Done

	subq.l #1,d1      ; dec bytecount

	; read byte
	; - A byte between 1 and 255 represents the distance in bytes to the *next* relocation offset (i.e. offset from previous)
	;   (starts at zero).
	moveq #0,d0
	move.b (a1)+,d0
	bne reloc

	; A zero byte indicates that the following word contains a distance greater than 255. 
	; Read longword offset
	; n.b. Can't do move.l (a1)+,d0 because the 68000 can only read words (and longwords) from 
	; word-aligned (even) addresses (68020+ can actually read from odd addresses at the expense of performance)
	subq #4,d1 ; bytecount -= sizeof(long)

	move.b (a1)+,d0  ; read MSB $XX......
	lsl.l #8,d0
	move.b (a1)+,d0
	lsl.l #8,d0
	move.b (a1)+,d0
	lsl.l #8,d0
	move.b (a1)+,d0  ; read LSB $......XX

reloc	adda.l d0,a0    ; A0 <- address of longword to relocate
	move.l (a0),d0  ; D0 <- relative address
	add.l a4,d0     ; Add loaded program start address D0 <- absolute address
	move.l d0,(a0)  ; store absolute address
	
	bra relocLoop ; next offset

relocLoopEnd

	; Invalidate the instruction cache for 68020+ CPUs
	; Required in case any of the relocated code is in the cache and needs to be refetched from RAM
	IF MIN_SUPPORTED_OS_VERSION>=37
	jsr _LVOCacheClearU(a6) ; V37 (Kickstart 2.04) Cannot be called on KS1.3
	ELSE
	btst #AFB_68020,AttnFlags+1(a6)
	beq executeLoadfile
	lea invalidateInstructionCache(pc),a5  ; Supervisor userfunc
	jsr _LVOSupervisor(a6)
	ENDIF

executeLoadfile
	adda.l #4,a4 ; skip relocation table offset longword
	jmp (a4)

error	moveq   #$FFFFFFFF,d0  ; boot failure code
	rts
I think this is OK. I got caught out trying to read a longword from an odd address at first. The solution doesn't seem very elegant, but I guess this isn't really performance critical code. I wasn't sure about JMP (a4) or moving the entry point into A1, zero into d0 and RTS from bootblock.
hop is offline  
Old 14 May 2022, 11:42   #18
a/b
Registered User
 
Join Date: Jun 2016
Location: europe
Posts: 1,039
Quote:
Originally Posted by hop View Post
subq.l #1,d1 ; dec bytecount
...
; subq #4,d1 ; bytecount -= sizeof(long)
subq.l #4,d1 ; bytecount -= sizeof(long)
Unsized instructions (in case there are multiple options, assembler specific of course) are usually resolved as .w, so it's better to use .l both times.

Speed/size is probably not an issue here, but I would write that loop like this (2 bytes shorter, slightly faster):
Code:
	; Read bytestream and apply relocations
	bra.b	relocNext
relocLoop
	; read byte
...
relocNext
	subq.l #1,d1      ; dec bytecount, end of bytestream?
	bgt.b	relocLoop
Odd address handling could be done e.g. through stack or a 32-bit aligned memory buffer to avoid slow 4x8 shifts:
Code:
	subq.l	#4,a7			; once only
	move.l	a7,a2			;
...
	move.b	(a1)+,(a2)+
	move.b	(a1)+,(a2)+
	move.b	(a1)+,(a2)+
	move.b	(a1)+,(a2)+
	move.l	-(a2),d0
...
	addq.l	#4,a7			; once only
a/b is offline  
Old 14 May 2022, 11:54   #19
hop
Registered User
 
Join Date: Apr 2019
Location: UK
Posts: 172
Thanks. I'll try those changes. I guess size could become important when this is extended to load multiple sections if the code stays in the bootblock.
hop is offline  
Old 15 May 2022, 16:12   #20
hop
Registered User
 
Join Date: Apr 2019
Location: UK
Posts: 172
Quote:
Originally Posted by phx View Post
The default script for rawseg defines a "text" segment (with CODE) and a "data" segment (with DATA and BSS).
I have a first pass rawseg loader working now. I'd like to look at this script for reference. The vlink website seems to be down and couldn't see it on the GitHub. Where can it be found?
hop is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
Anyone help with a pic of wb 3.1 on 4:3 tv? cypher007 support.Hardware 14 30 June 2020 08:18
Wave Pic pmc Coders. Tutorials 18 03 June 2009 18:37
It's... Request-a-pic! Shoonay EAB's competition 42 05 July 2008 15:03
This may be handy for some ( BIG PIC ) synchro Amiga scene 27 27 June 2004 22:00

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 09:58.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.26486 seconds with 16 queries