Okay. Now we need to talk a little bit about the way stack machines work. The notion of a stack was an innovation which occurred to someone, I'm not sure where in the development of computer evolution. But, for example, my old favorite little dinky 12-bit PDP-8 did not have this notion originally of a stack. So when you wanted to execute a subroutine - a subroutine just sort of being a piece of code that many different places in the program might want to run. So the idea is, instead of repeating that code throughout the program, you only have it in one location. And different places in the program are able to execute that subroutine, the idea being that the subroutine does whatever it does. And when it's done, it returns to the instruction after the one that called it, that invoked it.

And by being able to go back to where it was called from, instead of, for example, always going back to the same place, if it goes back to where it was called from, then you can call it from anywhere you want, knowing that once it's done it'll come back to you, and you can continue doing what you were doing. So you need some way of knowing where you were called from, that is, the subroutine needs a way of knowing where it was called from in order to go back there.

Well, before stacks were created, and the solution that the PDP-8 used, was the first word of the subroutine was always left blank. And when the subroutine was called, the computer would put the address of the instruction after the one that called it into the top of the subroutine. So it would sort of just be stuck there. Then the subroutine would do whatever it does. And when it's all done, it would jump to the location stored at the front of it. And that would take it back to where it was called from.

Well, that was an elegant solution, and it was the only one we had at the time. But there was a problem with that. And that is, you couldn't have reentrant code. That is to say that, for example, not only could the subroutine not call itself, because if it called itself it would overwrite the return address at the top of it with another return address, but it couldn't call any other code that might have some reason for calling it. That is, you could never nest subroutines. Which ended up being a real problem as programs got more complicated because it just - you had to really understand what your program's flow was and make sure that there was no way that a subroutine could ever execute code where anywhere downstream it could get called again prior to it returning.

So the innovation of a stack was tremendous for computer science. The idea was that, instead of storing the return instruction in the code of the subroutine, instead we would have sort of a separate scratchpad which would automatically, I want to say, grow. I'm trying to think of how to describe it. It would automatically accept values and return values in a last-in, first-out mode, a so-called LIFO, meaning that if you put a value in, that's the value you get out. And as you take values out, they come out in the reverse order that you put them in, in very much like a stack. If you could imagine, if you imagine something that's called a stack, for example, like a stack of plates, where if you put plates on the stack, the stack grows. And as you take plates off, you're getting them in the reverse order.

So what happens is, with a stack-oriented machine, which is what everything is using now, it's such a successful and popular concept that when a subroutine was called, the return address was placed on the stack, and the subroutine would do what it does, and then a special instruction, a return instruction, would always take the value that's on the top of the stack, which would have been the last one placed on the stack, and return to there. So the beauty of that is that, if that subroutine called some other code that ended up calling back to the subroutine, well, this all just gets stuck on the stack. So as the return instructions are executed at the end of each subroutine, the values are popped off the stack in the reverse order, and everything works. Everything sort of comes back just exactly the way it's supposed to.

So the Z80 was a stack-oriented machine. And so the designers took advantage of its stack orientation in order to write their code. So the problem was that from a hacking standpoint it's not possible for us to provide any code because the only code we can provide would be in RAM. But we could provide pointers to code in ROM. So what these hackers cleverly realized is that there was, spread throughout the code for this voting machine, were subroutines, all ending in a return instruction. And they didn't want necessarily to do what these subroutines did. But they looked at the last few instructions prior to the return instruction and said, okay, is that useful for something? Is the little bit at the end of the subroutine useful? What does that do?

Well, it turns out that they wrote some code to look for all the return bytes. In the Zilog Z80 instruction set, a return instruction is a C9 in hex. These are all 8-bit instructions. A C9 is a return instruction. So they found all the C9s that were in ROM. And then they looked at the instructions just in front of those C9s to see what those do. And what they were trying to do was come up with a corpus, come up with a collection of useful things where they could jump to the near, just near the end of the subroutine and get a little bit of work done. Not a whole bunch. Just add something to the accumulator. Maybe subtract two values. Or put something somewhere in memory. Just little bits of work which happened to be at the end of all the subroutines, all the various subroutines that existed in this code.

One of the cool things from their standpoint about the Z80 is that every single byte is an instruction. It was back in the day where we had 8-bit bytes. So you had 256 possible instructions. And in the Z80 it was completely dense. That is to say, this map of 256 possible instructions was completely full. There were no invalid instructions. There were no privileged instructions. On more advanced machines like the Pentiums and PowerPCs and so forth, they have much larger instruction sets that won't fit in a single byte anymore. So many times there's areas of sort of ranges of instructions which are illegal. They're just not defined. They're for the future. They just didn't need all of the instruction space. And in other cases there are so-called privileged instructions, for example, which are powerful, which only the operating system running in the kernel, but not the user, is able to execute.

So for example in a Windows environment or in a Linux or UNIX environment, the user processes cannot actually do I/O. You can't access the physical hardware port because if you allowed that to happen, then users would have too much power. Instead you have to ask the operating system to do those things on your behalf, and it manages conflicts between programs that way. So this is the way things have evolved. But back in the days of the Zilog Z80, there was no notion of privileged instructions. What that means is that any data in this ROM that they had access to could be instructions. Even if they weren't meant to be, if they were never - if they were just like regions of data that happened to have C9, for example, in them, then the things in front of these return instructions could be executed. Nothing would generate an error. Nothing would blow up. Nothing would go wrong.

So what the researchers did was they found all these little return instructions, and they analyzed the work being done just before the return. Because what they realized they could do is come up with a stack which doesn't have code on it because the stack is in RAM, and we know that we can't execute out of RAM. But we can have pointers in the stack into subroutines. And when the subroutine returns, it'll come back and get the next pointer from the stack. Because that's how stack machines work.

So what they did was they aggregated sets of little tiny bits of work at the end of all these different subroutines into what they called "gadgets." And a gadget would do a defined thing, like it would add two values together. It would subtract one from another. It would perform a nonconditional jump or a conditional, a branching jump. Or it would do all the various things that programmers want to do. They were able to come up with little tiny fragments of work which when aggregated together created a complete pseudo instruction set. And it was what's called...