Self-modifying code is not limited to assembly.

A couple of high-level languages offer the (usually evil) choice to change your code in run time.

The best example is most likely COBOL. The ALTER statement works in the following way :

.
.  (some thousands of lines snipped)
.

        PERFORM READ-DATA 
            UNTIL MY-SUM IS GREATER THAN 700.

.
. (some more lines snipped)
.

 READ-DATA SECTION.
 HERE-IT-GOES.
        GO TO INITIAL-ITERATION.
 INITIAL-ITERATION.
        MOVE 0 TO MY-SUM.
        ALTER HERE-IT-GOES 
            TO PROCEED TO MORE-ITERATIONS.
        GO TO READ-FROM-FILE.
 MORE-ITERATIONS.
        ADD INPUT-SUM TO MY-SUM ROUNDED.
 READ-FROM-FILE.
        READ INFILE.
 READ-DATA-EXIT.
        EXIT.

What it does is simple: Read records from an input file until the sum of values in a certain field of the input field is greater than 700.

The ALTER statement changes the statement

        GO TO INITIAL-ITERATION.
into
        GO TO MORE-ITERATIONS.

during run-time.

Most people who wrote COBOL compilers apart from IBM decided not to implement ALTER.


Some lesser-known languages like NODAL and POCAL also offered self-modifying code features, easier to implement because both were interpreted languages.

A sample in POCAL :

10.10 SET I=0
10.20 SET POCLIN(10.10)="SET I=" I+1
10.30 DO 20!30
10.40 TYPE "Program used " I " times" !
10.50 END

20.10 SAVE "(SOMEDISK:SOMEUSER)STUPID:POCL"

30.10 TYPE "Saving failed - tough luck !"
This program not only modifies itself, it also saves itself back to disk.

The conclusion might be that languages which allow for self-modifying code are also self-obfuscating.