feature article
Subscribe Now

Raindrops on Roses and Whiskers on Kittens…

These Are a Few of My Favorite Things About x86

Many years ago, I said that there are two kinds of programmers: those who admit they hate x86 processors, and liars. Over the intervening years, my attitude toward x86 chips has softened quite a bit, to the point where I actually like them now. I think the change of heart is because the chips themselves got better, not because I’ve gone all soft in the head. But you can decide for yourself.

If you haven’t used an embedded x86 chip in anger for the past 10 years or so, you might be in for a treat. They’re a lot easier to program than you may remember, and they’re pretty useful for embedded systems. Granted, Intel still treats the embedded market as a distant cousin compared to its PC business, but as that latter market slowly evaporates, the embedded chips rise in relative status. That means you and I are more interesting to the Intel executive staff than we used to be. If things keep going this way, we might get invited to the company Christmas party in a few years.

One of the things I used to hate about early x86 processors was their memory segmentation. Other 32-bit chips had flat memory models, with one smooth, unbroken address range from 000000 all the way to 0xFFFFFF. I could put physical memory and I/O anywhere I wanted it in the address map, and I could address it without any strife or struggle. In contrast, early x86 chips made me jump through oddly sized hoops to reach anything, and they used this weird two-register segment+offset address model that didn’t have much correlation with the way I wanted to organize memory.

No more. Now segmentation is one of my favorite features – because it doesn’t work anything at all like it used to. Now it’s segmentation in name only. What it really is, is a cool debugging and security feature, and I’ve found it very useful.  Modern segmentation has helped me trap all sorts of software errors, and it’s kept my code from running off into the weeds like a Mendocino pot grower.

Segmentation has a couple of nifty features, all of which can help you either find bugs or minimize their effects when they happen anyway. First off, modern x86 processors define three types of memory segments: code, data, and stack. That means you get to (have to, actually) identify every range of memory that you use as one of those types. That doesn’t mean you have to define the entire address space of the processor; just the address ranges that you actually use. In essence, you’re telling the chip, “this stuff here is code, this over here is data, and my stack lives over there.”

You can have as many of these segments as you want; you’re not limited to one code segment, for example, or a single data or stack segment. In fact, go nuts. Define a whole bunch of code segments, and so on. We’ll see why in a minute.

The first benefit of this identification process is that the chip will know what parts of memory are okay to execute (i.e., code segments), which parts are okay to write data into (data and maybe stack segments), and which parts should be addressed backwards and are okay for pushing parameters (stack segments). That means an x86 processor will never mistakenly execute your data, even if you screw up a jump or subroutine call. The chip “knows” that certain address ranges contain data or stack, not code, and will simply refuse to jump there. So right off the bat, you’ve got yourself a handy bug-containment feature.

It works the other way around, too. The chip will write data only into data segments, never code segments. It won’t even write into a stack segment unless you’re doing a stack operation, like pushing parameters. That means you won’t accidentally write over the top of your code with a mismatched pointer, botched dereference, or runaway index. The chip just won’t do it. “Nope, that there’s code, and I ain’t writin’ nothin’ in there,” you can almost hear it say. 

Ah-hah, but what if I actually want to have self-modifying code? How can I update my code if I can never write into code space? No problem: you simply define a data segment that covers the same address range as the code. Modern x86 chips have no problem with overlapping segments, so it’s okay to dual-define some addresses as both code and data. For safety (and your own sanity), you should keep the overlap as small as possible to avoid exposing more code than necessary. And since you can define and delete segments on the fly at run-time, you can create the overlapping data segment just before you need it, and then delete that definition right after you’re done with the update. The rest of the time, your code space is execute-only, and there’s no way to accidentally overwrite it.

Segments can be any size you like, from a single byte to the whole universe of addresses. And you can have as many as you want. You can combine these two features to your advantage to make your system more secure and easier to debug. If you’ve got code scattered over several ranges (a ROM here, some diagnostic code there, and the operating system here, here, and here…) then the best approach is to define code segments that snugly encompass each chunk of code – no bigger and no smaller. That way, you can never run “off the edge” of the code segment and into undefined memory or data/stack space. The chip knows where the code ends, and it simply won’t fetch or execute anything outside of those boundaries. You can also scatter multiple data spaces around the memory map, and the chip will prevent stray writes to anything outside of those areas. Enclosing your stack(s) within tightly defined boundaries also prevents nasty stack underruns, which can be difficult bugs to locate any other way.

Old x86 chips used to “wrap around” the end of a segment, which a few programmers used as a cheap loop-counter trick. Mostly it was a bug, however. Modern x86 chips won’t wrap around the end of a segment anymore, but instead trap it as the programming error it usually is.

Memory segmentation is pretty handy, both for defining what parts of memory you’re using, but also what parts you aren’t. Most systems have a bunch of holes in their address map, where the vast majority of addresses aren’t used at all (who has terabytes of RAM in their embedded system?). Chances are, 90-some percent of addresses are invalid, so having a chip that catches and traps these is a nice bonus. Over the years, memory segmentation has gone from being a nuisance to becoming a real benefit. I may eventually get used to the x86 architecture after all. 

Leave a Reply

featured blogs
Jul 6, 2020
If you were in the possession of one of these bodacious beauties, what sorts of games and effects would you create using the little scamp?...
Jul 3, 2020
[From the last episode: We looked at CNNs for vision as well as other neural networks for other applications.] We'€™re going to take a quick detour into math today. For those of you that have done advanced math, this may be a review, or it might even seem to be talking down...
Jul 2, 2020
In June, we continued to upgrade several key pieces of content across the website, including more interactive product explorers on several pages and a homepage refresh. We also made a significant update to our product pages which allows logged-in users to see customer-specifi...

Featured Video

Product Update: DesignWare® Foundation IP

Sponsored by Synopsys

Join Prasad Saggurti for an update on Synopsys’ DesignWare Foundation IP, including the world’s fastest TCAMs, widest-voltage GPIOs, I2C & I3C IOs, and LVDS IOs. Synopsys Foundation IP is silicon-proven in 7nm in more than 500,000 customer wafers, and 5nm is in development.

Click here for more information about DesignWare Foundation IP: Embedded Memories, Logic Libraries & GPIO

Featured Paper

Cryptography: A Closer Look at the Algorithms

Sponsored by Maxim Integrated

Get more details about how cryptographic algorithms are implemented and how an asymmetric key algorithm can be used to exchange a shared private key.

Click here to download the whitepaper

Featured Chalk Talk

Why Does a Medical Tool Need Security?

Sponsored by Mouser Electronics and Maxim Integrated

Connected Medical devices require a unique set of security design requirements and a software-only security solution with a non-secure MCU might not be the best way to go. In this episode of Chalk Talk, Amelia Dalton chats with Scott Jones from Maxim Integrated about the details of secure authentication and how we can use the SHA-3 authentication model to get our medical security plan on track.

Click here for more information about Maxim Integrated MAX66240 DeepCover® Secure Authenticator