{"id":19738,"date":"2014-01-09T20:19:13","date_gmt":"2014-01-09T20:19:13","guid":{"rendered":"http:\/\/ok-cleek.com\/blogs\/?p=19738"},"modified":"2014-05-06T19:46:40","modified_gmt":"2014-05-06T19:46:40","slug":"zap-eax-mm1","status":"publish","type":"post","link":"https:\/\/ok-cleek.com\/blogs\/?p=19738","title":{"rendered":"ZAP [eax], [mm1]"},"content":{"rendered":"<p>Assembly language... <\/p>\n<p>(scared yet?)<\/p>\n<p>Writing it is like riding a bike without training wheels. No, more like riding a bike without training wheels or brakes, and it's a <a href=\"http:\/\/en.wikipedia.org\/wiki\/Fixed-gear_bicycle\">fixie<\/a>. And you're riding down Mt Doom with a dwarf standing on the back pegs.<\/p>\n<p>So, a few years ago I did a major revision of one of my software packages, and added support for 64-bit processors as part of the work. Along with a lot of nit-picky work, there were a few architectural changes, and one of them was reworking some in-line assembly I was using for performance reasons. The code is used to blend two images: pixel_top + pixel_bottom = pixel_new. It's the kind of thing that absolutely flies when using MMX because you can do 8 pixels at a time. Anyway, in x64, the MS C++ compiler doesn't allow in-line ASM as it does in Win32. Not exactly sure why. Doesn't matter. No big deal. I just moved each chunk of ASM to an external .ASM file, put a \"PROC\" and \"END\" around each, added parameter lists, etc.. Only slightly more complex than copy\/paste.<\/p>\n<p>And that worked fine for <i>years<\/i>. Until yesterday.<\/p>\n<p>Yesterday I learned that one of those functions had started crashing in certain situations. And I stared at the code for hours and didn't see anything wrong with the logic - the code looked like it should do exactly what it was supposed to do. And it was! But it wasn't. For some reason, in release mode, with full optimizations turned on and with a certain data size, a pointer was going crazy and running off into the woods, where it encountered an angry wizard who killed the process dead.<\/p>\n<p>Then I looked under a rock I found on the internet and learned something! <\/p>\n<p>When you write in-line assembly with Microsoft's C\/C++ compiler, you don't have to worry much about the contents of most of the common CPU registers when entering or leaving your _asm{...} blocks. The registers are almost like local variables. You can put anything you want in them and the compiler doesn't care and it will clean up after you. But when you move your ASM to an external (non-inline) function and use the MASM compiler (aka the 'assembler'), you are expected to behave as a responsible adult. You are supposed to give the assembler a list of all the registers you are going to use. You are supposed to do that so that the compiler can then coordinate its own register usage with yours - so that you don't interfere on each other. You're <i>supposed<\/i> to tell it; the ASM compiler doesn't actually care one way or another - <i>want to ride your bike without a seat? ASM doesn't give a crap. Go ahead.<\/i> Checking that you've done this would be easy, but the assembler doesn't bother. And if you don't tell the compiler that you're using a given register - EAX for example - it will assume EAX is available for other uses and that it doesn't have to worry about you meddling with EAX. But then if you <i>do<\/i> meddle with EAX in your function, and the compiler was using EAX to hold a pointer, and your program comes out of your function but now that pointer has gone crazy and run off into the woods where the angry wizard lives... well, your program is going to get killed. <\/p>\n<p>Or maybe it won't! Maybe three years of new revisions will go by and never once will the compiler decide it cares about EAX when calling your function. It will be using EBX or EDX or whatever to hold that one pointer. But then <i>one day<\/i> (yesterday, in my case) it will decide to use EAX... and you won't know it until you hear the ZAP! of the angry wizard's staff flicking your program out of existence.<\/p>\n<p>And that's why one should avoid assembly whenever possible. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Assembly language... (scared yet?) Writing it is like riding a bike without training wheels. No, more like riding a bike without training wheels or brakes, and it's a fixie. And you're riding down Mt Doom with a dwarf standing on the back pegs. So, a few years ago I did a major revision of one [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[50],"tags":[],"class_list":["post-19738","post","type-post","status-publish","format-standard","hentry","category-programming"],"_links":{"self":[{"href":"https:\/\/ok-cleek.com\/blogs\/index.php?rest_route=\/wp\/v2\/posts\/19738","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ok-cleek.com\/blogs\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ok-cleek.com\/blogs\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ok-cleek.com\/blogs\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/ok-cleek.com\/blogs\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=19738"}],"version-history":[{"count":12,"href":"https:\/\/ok-cleek.com\/blogs\/index.php?rest_route=\/wp\/v2\/posts\/19738\/revisions"}],"predecessor-version":[{"id":19755,"href":"https:\/\/ok-cleek.com\/blogs\/index.php?rest_route=\/wp\/v2\/posts\/19738\/revisions\/19755"}],"wp:attachment":[{"href":"https:\/\/ok-cleek.com\/blogs\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=19738"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ok-cleek.com\/blogs\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=19738"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ok-cleek.com\/blogs\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=19738"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}