0

I got x86 code for addition of two numbers having comp3 type(see cobol) , logic of addition is quite strange and confusing but gives correct result .can anybody help me with this code

>>00401229<<  add         eax,33333333h    ;  [00 00 01 23] + [33 33 33 33] = [33 33 34 56]eax  

0040122E  add         edx,33333333h        ;  [00 00 02 20] + [33 33 33 33] = [33 33 35 53]edx

00401234  mov         ebx,eax          ; copying eax to ebx   ; ebx = eax = 33 33 34 56

00401236  xor         ebx,edx          ; [33 33 34 56] xor [33 33 35 53] = [00 00 01 05](EBX)

00401238  add         eax,edx          ; [33 33 34 56]eax  + [33 33 35 53]edx = [66 66 69 A9]eax 

0040123A  xor         ebx,eax          ; [00 00 01 05](ebx) xor [66 66 69 A9](eax) = [66 66 68 AC](ebx)

0040123C  shr         ebx,3                ; 3 >> [66 66 68 AC](ebx) =  [0C CC CD 15](ebx)

0040123F  not         ebx                  ; [0C CC CD 15](ebx) NOT  ==>  [F3 33 32 EA](ebx)

00401241  and         ebx,22222222h        ; [F3 33 32 EA](ebx) & [22 22 22 22] = [22 22 22 22]

00401247  lea         ebx,[ebx+ebx*2]      ;ebx = 66 66 66 66

0040124A  sub         eax,ebx          ;[66 66 69 A9]eax - [66 66 66 66]ebx = 343 

more code may not be relevant

004011D1  mov         eax,3C120000h                     // EAX = 3C120000h 

004011D6  mov         dword ptr [$HELLO.DATA+0D8h (409A08h)],eax   // at  409A08h moving data 00 00 12 3c

004011DB  mov         eax,0C220000h                    // EAX = 0C220000h   

004011E0  mov         dword ptr [$HELLO.DATA+0E0h (409A10h)],eax   // at 409A10h moving data 00 00 22 0c

004011E5  sub         eax,eax                      // may be clearing eax

004011E7  mov         eax,dword ptr [$HELLO.DATA+0D8h (409A08h)]   // copying from  409A08h data(00 00 12 3c) to EAX

004011EC  bswap       eax                      // eax becomes  00 00 12 3c from 3C 12 00 00h

004011EE  sub         edx,edx                      //  perhaps clearing edx

004011F0  mov         edx,dword ptr [$HELLO.DATA+0E0h (409A10h)]  // copying from  409A08h data 00 00 22 0c to EDX

004011F6  bswap       edx                     //   edx becomes  00 00 22 0c from  0C 22 00 00

004011F8  mov         ebx,eax ....................................// copying from eax to ebx , ebx becomes 00 00 12 3c  


004011FA  and         ebx,0Fh ....................................// ebx & 0Fh,(00 00 12 3c)&(0Fh) => 00 00 00 0C
                                  // extracting sign from value ebx ,storing 'C' in ebx

004011FD  mov         ch,byte ptr $HELLO.LIT+230h (40E230h)[ebx]  // 'ch' refer to 8 to 15 bits of ecx register         
                                  // ecx register -> |_15 to 8_| 7 to 0|  , 
                                  // byte from ebx  is copied to ecx position 8 to 15 

00401203  mov         ebx,edx                     // value of edx ( 00 00 22 0C ) copied to ebx  

00401205  and         ebx,0Fh                     // extracting sign of second no by preserving last        

                             nibble , now ebx has sign of second no i.e 'C'

00401208  mov         cl,byte ptr $HELLO.LIT+230h (40E230h)[ebx]  //   'CL' refer to '0 TO 7th' bit of 'E C X'
                                  // Copying last 7 bits of ebx to cl 
                                  // ECX Becomes ECX =  8E 19 '0C' '0C' 
                                  // contains sign of both var ,     var1 and var 2
                                                  15 to 8 and 7 to 0

0040120E  shr         eax,4                   // shifitng EAX right , removing sign nibble from var1

00401211  shr         edx,4                       // shifitng EDX right , removing sign nibble from var2

                                var2 , EDX = 00000220
                                var1 , EAX = 00000123 


