Author Topic: Can you code a Z80 program with zero absolute addresses?  (Read 1340 times)

0 Members and 1 Guest are viewing this topic.

Offline zhulien

  • 6128 Plus
  • ******
  • Posts: 920
  • Country: au
  • aka Vorax
    • 8bitology
    • Awards
here is a challenge for you... Can you code a Z80 program with zero absolute addresses?

like
0
No reactions

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 1.156
  • Country: fr
    • urban exploration
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #1 on: 17:53, 26 August 21 »
YES  8)
like
0
No reactions
use RASM, the best assembler ever made :p

I will survive

Offline zhulien

  • 6128 Plus
  • ******
  • Posts: 920
  • Country: au
  • aka Vorax
    • 8bitology
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #2 on: 17:55, 26 August 21 »
other than something simple like an ret or a maths operation followed by ret?
like
0
No reactions

Offline Animalgril987

  • Supporter
  • CPC6128
  • *
  • Posts: 231
  • Country: gb
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #3 on: 19:39, 26 August 21 »
Certainly. Some game loaders do it, so that their code is relocatable (because HIMEM) will be different for the different CPCs.
like
0
No reactions


Offline norecess

  • CPC6128
  • ****
  • Posts: 278
  • Country: ca
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #5 on: 21:10, 26 August 21 »
If my memory is still good, I think DAMS assembler (ADAM in UK: https://www.cpc-power.com/index.php?page=detail&num=4248) is entirely relocatable. It's considered as a big program for the Amstrad CPC.
« Last Edit: 21:11, 26 August 21 by norecess »
like
0
No reactions

Offline Zik

  • CPC464
  • **
  • Posts: 29
  • Country: fr
  • Amstrad 6128plus
    • Quasar CPC
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #6 on: 00:03, 27 August 21 »
Can you code a Z80 program with zero absolute addresses?
Absolutely!
like
0
No reactions

Offline zhulien

  • 6128 Plus
  • ******
  • Posts: 920
  • Country: au
  • aka Vorax
    • 8bitology
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #7 on: 14:20, 27 August 21 »
how does DAMS achieve this?


The way i thought of doing it, perhaps is too complicated an approach, was to have a GUID in the code, search all memory for the GUID, from that GUID calculate where it was found and we can now calculate where we are actually executing then to update jump tables based on an offset (where we assembled the jump table from vs where we are currently executing) and that all calls are jumps via the recalculated jump tables. 


Is there a better way?
like
0
No reactions

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 1.156
  • Country: fr
    • urban exploration
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #8 on: 14:25, 27 August 21 »

"easy" way: no call, no jump, no memory variable, only relative jumps
or use a relocation table, patch the code, run the code anywhere
like
0
No reactions
use RASM, the best assembler ever made :p

I will survive

Offline m_dr_m

  • 464 Plus
  • *****
  • Posts: 326
  • Country: gb
  • http://orgams.wikidot.com/
    • OrgaMS!
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #9 on: 14:54, 27 August 21 »
Yep, DAMS does it via a relocation table. No calls in such a big tool would be rather challenging (especially considering the small footprint of dams). Well, Orgams's z80 emulation for step by step debugging doesn't use calls, to be both fast and transparent.
like
0
No reactions

Offline andycadley

  • Supporter
  • 6128 Plus
  • *
  • Posts: 1.022
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #10 on: 15:48, 27 August 21 »

Traditionally with something like:

CALL pchl ; store PC in HL


....


pchl: POP HL
JP (HL)
like
0
No reactions

Online eto

  • Supporter
  • 6128 Plus
  • *
  • Posts: 516
  • Country: de
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #11 on: 21:28, 27 August 21 »
CALL pchl ; store PC in HL

isn't pchl then absolute?
like
0
No reactions

Offline scruss

  • CPC664
  • ***
  • Posts: 106
  • Country: ca
    • index.php?action=treasury
    • We Saw a Chicken ...
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #12 on: 22:13, 27 August 21 »
I'm told that Richard Russell's Z80 floating point library (used on the Z88 and later versions of BBC BASIC for Z80 machines) is relocatable, fully re-entrant and uses no storage outside the stack. I'm pretty sure it's using a jump block though, as using JR throughout would be complex.
like
0
No reactions

Offline andycadley

  • Supporter
  • 6128 Plus
  • *
  • Posts: 1.022
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #13 on: 23:05, 27 August 21 »
isn't pchl then absolute?
Well it depends on how strict you want to be about it. You could write the instructions to a fixed location (e.g. the screen or one of the RST points) first. Or pass dummy parameters from BASIC, writing the PCHL routine to (IX) via a series of direct instructions and then doing a CALL (IX) by the combination PUSH IX; RET


Got to be said though that writing fully relocatable code in Z80 is enormously hard work. The CPU just isn't really designed for it. You really want Register Indirect addressing on absolutely every type of instruction as well as something like LEA to calculate addresses.
like
0
No reactions

Offline GUNHED

  • 6128 Plus
  • ******
  • Posts: 2.909
  • Country: de
  • Reincarnation of TFM
    • FutureOS - The quickest OS for the CPC and Plus
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #14 on: 06:52, 28 August 21 »
here is a challenge for you... Can you code a Z80 program with zero absolute addresses?
Under FutureOS quite some apps start at &0000.  :)
like
0
No reactions
http://futureos.de --> Get the revolutionary FutureOS (Update: 2021.01.24)
http://futureos.cpc-live.com/files/LambdaSpeak_RSX_by_TFM.zip --> Get the RSX-ROM for LambdaSpeak :-) (Updated: 2021.07.15)

