Skip to main content
added 671 characters in body
Source Link
Raffzahn
  • 236.1k
  • 23
  • 682
  • 976

Aside from such generic replacements there is generated code - that's not just some fancy modern JIT (*1):

While one could argue that all of these cases have many layers of execution inbetween generation an calling(*2), there isare other quite common ways of runtime generation within applications falling into the JIT category - except predating JavaScript by several decades - as what we call now JIT was present in many applications that do have to work with ad hoc queries on large amount of data. Examples are

  • Regular Expressions - already in 1968 QED for MULTICS generated code so evaluation could be speed up
  • Data Base Queries - it was (and maybe still is) rather common to translate queries at run time into machine code

or, more modern, but still 1980s,

  • Microsofts CBLT or Compiled BLock Transfer - To make BitBliting somewhat performant, Windows GDI generated tight screen handling loops on stack (see this description) (*3).

At the possiblelowest end, there is in addition the

That case might be most prominent on x86 with the interrupt number when intending to call an arbitrary service via an INT instruction (*3*4).

*1 - JIT does of course predate JavaScript - byit rather a good three decades - as what we call now JIT was presentlate comer in many applications that do have to work with ad hoc queries on large amount of data. Examples are

  • Regular Expressions - already in 1968 QED for MULTICS generated code so evaluation could be speed up
  • Data Base Queries - it was (and maybe still is) rather common to translate queries at run time into machine code

*2 - I wouldn't, as there is no guarantee that such generator isn't running into the generated code right after modifying the last byte (which as well can be the first in that section).

*3 - Thanks to occipita for adding this example.

Aside from such generic replacements there is generated code - that's not just some fancy JIT (*1):

While one could argue that all of these cases have many layers of execution inbetween generation an calling(*2), there is still the possible

That case might be most prominent on x86 with the interrupt number when intending to call an arbitrary service via an INT instruction (*3).

*1 - JIT does of course predate JavaScript - by a good three decades - as what we call now JIT was present in many applications that do have to work with ad hoc queries on large amount of data. Examples are

  • Regular Expressions - already in 1968 QED for MULTICS generated code so evaluation could be speed up
  • Data Base Queries - it was (and maybe still is) rather common to translate queries at run time into machine code

*2 - I wouldn't, as there is no guarantee that such generator isn't running into the generated code right after modifying the last byte (which as well can be the first in that section).

Aside from such generic replacements there is generated code - that's not just some fancy modern JIT (*1):

While one could argue that all of these cases have many layers of execution inbetween generation an calling(*2), there are other quite common ways of runtime generation within applications falling into the JIT category - except predating JavaScript by several decades - as what we call now JIT was present in many applications that do have to work with ad hoc queries on large amount of data. Examples are

  • Regular Expressions - already in 1968 QED for MULTICS generated code so evaluation could be speed up
  • Data Base Queries - it was (and maybe still is) rather common to translate queries at run time into machine code

or, more modern, but still 1980s,

  • Microsofts CBLT or Compiled BLock Transfer - To make BitBliting somewhat performant, Windows GDI generated tight screen handling loops on stack (see this description) (*3).

At the lowest end, there is in addition the

That case might be most prominent on x86 with the interrupt number when intending to call an arbitrary service via an INT instruction (*4).

*1 - JavaScript it rather a late comer in that.

*2 - I wouldn't, as there is no guarantee that such generator isn't running into the generated code right after modifying the last byte (which as well can be the first in that section).

*3 - Thanks to occipita for adding this example.

added 2547 characters in body
Source Link
Raffzahn
  • 236.1k
  • 23
  • 682
  • 976

Preface:

Avoiding '(self) modified' code is impossible on computers allowing to load code (see section at the End)


The Question

It was the fear of problems due incompatibility not any experienced/known incompatibilities

Now, backward compatibility aside, generated code is a very common feature in non trivial software. Think RegExp and data base queries (*1).


Computers Use Self Modifying Code All the Time

It's important to keep in mind, that any computer that allows to load an arbitrary program already needs the ability to modify code.

  • Loading a program, modifies that locations. Usually they did hold code prior - like the last program run.

