This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

16-bit relocations in 32-bit code


Hello!

I'm writing a simple 16-bit Forth kernel and encountered a complex
problem that I can't solve for several days, so I'm asking for help.

Forth uses indirect code, e.g. most Forth 'words' (subroutines) are
just list of addresses of another words. Something like this (in
assembly):

.long OVER
.long MINUS
.long SWAP
.long PLUS

...
OVER:
...
MINUS:
...

and so on. Now this wouldn't be a problem if it would be a 32-bit Forth
kernel, but I explicitly need a 16-bit Forth kernel, so all offsets
have to be 16-bit. Of course, that's generally impossible on 32- and
64-bit machines, so I'm doing the following:

 * All Forth code is put into a separate section (let's call
   it .f_text)
 * At linking time I use a special linker script which places .f_text
   at a known address (say, 0x60000), like this:
   .f_text 0x60000 : { *(.f_text) }
   I tried to use the --section-start ld option, but there was a bug
   in its implementation (reported and it's fixed now).
 * I subtract this known section offset from every offset, e.g:

.short OVER-0x60000
.short MINUS-0x60000
.short SWAP-0x60000
.short PLUS-0x60000

This worked fine on x86_64 (my primary development machine), but I
encountered a big problem when I tried to compile it for i386: unlike
x86_64, on i386 the relocation offset is kept in the .text section
directly in the place where the relocation has to be applied.

So the problem is that 0x60000 does not fit in the 16-bit word I'm
reserving for the relocation. The difference between label offset and
0x60000 guaranteed fits in 16-bits, but the 0x60000 itself doesn't.

A partially working solution was to put the .f_text segment at offset
zero (sic!) but such executables work only if launched as root.

I tried many other solutions: subtracting a known symbol (like
_f_text_start) from every symbol:

.short PLUS-_f_text_start

This gives:
test.s:7: Error: can't resolve `.text' {.text section} -
`f_text_start' {*UND* section}

Also I tried to take only the lower 16 bits from every address, and
ensuring that the section start is aligned at 0x10000:

.short  PLUS & 0xffff

This gives:
test.s:7: Error: invalid sections for operation on `PLUS' and `L0'

Are there any ideas how my goal could be achieved? It would be good to
find at least some hack for i386 targets (elf_i386 and pei_i386 would
be ideal), since on x86_64 everything works fine with the first
approach.

-- 
Andrew

Attachment: signature.asc
Description: PGP signature


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]