Online eto

  • Supporter
  • 6128 Plus
  • *
  • Posts: 516
  • Country: de
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #15 on: 13:03, 28 August 21 »
Well it depends on how strict you want to be about it.

Well... I think if the question has at its core the restriction "zero absolute addresses". Once you soften this, you answer a totally different question.
like
0
No reactions

Offline zhulien

  • 6128 Plus
  • ******
  • Posts: 920
  • Country: au
  • aka Vorax
    • 8bitology
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #16 on: 13:25, 28 August 21 »

Since we cannot use an absolute address, we cannot know where our code or even labels are - we can search for our code. An example is here, we found our code id 'AGUID' (it could be a real guid if you want longer code). After having our one known found absolute address, we can now modify it to put a call to a nearby function that get's the PC. Having got the PC we can for example find the absolute address to a table of relative function offsets. Finally we then go to our actual code logic with IY having the absolute address of the table of relative function offsets. I have coded a relocatable call, but... of course in this example it breaks the rule to call it 3 times as it itself should not be an absolute address.


I think it is possible to continue with the route I have shown as an example, but instead of having a relocatable call, basically jump relative to the offsets in the table that is known. Yes, the code will be spaghetti code, and of course there is no recursion easily and no subroutines in the normal sense, the functions would essentially be using looked up JRs to make an equivalent to a call, and continue their flow with other looked up JRs rather than returning. There are definitely a lot better ways of doing things and even by having a single known service function such as the relocatable_call demonstrated, it could be easily possible to make everything else relocatable.


Any imrpovements?  Can we make a fully self-relocating code that runs from any memory location without a separate loader?

Code: [Select]

ORG #4000


JR FINDCODE


CODE_ID: TEXT "AGUID"
PCISHERE: JR GOTPC


GETPC: POP HL ; GET PC
PUSH HL
RET


GOTPC: LD BC, TAB_ADDRESSES - PCISHERE + 2
ADD HL, BC
PUSH HL
POP IY ; IY = ADDRESS OF TAB_ADDRESSES


JR ENTRY






; FIND SOME GUID
FINDCODE: LD BC, 0 ; WE WILL LATER OVERWRITE THE GUID TO BE A CALL
FINDLOOP: PUSH BC ; TO GETPC WHICH IS A KNOWN NUMBER OF BYTES FROM
POP HL ; THE CODE_ID
LD A, (HL)
CP 'A'
JR NZ, FINDNEXT


INC HL
LD A, (HL)
CP 'G'
JR NZ, FINDNEXT


INC HL
LD A, (HL)
CP 'U'
JR NZ, FINDNEXT


INC HL
LD A, (HL)
CP 'I'
JR NZ, FINDNEXT


INC HL
LD A, (HL)
CP 'D'
JR NZ, FINDNEXT
JR Z, FOUND


FINDNEXT: INC BC
JR FINDLOOP


