1

so my input is a 9 character long code containing letters A-Z and number 0-9.

Each character has a different mathematic operation attached to it e.g. Character 1 from 647388ABC (6) will be multiplied by 5, (4) will by multiplied by 2 etc.

All the results will be summed up later on but first I need to be able to access them I individually.

mov eax, [esp+8] ; this gives me the input in eax 
mov ebx, [eax+4] ; code into ebx

My idea now was just to do it like this:

mul [ebx+1], 5

And just continue up until I arrived at the last character but it does not seem to work

Etti _
  • 21
  • 2

1 Answers1

3

Your input characters are in the form of a string? If so, each character individually has to then be converted to an integer. You did not specify if each integer is an arbitrary individual digit or multiples of base 10. Is "123" just 1, 2, 3 or 123(one hundred twenty three)?

The mul instruction uses the al, ax, or eax registers and stores the result in ax, dx:ax or edx:eax (hi bits : lo bits). But more convenient is imul: you can use it with an immediate operand and only produce an output of the same width as the input.

lea   ecx,[esp+8] ;ecx points to input (647388ABC)

movzx eax, byte [ecx] ;get a single byte from ecx and move it into al
sub   eax, 48         ; ASCII digit -> integer.  48 = '0'
imul  eax, 5          ; result 5*6 is stored in eax

To handle letters, you'd want to branch on the sub result being <= 9 (unsigned), otherwise subtract another amount.

Extension: Assuming eax already holds the byte we can do a branch to check if it's a character from "A" - "Z" where "A"==0 && "Z"==25 then perform the necessary operation (subtraction) to get the integer.

cmp eax,65
jl digit
cmp eax,90
jg terminate
sub eax,65
jmp operation
digit:
sub eax,48
operation:
                ;perform mathematical operation here
terminate:
ret
Jade
  • 51
  • 4
  • Sorry, I should have specified: The Input are individual digits so 123 is 1,2,3 Why does it have to be converted to an integer? If I understand the code correctly, does that mean to multiply the 4 (2nd digit in 647388ABC) I'd have to replace the [ecx] with [ecx+1] ? – Etti _ Dec 05 '20 at 14:18
  • 1
    *convert it to decimal* isn't an accurate description. You're converting an ASCII code for a decimal digit to a (binary) integer from 0..9. (Assuming the input was from `'0'` .. `'9'`. Which is a bad assumption because the OP's input includes some alphabetic characters. I think they might be supposed to add up actual ASCII codes, not the decimal digits those codes represent. Not a clear question.) – Peter Cordes Dec 05 '20 at 14:25
  • Since this is 32-bit code, you'd normally want to `movzx eax, byte [ecx]`; that's more efficient than xor-zeroing EAX and then merging a low byte into it. And you'd normally want `imul eax, 5`. Both those instructions are guaranteed to be available since this is 32-bit code. Or of course `lea eax, [eax + eax*4]` to multiply by 5 specifically. – Peter Cordes Dec 05 '20 at 14:26
  • @PeterCordes Ok sorry, I should have been more clear. The task is: Have a string (9 digits long - can contain either numbers or letters) input, multiply 1st, 4th and 7th digit with 7, multiply 2nd, 5th and 8th with 3 and multiply 3rd, 6th and 9th with 1. All results should then be added up and the last digit of the result is my end result. – Etti _ Dec 05 '20 at 14:34
  • My idea for multiplying the letters was the following: Input: A12345678 // To see if A is a Number or Letter I'd cmp it with 65, if its equal or greater than it has to be a Letter, otherwise its a Number. If its a Letter I'd sub 55 to get the value of the letter (A = 10, B = 11, C = 12 etc. - thats given) – Etti _ Dec 05 '20 at 14:43
  • @Etti_: Ok, so you have a number in base 36, and you *do* need to convert each digit from an ASCII code to its integer value. Just like for hex string -> integer, but allowing digits up to Z instead of just F. So you can take any hex-input example. – Peter Cordes Dec 05 '20 at 14:53
  • @PeterCordes Yes I actually wasn't sure what they were asking. Some of it was based on assumption. I should have written it more clear though, instead of decimal used integer value of ascii representation or base 10 integer. But a lot of the answer was based off assumption. I couldn't flag or comment for clearer question. – Jade Dec 06 '20 at 14:38
  • You have enough rep to comment now, so you'll be able to do that next time. BTW, your edit broke your answer; `mul 5` doesn't exist, only `imul eax, 5`. I fixed that for you. If you want, you could expand on it to handle branching for number vs. letter digits. – Peter Cordes Dec 06 '20 at 14:53
  • @PeterCordes I added the branching for checks, have a look and see if it needs changes. – Jade Dec 06 '20 at 17:00
  • First of all, style: code should be indented to the right of labels, see this codereview: [Checking if a number is prime in NASM Win64 Assembly](https://codereview.stackexchange.com/a/204965). Also style: don't hard-code magic numbers like `90`, use `'Z'`. Other than that, looks like your logic is correct (as long as you can assume that every character below `'A'` is a decimal digit). – Peter Cordes Dec 06 '20 at 17:06
  • For efficiency, it's more branchy than it needs to be. I would have done it with `sub eax, '0'` / `cmp eax, 10` / `jb operation` / `sub eax, 'A' - '0'` / fall through into `operation:`. Or 2x LEA and cmp/cmov if I wanted to keep the critical-path latency down to 1 cycle for both number and letter. The significant optimization is doing a range-check with sub/cmp/unsigned-condition instead of 2 signed compares, avoiding both `cmp eax,65` and `sub eax,65`. [double condition checking in assembly](https://stackoverflow.com/a/5197264) and [this](https://stackoverflow.com/a/54585515/224132) answer – Peter Cordes Dec 06 '20 at 17:14