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
Nov 25, 2020
It constantly amazes me how there are always multiple ways of doing things. The problem is that sometimes it'€™s hard to decide which option is best....
Nov 25, 2020
[From the last episode: We looked at what it takes to generate data that can be used to train machine-learning .] We take a break from learning how IoT technology works for one of our occasional posts on how IoT technology is used. In this case, we look at trucking fleet mana...
Nov 25, 2020
It might seem simple, but database units and accuracy directly relate to the artwork generated, and it is possible to misunderstand the artwork format as it relates to the board setup. Thirty years... [[ Click on the title to access the full blog on the Cadence Community sit...
Nov 23, 2020
Readers of the Samtec blog know we are always talking about next-gen speed. Current channels rates are running at 56 Gbps PAM4. However, system designers are starting to look at 112 Gbps PAM4 data rates. Intuition would say that bleeding edge data rates like 112 Gbps PAM4 onl...

featured video

Accelerate Automotive Certification with Synopsys Functional Safety Test Solution

Sponsored by Synopsys

With the Synopsys Functional Safety Test Solution architecture, designers of automotive SoCs can integrate an automated, end-to-end BIST solution to accelerate ISO compliance and time-to-market.

Click here for more information about Embedded Test & Repair

featured paper

Learn how designing small is easier than you think

Sponsored by Texas Instruments

Designing with small-package ICs is easier than you think. Find out how our collection of industry's smallest signal-chain products can help you optimize board space without sacrificing features, cost, simplicity, or reliability in your system.

Click here to download the whitepaper

Featured Chalk Talk

Bluetooth Overview

Sponsored by Mouser Electronics and Silicon Labs

Bluetooth has come a long way in recent years, and adding the latest Bluetooth features to your next design is easier than ever. It’s time to ditch the cables and go wireless. In this episode of Chalk Talk, Amelia Dalton chats with Mark Beecham of Silicon labs about the latest Bluetooth capabilities including lower power, higher bandwidth, mesh, and more, as well as solutions that will make adding Bluetooth to your next design a snap.

Click here for more information about Silicon Labs EFR32BG Blue Gecko Wireless SoCs