First assembly puzzle!

This is our first assembly language puzzle for the new site! These puzzles are tests to see whether you are good enough of an assembly nerd, and to learn some tricks if you’re not =^_^=

Our first puzzle is of a classic type: size optimization.  It is for x86-32 assembly language, certainly the most widely known assembly language.  We will definitely do other puzzles for other processors though!

You might find that many of these puzzles are good ideas to place into compilers and other automated assembly/machine code generators.

The puzzle: In terms of opcode bytes, find the smallest sequence of x86-32 instructions to implement the following C/C++ code:

if ((x == 0) || (y == 0))
    goto label;

Rules:

  • x and y are 32-bit integers or pointers.
  • x and y are each already in general-purpose registers or memory locations of your choice.
  • Do not assume a particular state of the flags, except that you may assume the direction flag is always clear as that is its usual state.
  • You may destroy any general-purpose registers or memory locations as you see fit, including the locations of x and y.
  • Assume that label is within range of a short jump.
  • Do not assume that you have access to protected instructions.
  • In general, answers that are the same size but faster or less destructive are considered better than others.

I was rather verbose in the rules because it’s the first puzzle.  Future puzzles won’t necessarily mention these restrictions.

Answers that don’t fit all the rules but have other merits like creativity are certainly welcomed!

The smallest answer I could find was 6 bytes.  The straightforward answer is 8 bytes.  Good luck!

-Myria

(check comments for solution(s))

