7

i'm beginning assembly, i'm using nasm for assembling the code, i'm trying to process a string residing in memory and change it, i want to check if a byte is in a certain range (ascii) so i can decide what to do with it, i can't seem to figure how to check if a value is in a certain range, i know all about the different kind of jump flags but how can i combine 2 cmp statements ?

my question is : how do i produce something similiar to this in assembly ?

if (x>=20 && x<=100)
     do something

thanks alot !

Matan
  • 581
  • 2
  • 4
  • 13

4 Answers4

31

There is a way to express a range check like this using only a single conditional jump:

     sub  eax,  20
     cmp  eax,  80
     ja   END
     // do something
END: ret

This is a very common optimization trick when working with integer ranges. The initial subtract maps the range [20,100] to [0,80]; membership in that range is then be checked with a single unsigned comparison.

Note also that the same thing can be done in C:

unsigned int upperBound = 100;
unsigned int lowerBound = 20;
if (yourValue - lowerBound <= upperBound - lowerBound) {
    // do something
}
Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
Stephen Canon
  • 103,815
  • 19
  • 183
  • 269
  • 2
    Compilers know this optimization, at least for compile-time-constant ranges (even using the unsigned-compare trick for signed ranges). They can't safely do it when the bounds aren't known at compile time, and in some cases fail to do it even if they can prove that `upper>lower` with runtime-variable ranges, though. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69615. – Peter Cordes Jun 02 '18 at 08:37
  • Related: [Reverse-engineering asm using sub / cmp / setbe back to C? My attempt is compiling to branches](https://stackoverflow.com/a/54976091) example of GCC compiling range checks to sub/cmp/unsigned condition. (Or `lea`/`cmp` if you just need the condition without modifying the original value, and the start of the range is a constant.) – Peter Cordes Oct 16 '22 at 09:48
7

Depending on what syntax you're using, and assuming x is in the eax register, something like this:

cmp  eax, 20
jl   ELSE
cmp  eax, 100
jg   ELSE
#do something
jmp  END

ELSE:
#do else

END:
Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
  • But, After comparing eax with 20 is matched then it'll jump to ELSE label without checking 2nd conditional jump. in question the condition include && (AND) operation not || (OR). – Ameer Hamza Apr 09 '19 at 21:17
  • @AmeerHamza Per De Morgan’s Laws, `!(a && b) == (!a || !b)`, and the latter is what is expressed here, as we jump to `ELSE` when either sub condition is not met, thus only not jumping when both *are* met. – Andrew Marshall Apr 09 '19 at 23:24
1

You can try compiling it from a higher level language (C/C++/ ...) with optimalisations at high (-O3 for gcc), and have a look at what the compiler generates (objdump). It should generate very efficient code.

Jan
  • 1,807
  • 13
  • 26
  • 1
    I'd almost suggest running it without optimizations first. Running it with may result in code that isn't easy to understand at first (more exotic instructions). Definitely look at the code for all levels of optimization (including none). – Andrew Marshall Mar 04 '11 at 16:44
0

Like that?

x<20
if false jump to ELSE
x>100
if false jump to ELSE
  do something
  jump to ENDIF
:ELSE
  do something else
:ENDIF

Or do you mean using only one assembly instruction?

ajuc
  • 590
  • 6
  • 12
  • yes... is there a way of using only one instruction ? or a minimum amount of them – Matan Mar 04 '11 at 16:34
  • 1
    An instruction in assembly does _one_ thing. If you're not doing just one thing it cannot be done in a single instruction, unless their is a special instruction for that case. Assembly is very verbose. – Andrew Marshall Mar 04 '11 at 16:45