; NOW WE KNOW THE ADDRESS OF THE CODE_ID
; LETS MODIFY IT TO BECOME A CALL TO GETPC
; BEFORE JUMPING TO IT
FOUND: PUSH BC ; BC = ADDRESS OF CODE_ID
PUSH BC
PUSH BC
POP HL ; HL = ADDRESS OF CODE_ID


; GETPC IS 7 BYTES BEYOND CODE_ID SO ADD 7 TO HL
LD BC, 7
ADD HL, BC


PUSH HL
POP DE ; DE = ADDRESS OF GETPC


POP HL ; HL = ADDRESS OF CODE_ID AGAIN


LD A, #CD ; A BECOMES CALL
LD (HL), A
INC HL


LD A, E ; G BECOMES PART OF GETPC ADDRESS
LD (HL), A
INC HL


LD A, D ; U BECOMES PART OF GETPC ADDRESS
LD (HL), A
INC HL


LD A, 0 ; I BECOMES NOP
LD (HL), A
INC HL


LD A, 0 ; D BECOMES NOP
LD (HL), A


POP BC ; BC = GETPC


JR CODE_ID ; JUMP TO CODE ID, WHICH THEN CALLS GETPC AND JUMPS TO
; GOTPC


TAB_ADDRESSES:
DW FUNC0-TAB_ADDRESSES, FUNC1-TAB_ADDRESSES, FUNC2-TAB_ADDRESSES


ENTRY: LD A,0 ; ENTRY POINT TO OUR APPLICATION
CALL RELOCATABLE_CALL ; RELOCATABLE CALL TO FUNCTION 0
HALT ; SHOULD HAVE A 255 IN A HERE


FUNC0: LD A,1 ; RELOCATABLE CALL TO FUNCTION 1
CALL RELOCATABLE_CALL ;
RET


FUNC1: LD A,2 ; RELOCATABLE CALL TO FUNCTION 2
CALL RELOCATABLE_CALL ;
RET


FUNC2: LD A,255 ; WE JUST WANT TO RETURN A RESULT OF 255
RET


RELOCATABLE_CALL:
; PUT CODE TO PRESERVE REGISTERS HERE
LD H, 0
LD L, A
ADD HL, HL ; GET THE ENTRY NUMBER


PUSH IY
POP BC ; BC = TABLE


ADD HL, BC ; HL = FUNCTION OFFSET TO READ


LD C, (HL) ; BC = 2 BYTE RELATIVE ADDRESS FROM THE TABLE
INC HL
LD B, (HL)


PUSH IY
POP HL
ADD HL, BC ; ADD THE TABLE TO RELATIVE ADDRESS TO GET AN ABSOLUTE ADDRESS


; PUT CODE TO RESTORE REGISTERS HERE


PUSH HL ; CALL THE ADDRESS
RET



like
0
No reactions

Offline Animalgril987

  • Supporter
  • CPC6128
  • *
  • Posts: 231
  • Country: gb
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #17 on: 15:12, 28 August 21 »
Why not:
  POP HL
  PUSH HL    ; HL now has copy of return address
  DEC HL       ; HL points to high byte of called address
  LD D, (HL)
  DEC HL      ;  HL now points to high byte of called address
  LD E, (HL)


 and DE holds the entry address of your routine.
« Last Edit: 15:15, 28 August 21 by Animalgril987 »
like
0
No reactions

Offline roudoudou

  • 6128 Plus
  • ******
  • Posts: 1.156
  • Country: fr
    • urban exploration
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #18 on: 16:31, 28 August 21 »
Why not:
  POP HL
  PUSH HL    ; HL now has copy of return address
  DEC HL       ; HL points to high byte of called address
  LD D, (HL)
  DEC HL      ;  HL now points to high byte of called address
  LD E, (HL)


 and DE holds the entry address of your routine.
you assume there is a CALL before your routine but AMSDOS has his own ways  ;D

like
0
No reactions
use RASM, the best assembler ever made :p

I will survive