00401214  cmp         ch,cl                     // comparing the sign of both number 
                                // Both ch & cl part of ECX

                //CMP - If the two values are equal, the Z Flag is set (1) otherwise it is not set (0)



00401216  je          $HELLO.CODE+219h (401229h)  // if both sign equal jump to '401229h'

                //JE and JZ : a conditional jump when ZF (the "zero" flag) is equal to 1.

                            //  var2 , EDX = 00000220
                            //  var1 , EAX = 00000123 
cschneid
  • 10,237
  • 1
  • 28
  • 39
naumaan
  • 55
  • 11
  • Help you in what way? – Bill Woodger Feb 14 '17 at 08:38
  • hi , look at the addition code , why its adding 33 33 33 33 to both nums,why using xor so on .. each instruction of addition module seems to me questionable ... if u could tell , what is going on ... – naumaan Feb 14 '17 at 08:41
  • I guess it is the way the author chose to convert a Binary Coded Decimal (BCD) into a binary value. In a BCD, there are only numeric digits, and each digit represents its decimal value. Having shifted off the sign, the packed-decimal has become a true BCD, which there is no native support for doing maths with (I assume). – Bill Woodger Feb 14 '17 at 08:58
  • yup that I know , look at addition logic that make no sense – naumaan Feb 14 '17 at 09:00
  • 1
    Probably the coder is a mathematician :-), it's like the "I'll guess the number you are thinking of" tricks where the seemingly nonsense answer contains within it the original number - if you know how. Forget about the assembler, write down in English what the code in the first block is doing. Then leave your desk, continuing to forget about assembler, and try to work out the trick. Bear in mind that 3+6=9, which is one less than 10. You'll need to work out the intent of the 22222222, so in what cases would the result not be 22222222? – Bill Woodger Feb 14 '17 at 09:09
  • yes I will do that thanks, above code is gen by x86 , definitely a coder, but not a human :) – naumaan Feb 14 '17 at 09:11
  • I haven't tried to work the trick out, and bear in mind that things could be done in there that are not relevant to anything. Why clear to zero, then set the same to a value? But I don't know your asm. – Bill Woodger Feb 14 '17 at 09:12
  • Humans can code too. If you take a mathematician, perhaps they will more likely code in "number tricks". Look here: http://stackoverflow.com/q/39854413/1927206. Original code by an engineer. Actual result is "wrong", but it is the specific result the coder wanted. No COBOL programmer would have done the task that way. Touch something in there, and it'll break. Once you work out what is going on, I don't think you'll use the technique in normal work, but, you've been exposed to different ways of thinking about it, which is good. – Bill Woodger Feb 14 '17 at 09:18
  • 1
    If you looked at Asm from the 60s, you'd be shocked about how order-specific a lot of the code would be, as one instruction relies on the previous to have left a particular state, which means you can save on storage by using that handy value. They could do a lot of stuff in less than a small number of K, but changing the programs later.... – Bill Woodger Feb 14 '17 at 09:22
  • Oh, and you'd best put more information in your question, so that it becomes a question. It'll suffer downvotes and closevotes likely otherwise. – Bill Woodger Feb 14 '17 at 09:47
  • The adding x'33 33 33 33' to both numbers makes a certain sense. Consider (x'18' + x'05') + (x'03' + x'03') = x'23' (ie decimal 18 + 5 = 23). Adding x'33 33 33 33' to each number is equivalent to adding x'66 66 66 66' to the total. Adding 6 does the carry. i.e. adding 6 to x'A' .. x'F' converts it to decimal (x'10' .. x'15') – Bruce Martin Feb 15 '17 at 00:13
  • presume adding x'33 33 33 33' to both makes the other adjustments easier to calculate. consider x'0718' + x'0628' = x'0C41', you would need to add x'0606' to get x'1347'. To convert a hex add to a decimal add you need to add x'hi jk lm no' where h->o is either 0 or 6. – Bruce Martin Feb 15 '17 at 04:20
  • This can also be done as Hex_Sum + x'66 66 66 66' - x'aa aa aa aa' where a is either 0 or 6 which is equivalent to Hex_Sum + x'66 66 66 66' + x'hi jk lm no' + x'00 00 00 01' when h->o is either 9 or F. – Bruce Martin Feb 15 '17 at 04:21

1 Answers1

2

Partial Answer

Background