29 thoughts on “First assembly puzzle!”

  1. Pingback: dowhatimean.net
    • Great post! This really resonated with me. The practical insights you shared are exactly what I was looking for. On a related note about AI tools, I’ve been using AI Photo Spark for quick professional headshots — uploads selfies and generates studio-quality portraits in under a minute. Worth checking out.

      Reply
  2. Oops, I read it backwards…now I feel dumb. That code jumps if either is nonzero. If the two are in ecx and eax, and then

    jecxz label
    or eax,eax
    jz label

    So yeah, 6 bytes.

    Reply
  3. (I’m the post author. We haven’t gotten the site to show who posted what yet…)

    dowhatimean.net: You have what my 6 byte solution was. There is a problem with your code that results in 6 bytes rather than 4. “mul” sets the zero flag based on the low half of the result, not the whole double-sized result. Thus 0x80000000 * 0x80000000 would break your code. This is required in order to get it correct (my original solution):

    mul edx
    or eax, edx
    jz label

    Matt Parks: Omg, I totally forgot about jecxz! On older systems, your code is certainly much faster than mine. I don’t know about the P4 and A64 though, since they have really fast multiplies. It all depends on whether the mul is more expensive than the CISC-like (and therefore microcoded) jecxz and its accompanying branch misprediction penalty.

    -Melissa

    Reply
  4. Forgive me my ignorance Melissa…

    My answer would have been

    or eax, edx
    jz label

    I see no need for the mul 😉

    -stefan

    Reply
  5. Maybe something like

    Input: eax, ecx

    dec eax
    jo label
    jecxz label

    ??? (I don’t remember at the moment if underflow also triggers o flag)

    Reply
  6. Stefan – I tried that code snippet out on my trusty DOS debug, and the jo didn’t branch like it should…guess the overflow wasn’t set. Good thought though. Any 5-byte answer has to look something like that though…what other one-byte instructions modify the flags?

    Myria – keep the puzzles coming! This is fun.

    Reply
  7. Unfortunately, “inc” and “dec” do not modify the carry flag, because the 8080 (and its clone, Z80) did not. “inc” and “dec” do modify the overflow flag, however. The problem with overflow is that it represents a *signed* overflow/underflow (for “dec”, this means going from 80000000 to 7FFFFFFF). This makes it useless for this problem >_< The 5 byte solution I found isn't as big a trick as it might seem. -Myria

    Reply
  8. The 5-byte solution I came up with is:

    jecxz label
    xchg eax, ecx
    jecxz label

    xchg eax, ecx is a single-byte opcode. Strangely, this optimal solution is also the least destructive: x and y were not destroyed by the operation if the condition is false, although they did switch places.

    Thanks to Matt for reminding me about jecxz =)

    imul has 3 forms, unlike mul. The first is the same format as mul: edx:eax = eax * param. The second form is a multiply of any register (not just eax) by another. However, this only stores the low 32 bits of the result. The third form is dest = src * immediate, again only storing the low 32 bits of the result.

    None of these sets the zero flag when the *whole* result is zero, only when the low 32 bits is zero. They *do* set carry when the result overflows (meaning that the operands weren’t really zero to begin with). Unfortunately, there is no “jump if zero and not carry” instruction in x86, as no normal arithmetic comparison would need one.

    -Myria

    Reply
  9. You can’t do register*register with lea. You can only do register*X where X is 1, 2, 3, 4, 5, 8 or 9. (Technically, only 1, 2, 4, 8, but you can add one register as well, plus the multiplication. So lea eax, [eax*5] is actually lea eax, [eax*4+eax].)

    -Myria

    Reply
  10. I’m mortified that I made a stupid error like that. I haven’t programmed in asm since 1991 and I have no 32 bit debugger to test instructions so my memory is showing it’s age.
    Derek

    Reply
  11. Dadhikaka,
    That only works when they are equal or both 0. What happens when the arguments have no 1 bits in common?

    Reply
  12. jecxz is nice and small, but painfully slow on the K6 onward.
    They slowed down the loop instruction, because of a popular
    software *cough* using it in delay loops (not Turbo Pascal,
    the other popular one…), to 300 MHz or so, and jecxz seems
    to share the implementation or something.

    Doesn’t hinder me from using it in the bootloader though 😉

    Reply
  13. I also tried out the OR idea and got positive results, but others here seem to have had a different experience?

    My code exactly:

    mov eax, 0
    mov ebx, 0

    or eax, ebx
    jz label

    No matter what values I set EAX and EBX to, the jump only occurs if both are 0. Am I missing something?

    Reply
  14. After posting, it hit me that it’s supposed to be if one is 0, not both. Replacing the OR with an AND seems to have solved that – and it’s still 4 bytes.

    Reply
  15. I’ve discovered your blog in August 2017 and reached the end (= the beginning ;)) of the blog – this post – today, early in September 2017! Lots of super interesting information here! 🙂

    Thanks a lot! 🙂

    Reply
  16. This is a nice blast from the past — I remember wrestling with similar size-optimization puzzles back in the day. The jump-if-either-is-zero trick with `mul` and `or` is a classic, but the 5-byte solution you hinted at is the kind of thing that makes assembly so much fun. If anyone wants to test their skills on a modern twist, I’ve been playing with an AI video generator that turns text into cinematic clips — it’s a different kind of puzzle, but equally addictive. Check it out at minimax3.com.

    Reply
  17. Great post! This brings back memories of classic size-optimization puzzles. I remember spending hours on similar challenges back in the day. The 6-byte solution using `mul` is clever, though I’m curious about that 5-byte trick you mentioned — I’ll have to dig deeper into the comments for the answer.

    On a slightly different note, if you’re into optimizing code generation, you might appreciate modern AI tools that handle similar problem-solving in a different domain. I’ve been experimenting with Wan3Video for generating cinematic video from text prompts — it’s like a puzzle in itself, but for visual storytelling. Worth a look if you’re into creative tech.

    Reply
  18. This is a great throwback to the classic days of x86 optimization puzzles! It reminds me of how much fun it is to shave off those extra bytes. For anyone diving into these challenges, I’ve found that modern tools can help visualize and debug such low-level code more efficiently. Speaking of handy utilities, I recently came across a free online tool at claudewatermarks.com that detects and removes hidden Unicode watermarks and AI text artifacts from Claude-generated content. It’s a neat resource for cleaning up AI-assisted assembly documentation or any generated code comments, ensuring your final write-ups are pristine. Definitely worth a look for fellow nerds who appreciate precision in both code and text!

    Reply
  19. This brings back memories of classic x86 optimization puzzles! The 6-byte solution with `mul`/`or`/`jz` is clever, but I’m curious about your 5-byte trick. For anyone into low-level coding, I’ve been exploring how modern AI tools can generate optimized assembly-like logic from high-level specs — it’s a fun contrast to hand-tuning opcodes. If you’re into that intersection, check out minimax3.com for AI-driven video generation, but for pure assembly nerdery, this site is gold. Keep the puzzles coming!

    Reply
  20. Great post! As someone who enjoys low-level optimization challenges, this x86-32 size puzzle is a fun mental exercise. The 6-byte solution using `jecxz` combined with `or eax,eax` is clever, and I appreciate the discussion about `mul` flag behavior—easy to overlook.

    If you enjoy this kind of creative constraint-solving, you might also like experimenting with AI-assisted code generation. I recently tried an AI rap generator at airapgenerator.app that turns lyrics into full tracks—it’s a totally different kind of “assembly” but equally fun to tinker with. Definitely worth a look for a creative break between puzzles!

    Reply
  21. Animate Photo AI is an easy-to-use online AI photo animator that turns still images into engaging videos. Upload a photo and describe the desired motion to create talking photos, revive old memories, add 3D parallax effects, or produce dynamic social media content—no editing skills required.

    Reply

Leave a Comment