Offline Animalgril987

  • Supporter
  • CPC6128
  • *
  • Posts: 231
  • Country: gb
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #19 on: 16:58, 28 August 21 »
Quote from: Animalgril987 on Today at 13:12:53
Why not:
  POP HL
  PUSH HL    ; HL now has copy of return address
  DEC HL       ; HL points to high byte of called address
  LD D, (HL)
  DEC HL      ;  HL now points to high byte of called address
  LD E, (HL)


 and DE holds the entry address of your routine.
you assume there is a CALL before your routine but AMSDOS has his own ways
Very true.
Also a typo: 3rd comment should say LOW byte, not high.
like
0
No reactions

Offline andycadley

  • Supporter
  • 6128 Plus
  • *
  • Posts: 1.022
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #20 on: 14:03, 29 August 21 »
you assume there is a CALL before your routine but AMSDOS has his own ways  ;D
Yes, this sort of approach will fail if you've been called via an indirection block of some kind, as the stacked return address will actually be the location of the indirection rather than the code it eventually jumps to.
like
0
No reactions

Offline andycadley

  • Supporter
  • 6128 Plus
  • *
  • Posts: 1.022
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #21 on: 14:10, 29 August 21 »
Well... I think if the question has at its core the restriction "zero absolute addresses". Once you soften this, you answer a totally different question.
Well it depends on whether you interpret that as strictly no absolute addressing or more as a requirement that the code automatically relocates itself (either initially or on every call).


Writing truly address independent code on the Z80 (i.e. where you can't just inline modify an absolute addressed instruction) is particularly difficult. Not impossible, but you definitely have to jump through some hoops to accomplish it.


Cheating slightly and using the fact that passing parameters from BASIC will reserve some scratch memory pointed to by IX isn't really using absolute addressing but it certainly feels like skirting around the limitations a bit.
like
0
No reactions

Offline zhulien

  • 6128 Plus
  • ******
  • Posts: 920
  • Country: au
  • aka Vorax
    • 8bitology
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #22 on: 17:17, 30 August 21 »
To write a relocator, I would do the following:


- assemble the application, eg: at 0000
- assemble the application again at a different address which changes the high and low byte of each call, eg: 0101
- write a file of addresses for use with a loader


Then write the loader, allocate the application ram, allocate the address file (if not processed as it is read), change each address then free up the address file in ram.


If a program can just run from where ever it is loaded, or self-relocate (that bit would at least need to run where ever it is loaded), then that has a useful purpose.


Are there any better ways?  If crunched of course the process would be a bit different.  Are there any crunchers/relocators that do so 'in place'?  eg: FFFCCC (F = free ram, C = crunched app) --> UUUUUF (U = unchrunched app)


Does anyone not use a mass storage device on CPC these days that makes crunching even necessary?  I think the Z80 cycles and complexity are not worth it given storage for CPC is now plentiful... how to fill up so many gigabytes of data with a Z80 anyway?
like
0
No reactions

Offline FloppySoftware

  • CPC6128
  • ****
  • Posts: 261
  • Country: es
  • The best team: Amstrad PCW, CP/M, and the Z80 cpu.
    • Floppy Software
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #23 on: 09:10, 23 September 21 »
I use CP/M PRL files to achieve this. They have a relocatable bitmap based on page offset.


You can generate PRL files with DR LINK, ZASM or my PRL program. There are other tools to do this.


You can write a PRL loader, I did it for my SamaruX project.
« Last Edit: 09:14, 23 September 21 by FloppySoftware »
like
0
No reactions
floppysoftware.es < NEW URL!!!
cpm-connections.blogspot.com.es

Offline krusty_benediction

  • CPC6128
  • ****
  • Posts: 209
  • Country: fr
    • Awards
Re: Can you code a Z80 program with zero absolute addresses?
« Reply #24 on: 10:31, 23 September 21 »
Never tested, but winape assembler proposes these directives:
relocate_end    Mark the end of a relocatable section of code.
relocate_start    Mark the start of a relocatable section of code.
relocate_table [byte|word] [base_address]    Generate a relocation table. By default a table of word sized offsets is generated, override this by specifying byte for small code sections. The base_address specifies the relative origin for the values in the table.

and these variables

relocate_count    The number of entries in the relocation table.
relocate_size    The size of the relocation table, assuming the table is using word entries.
I guess other assemblers have such functionalities too.I would say they generate a table of addresses you have to patch by adding them the loading address of the program.
No need to do the things by yourself