To understand what is going on lets consider what happens at the level of adding 2 single digit hex-decimal numbers together

If the sum of the 2 hex-decimal digits add up to < 10; the result is exactly the same as adding 2 decimal numbers together:

x'4' + x'5' = x'9' ~ 9

But if the 2 digits add up to a number >= 10, we can add x'6' to get the decimal equivalent

x'5' + x'6' = x'B'      and x'b'  + x'6' = x'11' ~ 5 + 6 = 11
x'8' + x'9' = x'11'     and x'11' + x'6' = x'17' ~ 8 + 9 = 17

The actual formula (at single digit level) is more complicated

if digit1 + digit2 < 10 (x'a')
   total = digit1 + digit2 + x'6' - x'6'
else
   total = digit1 + digit2 + x'6' - x'0'

Formula

Hexidecimal addition can be used to do Decimal addition using this formular

     Number_1 + Number_2 + x'66 66 66 66' - x'hi jk lm no'

Where h --> o in x'hi jk lm no' are either 0 or 6. Basically if Number_1.digit + number_2.digit >= 10 then h --> o will be 0 otherwise it will be 6.

Examples:

 [00 00 01 23] + [00 00 02 20} + [66 66 66 66] - [66 66 66 66] = [00 00 03 43]
 [00 00 07 18] + [00 00 06 28} + [66 66 66 66] - [66 66 06 06] = [00 00 13 46]
 [00 00 01 83] + [00 00 02 91} + [66 66 66 66] - [66 66 66 06] = [00 00 04 74]

Explaining the code

The Following 4 statements (from the first 5) calculate: number_1 + Number_2 + x'66 66 66 66'

  00401229  add         eax,33333333h    ;  [00 00 01 23] + [33 33 33 33] = [33 33 34 56]eax  
  0040122E  add         edx,33333333h    ;  [00 00 02 20] + [33 33 33 33] = [33 33 35 53]edx
  00401234  mov         ebx,eax          ; copying eax to ebx   ; ebx = eax = 33 33 34 56
    
  00401238  add         eax,edx          ; [33 33 34 56]eax  + [33 33 35 53]edx = [66 66 69 A9]eax 

lines at the end

The Lines at the end are also easy

  00401241  and         ebx,22222222h        ; [F3 33 32 EA](ebx) & [22 22 22 22] = [22 22 22 22]
  00401247  lea         ebx,[ebx+ebx*2]      ;ebx = 66 66 66 66
  

The number x'6' is represented as b'0110', i.e. 2 bits are set. It is much easier to set/clear 1 bit i.e. x'2' is b'0010' hence the 22222222h.

So the following line calculates x'hi jk lm no' / 3:

  00401241  and         ebx,22222222h        ; [F3 33 32 EA](ebx) & [22 22 22 22] = [22 22 22 22]
  

and the second line multiplies (x'hi jk lm no' / 3) by 3 giving us x'hi jk lm no'; At bit level, it converts a 0010 to 0110.


Working backwards

looking at the 2 previous lines

 0040123C  shr         ebx,3                ; 3 >> [66 66 68 AC](ebx) =  [0C CC CD 15](ebx)
 0040123F  not         ebx                  ; [0C CC CD 15](ebx) NOT  ==>  [F3 33 32 EA](ebx)

The Shift right 3 will shift the 'carry bit' back to the 2 bit (ready to and with x'2'). Consider adding 2 digits at bit level:

 8 + 9 = b'1000' + b'1001' = b'10001' 

next we need to add 6 for the decimal adjustment

 b'10001' + b'0110' = b'10111'

If you shift b'1 0111' 3 bits to the right you get b'0010' (x'2'), the not reverses this to b'1101' ready for the and to x'22 22 22 22' in this step that has already been discussed:

  00401241  and         ebx,22222222h        ; [F3 33 32 EA](ebx) & [22 22 22 22] = [22 22 22 22]

Possible problem

I suspect the code will loose the top Carry bit so

[50 00 00 01] + [50 00 00 01]

will probably be [A0 00 00 02] and not [00 00 00 02] as it should be. The second part may correct for this ???

If the number started as a Comp-3 and was right shifted 4 bits, this will not be a problem

Community
  • 1
  • 1
Bruce Martin
  • 10,358
  • 1
  • 27
  • 38