What's this assembly doing?
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
New contributor
add a comment |
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
New contributor
add a comment |
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
New contributor
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
disassembly x86 dos
New contributor
New contributor
edited 9 hours ago
perror
11.3k1767130
11.3k1767130
New contributor
asked 11 hours ago
JezJez
1384
1384
New contributor
New contributor
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
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
add a comment |
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.
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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
add a comment |
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
add a comment |
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
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
answered 8 hours ago
Igor Skochinsky♦Igor Skochinsky
24.4k44587
24.4k44587
add a comment |
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
answered 8 hours ago
Johann AydinbasJohann Aydinbas
57628
57628
add a comment |
add a comment |
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.
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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