This is not only about programs loaded by a monitor, but as well

  • overlays - which in extreme may mean calling a function at exactly the same memory location as the calling instruction.

Aside from such generic replacements there is generated code - that's not just some fancy JIT (*1):

  • Every compiler produces new code to be executed
  • Likewise using a debugger

While one could argue that all of these cases have many layers of execution inbetween generation an calling(*2), there is still the possible

  • need to modify immediate operands of instructions

That case might be most prominent on x86 with the interrupt number when intending to call an arbitrary service via an INT instruction (*3).

In fact, it can be assumed that, in many cases, such modification only happened quite short before the invocation, using something like

        ...
        MOV AL,DesiredService
        MOV INTNR,AL
        MOV AX,axContent
        INT 0FFh
        ORG *-1
INTNR   DB  0
        ...

*1 - JIT does of course predate JavaScript - by a good three decades - as what we call now JIT was present in many applications that do have to work with ad hoc queries on large amount of data. Examples are

  • Regular Expressions - already in 1968 QED for MULTICS generated code so evaluation could be speed up
  • Data Base Queries - it was (and maybe still is) rather common to translate queries at run time into machine code

*2 - I wouldn't, as there is no guarantee that such generator isn't running into the generated code right after modifying the last byte (which as well can be the first in that section).

*3 - Thanks to Natan Eldredge for reminding us.

It was the fear of problems due incompatibility not any experienced/known incompatibilities

Preface:

Avoiding '(self) modified' code is impossible on computers allowing to load code (see section at the End)


The Question

It was the fear of problems due incompatibility not any experienced/known incompatibilities

Now, backward compatibility aside, generated code is a very common feature in non trivial software. Think RegExp and data base queries (*1).


Computers Use Self Modifying Code All the Time

It's important to keep in mind, that any computer that allows to load an arbitrary program already needs the ability to modify code.

  • Loading a program, modifies that locations. Usually they did hold code prior - like the last program run.

This is not only about programs loaded by a monitor, but as well

  • overlays - which in extreme may mean calling a function at exactly the same memory location as the calling instruction.

Aside from such generic replacements there is generated code - that's not just some fancy JIT (*1):

  • Every compiler produces new code to be executed
  • Likewise using a debugger

While one could argue that all of these cases have many layers of execution inbetween generation an calling(*2), there is still the possible

  • need to modify immediate operands of instructions

That case might be most prominent on x86 with the interrupt number when intending to call an arbitrary service via an INT instruction (*3).

In fact, it can be assumed that, in many cases, such modification only happened quite short before the invocation, using something like

        ...
        MOV AL,DesiredService
        MOV INTNR,AL
        MOV AX,axContent
        INT 0FFh
        ORG *-1
INTNR   DB  0
        ...

*1 - JIT does of course predate JavaScript - by a good three decades - as what we call now JIT was present in many applications that do have to work with ad hoc queries on large amount of data. Examples are

  • Regular Expressions - already in 1968 QED for MULTICS generated code so evaluation could be speed up
  • Data Base Queries - it was (and maybe still is) rather common to translate queries at run time into machine code

*2 - I wouldn't, as there is no guarantee that such generator isn't running into the generated code right after modifying the last byte (which as well can be the first in that section).

*3 - Thanks to Natan Eldredge for reminding us.

Source Link
Raffzahn
  • 236.1k
  • 23
  • 682
  • 976

Backward compatibility, is the obvious general answer. But backward compatibility with what software exactly?

There may have been some PC/PC-XT .COM program using self modifying code to shave a byte or a cycle. But I don't think they had any special software they had in mind. After all, those enhanced CPUs were designed way before any incompatibility could have been detected.

Also you don't have to look for specific 486 code, that box was already opened with 8088 PCs. At least in case of IBM it's easy to see the see the effort they invested to emulate 8088 ISA access with the AT or the addition of the ever dreaded A20 gate. In Either case it would have been easy to dismiss the fringe cases those hacks fixed. With compatibility being a holy grail, continued support for such practice was a must.

It was the fear of problems due incompatibility not any experienced/known incompatibilities