Maybe someone here knows what was that purpose?
I was surprised when he told me how people normally passed arguments. They would put them after the JMS instruction in the caller. So, the callee would indirect from the "return address" stored in FOO to retrieve its arguments, incrementing the return address after each one. So the code to call FOO with arguments 1 and 2 would be (in Intel syntax)
JMS FOO
DW 1
DW 2
[code to run after returning]
Mark Smotherman explains this in more detail, using PDP-8-compatible syntax, in https://people.computing.clemson.edu/~mark/subroutines/pdp8.....It seems sort of intuitive to do things this way; if you're writing atan2(3, 4), it's nice to be able to translate this to
jms atan2
3
4
rather than, say, mov $3, %rdi; mov $4, %rsi; call atan2.Maybe someone had this habit in their assembly and adapted it to the 8086's calling convention by inserting MOVs and a JMP instruction?
You can also imagine that a compiler might be somewhat simpler if it generated code in the order in which it encountered the expressions. Gas lets you switch back and forth between .text and .data, so that if your compiler does this, you still don't have to insert JMP instructions. However, a few years ago when I wrote Ur-Scheme, I did do this for lambda expressions: the code for the lambda expression is generated inline in the middle of its containing code, which then has to contain a jump past it.
Since I was still learning the x86 CPUs, the intention here was not to save bytes but instead to have something working. I believe I picked up the style of having the string at the top and jumping over it from other similar code I had come across in those days.
You are right of course. Here is a complete example that moves the string to the bottom and saves two bytes:
I have now updated the GitHub repository with this updated source code and binary. Thank you for the nice comment!