Here are some ramblings for posterity that this article brought back from distant memory of when I was one of a small group of people working on the Norcroft toolchain for RISC OS. (E&OE!) Please forgive the parts where I drop into hideously detailed techie-talk!
The history of ELF on RISC OS goes back at least 6 years to when I modified link to support a subset of ELF functionality. This first became public when we made a beta release of the 32-bit toolchain, although as I recall, we did not exactly trumpet it from the rooftops. Additionally, support was added for symbol definition files (files that the linker would output listing all the symbols in the generated output files and the values assigned to them), which was probably more useful for us to make building ROM images simpler than to anybody outside Acorn. So in the end, the linker could combine AOF, ELF and symdef files (COFF support was compiled out, IIRC). It could write out ELF relocatable object files and ELF program files (in addition to AIF and modules, of course)
I also made significant changes to libfile. libfile was also updated to support ELF object files and symdef files. Furthermore, I broke the implicit dependency that ALF files could only contain AOF files (and COFF objects only in AR-format library files): any library file format can contain an arbitrary mixture of any type of object file (including symdef files).
IIRC, the beta tools were distributed with ReadELF (or something with a similar nme) to help dissect ELF files. If I don't recall correctly, I just had it on my machine to help me debug the linker - sorry about that.
The major headache for object file interchanging is the relocation data. The ARM ELF spec was missing some required types of relocation, and the AOF specification includes relocations that require you to examine the instruction being modified and change behaviour based on the instruction you find - and, worse, allows you to modify several instructions! This just doesn't happen in ELF, since all ELF relocations must be described in a static table describing a mechanical unconditional alteration to the instruction.
I was quite surprised to see a module called ELFLoader pop up that *didn't* come out of Castle. I thought I'd registered that module name and SWI chunk, perhaps I just called my module "ELF" and gave it the title "ELF Loader". I certainly received the filetype allocation that I specifically asked for (&E1F - what else and made the changes to FileSwitch to support direct execution of ELF program files (i.e. you could *Run it just like files of type &FF8). Now that was one of the last things I did, so that change might never have made it out. My ELF module would load the binary and start it as an application correctly in exactly the same way that FileSwitch launches AIF images.
I never got around to modifying CMHG - it wasn't really urgent, because the linker would happily link the AOF file generated by CMHG with the other ELF object files.
The one important facility that was missing was automatic run-time decompression of ELF program files. This is not something that the wider non-RISC OS community is particularly interested in, I discovered. There are technical reasons for this (typically other systems like to memory map code directly from disc into memory - so you wouldn't want to have the code compressed), but with some hijacking of platform-dependent parts of the ELF header could no doubt have been used.
One problem at the time which may well have been sorted out now is that GNU bfd's ARM ELF differed in subtle, but irritatingly incompatible, ways with ARM's ARM ELF (for example, differing meanings for flag bits). I considered compatability with ARM's version to be more important (and indeed, we were looking at the way ARM did shared libraries in their ADS toolchain (the successor to ARM SDT - which is what Norcroft was, putting it simplistically). That work had not really progressed very far, although the beginnings of it were in place in the C compiler in that I removed the crusty way that module code was generated and replaced it by a much cleaner, less invasive (to the core compiler code) implementation [Aside: this is the stuff that loaded data address constants by just blindly stuffing the equivalent of "LDR rX, address:LDR r12,[r10,=-0]:ADD rX, r12, rX" (plus a relocation for the second LDR); somebody once found a case where the compiler used R12 for rX. This made the program concerned go bang! This was replaced using virtual register constructs that the compiler could actually recognise and optimise properly. End aside.] Once that had been tidied, the idea was to generate the shared library data loading code instead of just whacking the "LDR rY, [r10, #=-0]: ADD rZ, rY, rX" sequence into the code (which was the tidyup - because once real virtual registers are used and rY can be declared constant, a lot of peephole optimisations become possible that were not possible before when effectively two completely opaque instructions were inserted).
We never got around to modifying the assembler or the C compiler to generate ELF. It would have been a fiddly job, but not particularly difficult provided you could concentrate on it for however long it would take and do it properly.
I remember thinking at the time that the best way to do modules would be to generate relocatable ELF object files with program tables, which probably wouldn't have been too hard. This code would probably have been loaded into a separate dynamic area instead of the RMA, kept write protected and the data instantiated in another companion area or the RMA. With an appropriate loader, you could even have multiple versions of the same library loaded at once. The SharedCLibrary module would instead because a ResourceFS wrapper with a large ELF file in it (although there are interesting mutual-dependency problems if you go on to write your loader in C - and the way that GNU ld gets around this problem is based around not writing code that triggers any library calls until you can get the C library linked.)
Then one day, just like that, RISC OS was canned. The End.