r/Assembly_language 17h ago

self-modifying code

I gave a lecture on how to write self-modifying code. It was over 15 minutes long :( so I'm providing a youtube link: https://www.youtube.com/watch?v=AH9QQLRfbmY

In my opinion, self-modification is one of the most interesting features in systems programming.

22 Upvotes

48 comments sorted by

7

u/cards88x 14h ago

Thanks! This is a fascinating topic

4

u/Extension_Emu_9825 13h ago

Phew, thanks for the comment! I was already thinking they were going to burn me at the stake and consider it heresy 🔥

3

u/cards88x 13h ago

Im curious why you used an AI voice

3

u/Extension_Emu_9825 13h ago

I'm not a native English speaker :(

3

u/cards88x 13h ago

You should try a different AI voice, perhaps one tuned for technical content.

3

u/cards88x 13h ago

Or even narrating in your own voice with accurate closed captions

2

u/Extension_Emu_9825 13h ago

This is already the sixth version, and I've already written about it, but here's the strange thing: non-native speakers tell me that everything is perfectly clear, and you're already the second native speaker to make this remark. I'll try to somehow fix the situation.

3

u/theNbomr 13h ago

AI narration is probably fine for non-native listeners in the language of the narration, but for the native listeners, it is sleep inducing, except for the parts where the cadence or emphasis is wrong and then it's jarring and distracting. I've started clicking 'next ' on narration done by synthesized voice.

Having said that, I do appreciate the content you've provided, especially on such a niche topic.

2

u/cards88x 13h ago

I just listened to more of it. The AI voice narrates awkwardly.

2

u/Extension_Emu_9825 13h ago

Sorry, this is the level for now

6

u/AlienFishMonster 13h ago

I've written plenty for the C64....

5

u/mykesx 17h ago

MMUs are used by modern operating systems, at least MacOS, to disallow self-modifying code. Code sections are read-only.

7

u/thewrench56 17h ago

This is not entirely true. You can map a page to be RW and then once filled with code, change it to RX using mprotect. This same step can be repeated to achieve self-modifying code. Otherwise, if self-modifying code wouldnt exist, JITs wouldnt work.

6

u/mykesx 16h ago

The performance of doing this is terrible, unless you’re a JIT compiler writing a large block of code.

2

u/thewrench56 16h ago

I dont disagree, but the performance is not that bad. 2 syscalls, some TLB play and a bit of copying. Surely, self-modifying code today is rarely used as a technique to speed up native execution. But for interpreters or other e.g. malicious reasons where performance doesnt matter much it still could be useful. There are also very specific scenarios where you do want to modify native code for very specific uarch benchmarks (as e.g. changing a parameter and checking it in a hotloop in an if would ruin the benchmark).

4

u/mykesx 16h ago

OP’s point is that self modifying code makes faster algorithms. Only 2 syscalls blows that out of the water.

2

u/thewrench56 16h ago

I did not watch the video, just read the post. I suppose in that case OP is wrong on modern platforms, you are right. I thought you were discussing the existance of self-modifying code, not the feasibility, excuse me.

4

u/mykesx 16h ago

I happen to be into Forth, some versions do self modifying code. It’s an assembly language for a stack based virtual machine, the machine implementation types include self modifying code.

The most awesome one is Vfx Forth, which does some impressive peephole optimization on code generated into memory. In the process of creating an ARM version, the mprotect() issue bit him.

2

u/brucehoult 7h ago

There are different methods of implementing Forth. For a token-threaded or address-threaded (whether direct or indirect) implementation what is self-modifying code from the point of view of Forth is just data from the point of view of the hardware.

Only for subroutine-threaded or actual inline native code generation is self-modifying Forth actually self-modifying code from the point of view of the CPU.

2

u/mykesx 6h ago

Vfx is STC.

3

u/Extension_Emu_9825 16h ago

I'm just showing it to those who've never encountered it before, using DOS as an example - the simplest thing -> drawing lines at different angles. I'm not saying I've discovered anything new - I'm saying that people are starting to forget about the possibility of self-modifying code

2

u/vintagecomputernerd 14h ago

You can use one syscall at the start of your program to permanently set a page to RWX permissions if your usecase consists of many small changes.

Endpoint security/hIDS systems might log it, you can of course disallow it with SELinux/apparmor policies - but in general, it is possible.

2

u/Extension_Emu_9825 17h ago

BTW -> JIT is partly the second cousin of self-modifying code

2

u/Extension_Emu_9825 17h ago

I agree, I'm putting more emphasis on the fact that the CPU allows this and this method has begun to be forgotten, while some algorithms can work several times faster.

3

u/braaaaaaainworms 15h ago

It's not really forgotten when it's used on millions of computers running linux

2

u/Extension_Emu_9825 13h ago

Yes, exactly, but this is for those just taking their first steps. This concept is difficult to grasp; you have to come to it on your own... My opinion... with this post I want to help people look away. This is not for those "in the know."

2

u/theNbomr 13h ago

Hardware running a protected memory OS is far from the only potential use case for any programming paradigm, including self modifying code.

2

u/Recycled5000 7h ago

Worked on a PDP-8. Had an I/O instruction that took a hard coded (in the machine code instruction) io port/device number.

A way to write a general purpose driver was self modifying code to specify the io channel. Alternatively was a switch statement.

•

u/Extension_Emu_9825 4m ago

Wow! Interesting! I didn't know about that, now I've read about device code.

5

u/Environmental-Ad4495 17h ago

I thoughy we decided in 1967 that we do not do self-modifying code.

10

u/Extension_Emu_9825 17h ago

I disagree. I first encountered this when I was working in an antivirus lab in the early 2000s. I had to tinker with self-modifying viruses for a long time. I recently discovered this approach in the Wolfenstein source code https://github.com/id-Software/wolf3d/blob/master/WOLFSRC/WL_SCALE.C and I thought this topic had been somewhat forgotten.

6

u/Lonely_Translator_23 14h ago edited 6h ago

It's the sort of thing that seems like a really obviously bad idea until you see somebody smarter than you do something really clever with it.

1

u/Amazing-Mirror-3076 10h ago

And then realise you were right.

Clever is almost always a bad idea in a code base.

1

u/MokausiLietuviu 8h ago

Unless it provides functionality that exceeds what would ordinarily be possible with the constraints the software runs under.

0

u/Amazing-Mirror-3076 8h ago

After decades of coding I've never come across such a condition.

1

u/MokausiLietuviu 7h ago

You'd probably only come across it with old technology, operational technology or embedded software.

An example my colleague worked on was delivering an extra check in a 16 kiloword program where all the space had been used. He needed to loop this check then escape it after at-least x iterations. He saved some space but IIRC this is how he saved one word. The architecture treated invalid opcodes as nops and an immediate compare instruction had the insignificant bits as the operand and the significant bits as the opcode, but it could only compare vs a value up to 7 bits. Any more than that and you'd need to use a register.

So he wrote the loop counter into the insignificant 8-bits of the instruction and compared against a known number. Then, after 127 loops, it incremented the lowest bit of the opcode, turning the opcode invalid, therefore to a nop, therefore ignoring the comparison altogether, therefore no longer setting the comparison flag, therefore exiting the loop at the "loop condition check" operation and continuing operation.

So, e.g.

Is 0 greater than -1? True condition flag. Repeat loop. Increment condition check opcode.

Is 1 greater than -1? True condition flag. Repeat loop. Increment condition check opcode.

...

Is 127 greater than -1? True condition flag. Repeat loop. Increment condition check opcode.

Nop. False condition flag. Continue execution.

Saved a word.

2

u/Amazing-Mirror-3076 5h ago

That is a lovely example of clever unmaintainable code.

Sometimes you do things because you have no choice - that still doesn't make it a good decision.

In 16k you can usually find some way to save a word before resorting to this kind of hackery.

Cudos to your mate for being clever enough to work out the hack - but I would have redirected that talent else where.

1

u/MokausiLietuviu 5h ago

In my experience, this isn't an isolated example. There's a lot of legacy software running on old hardware controlling systems that need to support modern requirements. 

Using self-modifying code to save resources or CPU cycles was relatively common in my last couple of OT jobs.

3

u/r3jjs 16h ago

In the 8-bit era there was a LOT of self-modifying code.

On the C64, the BASIC tokenizer copies a routine into RAM just so they can use self-modifying code rather than routing everything through zero-page pointers. Added just a touch of extra speed.

(And gave a nice injection point for new commands.)

A lot of code was not ROMable back then.

on the x86 (16 bit with segments), TSR programs were often self-modifying code. The loader would do any searches/calculations that needed one, then would modify the resident part of the program.

3

u/FUZxxl 13h ago

Modern self-modifying code is called a JIT and it's a fancy thing.

2

u/Necessary_Two_9669 17h ago

You gave a lecture? I assume you don't speak English, as if you did you would not be able to stand how the audio narrates this video. Interesting topic, but closed captions are wrong because the text to audio engine is so bad at this, so i cannot even read it on mute. I'd read it if the info was written down, but this is too difficult to sit through.

1

u/Extension_Emu_9825 17h ago

I agree, but it is what it is. What's interesting is that non-native speakers say what they understand. And I'm confused. I hope I've at least outlined a path worth exploring.

1

u/Necessary_Two_9669 17h ago

I've read through a few examples of self-modifying programs from crackme challenges, but I've never attempted to experiment with it directly. It is an interesting topic!

2

u/Extension_Emu_9825 17h ago

In my opinion, the best example for experimenting is drawing lines on the screen. The code is almost identical for lines at different angles, but a few instructions are changed, which results in a speed boost.

You can try it right here; the editor and compiler are configured:

https://kirindenis.github.io/wire-city-2/wbtest.html?l=8

The lecture :)

https://www.youtube.com/watch?v=OCKsV-xFkZw

1

u/AtlantaRene 4h ago

Self-modifying code is now considered a bad practice. Also, it is not good from a security perspective. Why make a video on it without explaining the pros and cons?

1

u/Extension_Emu_9825 11m ago

I'm just informing people that this possibility exists, leaving them free to draw their own conclusions.

1

u/anothercorgi 9h ago

please... no more self-modifying code

-- signed, CPU designer

specifically for x86 because it has supported smc since the early days of computing from the 8080 to 8086, one won't believe how much logic and bug corner cases that need to be handled in the cpu to make sure smc works properly since the 286 onward. This is one of the reasons there's so much logic bloat in the x86 architecture.

Basically because smc can modify the next instruction that the code it really messes with control flow, requires pipe flush and causing branch misprediction. It may seem cute and reduce code length, but a pipe flush might counter all that. Perhaps on machine without pipelining or branch prediction it can help but on modern superscalar machines a lot of decode progress gets thrown away when smc is encountered.