Assembler Relaxation
eli.thegreenplace.net
eli.thegreenplace.net
This goes all the way back to OPTASM in the 80s, if not earlier:
http://archives.scovetta.com/pub/walnut-creek/JSAGE/ZNODE3/I...
https://books.google.com/books?id=FC-L2faxEVkC&pg=PA43&lpg=P...
FASM is well known for this too:
https://en.wikipedia.org/wiki/FASM#Design
Essentially, the byte array holding the instruction has to be re-allocated because it has to grow larger
No it doesn't - just do one pass to figure out the maximum size (i.e. all instructions are the longest variant), and allocate a buffer of that size. You can be somewhat more intelligent by not increasing the size for the jumps that won't ever grow - e.g. backward ones ones whose target has been resolved already, and there aren't enough possibly-growing jumps between it and the current position to overflow the offset. Now iterate the code generation, moving the necessary bytes in the buffer forward when you hit a forward reference that's too far, until you reach the end. All done and ready to output, without any excess copying or messing around with linked lists. That's what the older assemblers which had this optimisation did, and they were plenty fast. (Rule of thumb: pointer chasing and small allocations are bad. Arrays and big blocks are good.)
http://dl.acm.org/citation.cfm?id=359474
Interesting paper, by a rather familiar author. I noticed the date coincides with the introduction of the 8086, but the paper makes no mention of it.
EDIT: The term is even in the wikipedia article for linker [1], although with a broader definition.
[1] https://en.wikipedia.org/wiki/Linker_(computing)#Relaxation
https://en.wikipedia.org/wiki/Linker_(computing)#Relaxation
It took me an embarrassingly long time to figure out what the obscure ld error messages about relaxation were actually referring to.
Optimising call distances in the assembler is pretty easy, but the big win is in the linker, because this allows you to optimise calls between procedures. Of course, you then need a linker which knows how to edit compiled machine code to change the kind of call. FWIW, I do a lot of embedded stuff, and I have very rarely met an embedded architecture where ld would do relaxation properly, and usually end up turning it off.
Is this a general problem. For example, is this a limited form of Bin Packing? Or is there a general solution for problems like these?
a:
times 124 nop
jmp b
jmp a
times 125 nop
b:@rer0tsaz - this is a great counter example.
Is there a general form for these types of problems and solutions?
Also, I wonder how often instruction sequences like that would occur.