What's this assembly doing?












6















I have been trying to figure out the assembly for part of a DOS game and there is an operation that keeps getting called that uses all 4 registers. I can see what each line does but I can't for the life of me figure out what all the code together is meant be doing.



Can anyone give me some idea?



The code is:



seg000:3825 some_math_op_on_regs proc far; CODE XREF: sub_72C6+19FP
seg000:3825 ; sub_72C6+1DDP ...
seg000:3825 cmp cl, 10h
seg000:3828 jnb short loc_383A ; Jump if CF=0
seg000:382A mov bx, dx ; c register is < 16; move d to b
seg000:382C shr ax, cl ; Shift a right by value in c (logical)
seg000:382E sar dx, cl ; Shift d right by value in c (arithmetic)
seg000:3830 neg cl ; Negate c (2's complement)
seg000:3832 add cl, 10h ; Add 16 to c
seg000:3835 shl bx, cl ; Shift b left by value in c (logical)
seg000:3837 or ax, bx ; OR a and b, store result in a
seg000:3839 retf
seg000:383A ; --------------------------------------------------------------------
seg000:383A
seg000:383A loc_383A: ; CODE XREF: some_math_op_on_regs+3j
seg000:383A sub cl, 10h ; c register is >= 16; subtract 16 from c
seg000:383D xchg ax, dx ; Switch values in a and d
seg000:383E cwd ; Convert word to doubleword
seg000:383F sar ax, cl ; Shift a right by value in c (arithmetic)
seg000:3841 retf
seg000:3841 some_math_op_on_regs endp









share|improve this question









New contributor




Jez is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

























    6















    I have been trying to figure out the assembly for part of a DOS game and there is an operation that keeps getting called that uses all 4 registers. I can see what each line does but I can't for the life of me figure out what all the code together is meant be doing.



    Can anyone give me some idea?



    The code is:



    seg000:3825 some_math_op_on_regs proc far; CODE XREF: sub_72C6+19FP
    seg000:3825 ; sub_72C6+1DDP ...
    seg000:3825 cmp cl, 10h
    seg000:3828 jnb short loc_383A ; Jump if CF=0
    seg000:382A mov bx, dx ; c register is < 16; move d to b
    seg000:382C shr ax, cl ; Shift a right by value in c (logical)
    seg000:382E sar dx, cl ; Shift d right by value in c (arithmetic)
    seg000:3830 neg cl ; Negate c (2's complement)
    seg000:3832 add cl, 10h ; Add 16 to c
    seg000:3835 shl bx, cl ; Shift b left by value in c (logical)
    seg000:3837 or ax, bx ; OR a and b, store result in a
    seg000:3839 retf
    seg000:383A ; --------------------------------------------------------------------
    seg000:383A
    seg000:383A loc_383A: ; CODE XREF: some_math_op_on_regs+3j
    seg000:383A sub cl, 10h ; c register is >= 16; subtract 16 from c
    seg000:383D xchg ax, dx ; Switch values in a and d
    seg000:383E cwd ; Convert word to doubleword
    seg000:383F sar ax, cl ; Shift a right by value in c (arithmetic)
    seg000:3841 retf
    seg000:3841 some_math_op_on_regs endp









    share|improve this question









    New contributor




    Jez is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.























      6












      6








      6








      I have been trying to figure out the assembly for part of a DOS game and there is an operation that keeps getting called that uses all 4 registers. I can see what each line does but I can't for the life of me figure out what all the code together is meant be doing.



      Can anyone give me some idea?



      The code is:



      seg000:3825 some_math_op_on_regs proc far; CODE XREF: sub_72C6+19FP
      seg000:3825 ; sub_72C6+1DDP ...
      seg000:3825 cmp cl, 10h
      seg000:3828 jnb short loc_383A ; Jump if CF=0
      seg000:382A mov bx, dx ; c register is < 16; move d to b
      seg000:382C shr ax, cl ; Shift a right by value in c (logical)
      seg000:382E sar dx, cl ; Shift d right by value in c (arithmetic)
      seg000:3830 neg cl ; Negate c (2's complement)
      seg000:3832 add cl, 10h ; Add 16 to c
      seg000:3835 shl bx, cl ; Shift b left by value in c (logical)
      seg000:3837 or ax, bx ; OR a and b, store result in a
      seg000:3839 retf
      seg000:383A ; --------------------------------------------------------------------
      seg000:383A
      seg000:383A loc_383A: ; CODE XREF: some_math_op_on_regs+3j
      seg000:383A sub cl, 10h ; c register is >= 16; subtract 16 from c
      seg000:383D xchg ax, dx ; Switch values in a and d
      seg000:383E cwd ; Convert word to doubleword
      seg000:383F sar ax, cl ; Shift a right by value in c (arithmetic)
      seg000:3841 retf
      seg000:3841 some_math_op_on_regs endp









      share|improve this question









      New contributor




      Jez is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.












      I have been trying to figure out the assembly for part of a DOS game and there is an operation that keeps getting called that uses all 4 registers. I can see what each line does but I can't for the life of me figure out what all the code together is meant be doing.



      Can anyone give me some idea?



      The code is:



      seg000:3825 some_math_op_on_regs proc far; CODE XREF: sub_72C6+19FP
      seg000:3825 ; sub_72C6+1DDP ...
      seg000:3825 cmp cl, 10h
      seg000:3828 jnb short loc_383A ; Jump if CF=0
      seg000:382A mov bx, dx ; c register is < 16; move d to b
      seg000:382C shr ax, cl ; Shift a right by value in c (logical)
      seg000:382E sar dx, cl ; Shift d right by value in c (arithmetic)
      seg000:3830 neg cl ; Negate c (2's complement)
      seg000:3832 add cl, 10h ; Add 16 to c
      seg000:3835 shl bx, cl ; Shift b left by value in c (logical)
      seg000:3837 or ax, bx ; OR a and b, store result in a
      seg000:3839 retf
      seg000:383A ; --------------------------------------------------------------------
      seg000:383A
      seg000:383A loc_383A: ; CODE XREF: some_math_op_on_regs+3j
      seg000:383A sub cl, 10h ; c register is >= 16; subtract 16 from c
      seg000:383D xchg ax, dx ; Switch values in a and d
      seg000:383E cwd ; Convert word to doubleword
      seg000:383F sar ax, cl ; Shift a right by value in c (arithmetic)
      seg000:3841 retf
      seg000:3841 some_math_op_on_regs endp






      disassembly x86 dos






      share|improve this question









      New contributor




      Jez is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      Jez is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 7 hours ago









      perror

      11.3k1767130




      11.3k1767130






      New contributor




      Jez is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 9 hours ago









      JezJez

      1334




      1334




      New contributor




      Jez is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      Jez is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      Jez is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






















          2 Answers
          2






          active

          oldest

          votes


















          7














          This looks like a 32-bit shift right compiler helper. In 16-bit era, 32-bit numbers were represented by a pair of registers, in this case ax:dx. The check for 16 is an optimization: if the shift is over 16, the low register value is lost completely, so it can be discarded and replaced by dx>>(shift-16), while the high register is filled with the sign bit as the result of the cwd instruction. Here's the (lightly) commented source code from the Borland C runtime library which seems to match yours:



          ;-----------------------------------------------------------------
          ;| H_LRSH.ASM -- long shift right |
          ;-----------------------------------------------------------------

          ;
          ; C/C++ Run Time Library - Version 5.0
          ;
          ; Copyright (c) 1987, 1992 by Borland International
          ; All Rights Reserved.
          ;

          INCLUDE RULES.ASI

          _TEXT segment public byte 'CODE'
          assume cs:_TEXT
          public LXRSH@
          public F_LXRSH@
          public N_LXRSH@

          N_LXRSH@:
          pop bx ;fix up for far return
          push cs
          push bx
          LXRSH@:
          F_LXRSH@:
          cmp cl,16
          jae lsh@small
          mov bx,dx ; save the high bits
          shr ax,cl ; now shift each half
          sar dx,cl
          ;
          ; We now have a hole in AX where the lower bits of
          ; DX should have been shifted. So we must take our
          ; copy of DX and do a reverse shift to get the proper
          ; bits to be or'ed into AX.
          ;
          neg cl
          add cl,16
          shl bx,cl
          or ax,bx
          retf
          lsh@small:
          sub cl,16 ; for shifts more than 15, do this
          ; short sequence.
          xchg ax,dx ;
          cwd ; We have now done a shift by 16.
          sar ax,cl ; Now shift the remainder.
          retf
          _TEXT ends
          end





          share|improve this answer































            4














            It appears to be a 32 bit right shift with the 32 bit number provided in dx:ax, and cl being the number of bits to shift.



            If you assume cl is over 16, a right shift by more than 16 bit only needs to care about the upper 16 bit, which are stored in dx, because the lower 16 bit are shifted out anyway.



            So that's exactly what the 2nd block does. If cl larger than 16, move dx (upper 16 bit) into ax and convert it to a 32 bit number, subtract 16 from cl because this is implicitly done by ignoring the lower 16 bit, then shift the upper part (which is now dx:ax thanks to the cwd) by that number.



            I didn't try to understand the top part, but my assumption is it does exactly the same for shift widths below 16 bits.



            Basically, it's a 32 bit right shift done in 16 bit architecture.






            share|improve this answer























              Your Answer








              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "489"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: false,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: null,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              noCode: true, onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });






              Jez is a new contributor. Be nice, and check out our Code of Conduct.










              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2freverseengineering.stackexchange.com%2fquestions%2f20712%2fwhats-this-assembly-doing%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              2 Answers
              2






              active

              oldest

              votes








              2 Answers
              2






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              7














              This looks like a 32-bit shift right compiler helper. In 16-bit era, 32-bit numbers were represented by a pair of registers, in this case ax:dx. The check for 16 is an optimization: if the shift is over 16, the low register value is lost completely, so it can be discarded and replaced by dx>>(shift-16), while the high register is filled with the sign bit as the result of the cwd instruction. Here's the (lightly) commented source code from the Borland C runtime library which seems to match yours:



              ;-----------------------------------------------------------------
              ;| H_LRSH.ASM -- long shift right |
              ;-----------------------------------------------------------------

              ;
              ; C/C++ Run Time Library - Version 5.0
              ;
              ; Copyright (c) 1987, 1992 by Borland International
              ; All Rights Reserved.
              ;

              INCLUDE RULES.ASI

              _TEXT segment public byte 'CODE'
              assume cs:_TEXT
              public LXRSH@
              public F_LXRSH@
              public N_LXRSH@

              N_LXRSH@:
              pop bx ;fix up for far return
              push cs
              push bx
              LXRSH@:
              F_LXRSH@:
              cmp cl,16
              jae lsh@small
              mov bx,dx ; save the high bits
              shr ax,cl ; now shift each half
              sar dx,cl
              ;
              ; We now have a hole in AX where the lower bits of
              ; DX should have been shifted. So we must take our
              ; copy of DX and do a reverse shift to get the proper
              ; bits to be or'ed into AX.
              ;
              neg cl
              add cl,16
              shl bx,cl
              or ax,bx
              retf
              lsh@small:
              sub cl,16 ; for shifts more than 15, do this
              ; short sequence.
              xchg ax,dx ;
              cwd ; We have now done a shift by 16.
              sar ax,cl ; Now shift the remainder.
              retf
              _TEXT ends
              end





              share|improve this answer




























                7














                This looks like a 32-bit shift right compiler helper. In 16-bit era, 32-bit numbers were represented by a pair of registers, in this case ax:dx. The check for 16 is an optimization: if the shift is over 16, the low register value is lost completely, so it can be discarded and replaced by dx>>(shift-16), while the high register is filled with the sign bit as the result of the cwd instruction. Here's the (lightly) commented source code from the Borland C runtime library which seems to match yours:



                ;-----------------------------------------------------------------
                ;| H_LRSH.ASM -- long shift right |
                ;-----------------------------------------------------------------

                ;
                ; C/C++ Run Time Library - Version 5.0
                ;
                ; Copyright (c) 1987, 1992 by Borland International
                ; All Rights Reserved.
                ;

                INCLUDE RULES.ASI

                _TEXT segment public byte 'CODE'
                assume cs:_TEXT
                public LXRSH@
                public F_LXRSH@
                public N_LXRSH@

                N_LXRSH@:
                pop bx ;fix up for far return
                push cs
                push bx
                LXRSH@:
                F_LXRSH@:
                cmp cl,16
                jae lsh@small
                mov bx,dx ; save the high bits
                shr ax,cl ; now shift each half
                sar dx,cl
                ;
                ; We now have a hole in AX where the lower bits of
                ; DX should have been shifted. So we must take our
                ; copy of DX and do a reverse shift to get the proper
                ; bits to be or'ed into AX.
                ;
                neg cl
                add cl,16
                shl bx,cl
                or ax,bx
                retf
                lsh@small:
                sub cl,16 ; for shifts more than 15, do this
                ; short sequence.
                xchg ax,dx ;
                cwd ; We have now done a shift by 16.
                sar ax,cl ; Now shift the remainder.
                retf
                _TEXT ends
                end





                share|improve this answer


























                  7












                  7








                  7







                  This looks like a 32-bit shift right compiler helper. In 16-bit era, 32-bit numbers were represented by a pair of registers, in this case ax:dx. The check for 16 is an optimization: if the shift is over 16, the low register value is lost completely, so it can be discarded and replaced by dx>>(shift-16), while the high register is filled with the sign bit as the result of the cwd instruction. Here's the (lightly) commented source code from the Borland C runtime library which seems to match yours:



                  ;-----------------------------------------------------------------
                  ;| H_LRSH.ASM -- long shift right |
                  ;-----------------------------------------------------------------

                  ;
                  ; C/C++ Run Time Library - Version 5.0
                  ;
                  ; Copyright (c) 1987, 1992 by Borland International
                  ; All Rights Reserved.
                  ;

                  INCLUDE RULES.ASI

                  _TEXT segment public byte 'CODE'
                  assume cs:_TEXT
                  public LXRSH@
                  public F_LXRSH@
                  public N_LXRSH@

                  N_LXRSH@:
                  pop bx ;fix up for far return
                  push cs
                  push bx
                  LXRSH@:
                  F_LXRSH@:
                  cmp cl,16
                  jae lsh@small
                  mov bx,dx ; save the high bits
                  shr ax,cl ; now shift each half
                  sar dx,cl
                  ;
                  ; We now have a hole in AX where the lower bits of
                  ; DX should have been shifted. So we must take our
                  ; copy of DX and do a reverse shift to get the proper
                  ; bits to be or'ed into AX.
                  ;
                  neg cl
                  add cl,16
                  shl bx,cl
                  or ax,bx
                  retf
                  lsh@small:
                  sub cl,16 ; for shifts more than 15, do this
                  ; short sequence.
                  xchg ax,dx ;
                  cwd ; We have now done a shift by 16.
                  sar ax,cl ; Now shift the remainder.
                  retf
                  _TEXT ends
                  end





                  share|improve this answer













                  This looks like a 32-bit shift right compiler helper. In 16-bit era, 32-bit numbers were represented by a pair of registers, in this case ax:dx. The check for 16 is an optimization: if the shift is over 16, the low register value is lost completely, so it can be discarded and replaced by dx>>(shift-16), while the high register is filled with the sign bit as the result of the cwd instruction. Here's the (lightly) commented source code from the Borland C runtime library which seems to match yours:



                  ;-----------------------------------------------------------------
                  ;| H_LRSH.ASM -- long shift right |
                  ;-----------------------------------------------------------------

                  ;
                  ; C/C++ Run Time Library - Version 5.0
                  ;
                  ; Copyright (c) 1987, 1992 by Borland International
                  ; All Rights Reserved.
                  ;

                  INCLUDE RULES.ASI

                  _TEXT segment public byte 'CODE'
                  assume cs:_TEXT
                  public LXRSH@
                  public F_LXRSH@
                  public N_LXRSH@

                  N_LXRSH@:
                  pop bx ;fix up for far return
                  push cs
                  push bx
                  LXRSH@:
                  F_LXRSH@:
                  cmp cl,16
                  jae lsh@small
                  mov bx,dx ; save the high bits
                  shr ax,cl ; now shift each half
                  sar dx,cl
                  ;
                  ; We now have a hole in AX where the lower bits of
                  ; DX should have been shifted. So we must take our
                  ; copy of DX and do a reverse shift to get the proper
                  ; bits to be or'ed into AX.
                  ;
                  neg cl
                  add cl,16
                  shl bx,cl
                  or ax,bx
                  retf
                  lsh@small:
                  sub cl,16 ; for shifts more than 15, do this
                  ; short sequence.
                  xchg ax,dx ;
                  cwd ; We have now done a shift by 16.
                  sar ax,cl ; Now shift the remainder.
                  retf
                  _TEXT ends
                  end






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered 6 hours ago









                  Igor SkochinskyIgor Skochinsky

                  24.4k44587




                  24.4k44587























                      4














                      It appears to be a 32 bit right shift with the 32 bit number provided in dx:ax, and cl being the number of bits to shift.



                      If you assume cl is over 16, a right shift by more than 16 bit only needs to care about the upper 16 bit, which are stored in dx, because the lower 16 bit are shifted out anyway.



                      So that's exactly what the 2nd block does. If cl larger than 16, move dx (upper 16 bit) into ax and convert it to a 32 bit number, subtract 16 from cl because this is implicitly done by ignoring the lower 16 bit, then shift the upper part (which is now dx:ax thanks to the cwd) by that number.



                      I didn't try to understand the top part, but my assumption is it does exactly the same for shift widths below 16 bits.



                      Basically, it's a 32 bit right shift done in 16 bit architecture.






                      share|improve this answer




























                        4














                        It appears to be a 32 bit right shift with the 32 bit number provided in dx:ax, and cl being the number of bits to shift.



                        If you assume cl is over 16, a right shift by more than 16 bit only needs to care about the upper 16 bit, which are stored in dx, because the lower 16 bit are shifted out anyway.



                        So that's exactly what the 2nd block does. If cl larger than 16, move dx (upper 16 bit) into ax and convert it to a 32 bit number, subtract 16 from cl because this is implicitly done by ignoring the lower 16 bit, then shift the upper part (which is now dx:ax thanks to the cwd) by that number.



                        I didn't try to understand the top part, but my assumption is it does exactly the same for shift widths below 16 bits.



                        Basically, it's a 32 bit right shift done in 16 bit architecture.






                        share|improve this answer


























                          4












                          4








                          4







                          It appears to be a 32 bit right shift with the 32 bit number provided in dx:ax, and cl being the number of bits to shift.



                          If you assume cl is over 16, a right shift by more than 16 bit only needs to care about the upper 16 bit, which are stored in dx, because the lower 16 bit are shifted out anyway.



                          So that's exactly what the 2nd block does. If cl larger than 16, move dx (upper 16 bit) into ax and convert it to a 32 bit number, subtract 16 from cl because this is implicitly done by ignoring the lower 16 bit, then shift the upper part (which is now dx:ax thanks to the cwd) by that number.



                          I didn't try to understand the top part, but my assumption is it does exactly the same for shift widths below 16 bits.



                          Basically, it's a 32 bit right shift done in 16 bit architecture.






                          share|improve this answer













                          It appears to be a 32 bit right shift with the 32 bit number provided in dx:ax, and cl being the number of bits to shift.



                          If you assume cl is over 16, a right shift by more than 16 bit only needs to care about the upper 16 bit, which are stored in dx, because the lower 16 bit are shifted out anyway.



                          So that's exactly what the 2nd block does. If cl larger than 16, move dx (upper 16 bit) into ax and convert it to a 32 bit number, subtract 16 from cl because this is implicitly done by ignoring the lower 16 bit, then shift the upper part (which is now dx:ax thanks to the cwd) by that number.



                          I didn't try to understand the top part, but my assumption is it does exactly the same for shift widths below 16 bits.



                          Basically, it's a 32 bit right shift done in 16 bit architecture.







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered 6 hours ago









                          Johann AydinbasJohann Aydinbas

                          57628




                          57628






















                              Jez is a new contributor. Be nice, and check out our Code of Conduct.










                              draft saved

                              draft discarded


















                              Jez is a new contributor. Be nice, and check out our Code of Conduct.













                              Jez is a new contributor. Be nice, and check out our Code of Conduct.












                              Jez is a new contributor. Be nice, and check out our Code of Conduct.
















                              Thanks for contributing an answer to Reverse Engineering Stack Exchange!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2freverseengineering.stackexchange.com%2fquestions%2f20712%2fwhats-this-assembly-doing%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              Loup dans la culture

                              How to solve the problem of ntp “Unable to contact time server” from KDE?

                              ASUS Zenbook UX433/UX333 — Configure Touchpad-embedded numpad on Linux