Example code in section 12-12
-----------------------------
The example code in Section 12-12 ("Merging Bit Strings" ) is incorrect.
Currently the code is:
CODE: SELECT ALL
; Merge two 16-bit strings into a single 32-bit string.
; AX - Source for even numbered bits.
; BX - Source for odd numbered bits.
; CL - Scratch register.
; EDX- Destination register.
mov cl, 16
MergeLp: shrd edx, eax, 1 ; Shift a bit from EAX into EDX.
shrd edx, ebx, 1 ; Shift a bit from EBX into EDX.
dec cl
jne MergeLp;
It should be:
Code: Select all
CODE: SELECT ALL
; Merge two 16-bit strings into a single 32-bit string.
; AX - Source for even numbered bits.
; BX - Source for odd numbered bits.
; CL - Scratch register.
; EDX- Destination register.
mov cl, 16
MergeLp: shrd edx, eax, 1 ; Shift a bit from EAX into EDX.
shrd edx, ebx, 1 ; Shift a bit from EBX into EDX.
shr eax, 1
shr ebx, 1
dec cl
jne MergeLp;
The second block of instructions in this section suffers from the same problem:
Code: Select all
CODE: SELECT ALL
shrd edx, eax, 6
shrd edx, ebx, 5
shrd edx, eax, 6
shrd edx, ebx, 11
shrd edx, eax, 4
Code: Select all
CODE: SELECT ALL
shrd edx, eax, 6
shr eax, 6
shrd edx, ebx, 5
shr ebx, 5
shrd edx, eax, 6
shr eax, 6
shrd edx, ebx, 11
shrd edx, eax, 4
Randy Hyde
Sections 9.2.1 and 9.2.3 are redundant
--------------------------------------
I just discovered that sections 9.2.1 and 9.2.3 cover the exact same material. Interesting boo-boo. Sorry for confusing anyone if you're wonder what the difference was.
Cheers,
Randy Hyde
Errata: Pointers
----------------
On page 162:
A MASM pointer is a 64-bit value that may contain the address of another
variable. If you have a dword variable p that contains 1000_0000h, then p
“points” at memory location 1000_0000h. To access the dword that p points
at, you could use code like the following:
Code: Select all
mov rbx, p
mov rax, [rbx]
First, "p" is not a qword (64-bit),
Second, "mov rbx,p" is completely wrong because p is a dword and we are trying to put a dword into a qword register.
Re: Errata: Pointers
Report Quote
Unread post by randyhyde » Sun Feb 13, 2022 6:55 pm
Yes, p should have been a qword.
cheers,
Randy Hyde
Listing 5-15 QuickSort
Report Quote
Unread post by sevilla.larry » Sun Nov 14, 2021 12:12 am
Hi tried the quicksort and add more data.
Modification:
Code: Select all
numElements = 20
theArray dword 1,10,2,9,3,8,4,7,5,6
dword 99, 7, 2, 88, 5, 77, 66, 44, 3, 55
Data after sorting:
1
2
2
3
3
4
5
5
6
7
7
8
9
10
55
44
66
77
88
99
I'm not familiar with the algorithm, but (seems) failed...
Re: Listing 5-15 QuickSort
Report Quote
Unread post by randyhyde » Sun Feb 13, 2022 6:53 pm
There was a missing push and pop (needed to preserve R9 around the swap).
Cheers,
Randy Hyde
Working code:
CODE: SELECT ALL
Code: Select all
; Listing 5-15
;
; Recursive quicksort
option casemap:none
nl = 10
numElements = 20
.const
ttlStr byte "Listing 5-15", 0
fmtStr1 byte "Data before sorting: ", nl, 0
fmtStr2 byte "%d " ;Use nl and 0 from fmtStr3
fmtStr3 byte nl, 0
fmtStr4 byte "Data after sorting: ", nl, 0
.data
theArray dword 1,10,2,9,3,8,4,7,5,6
dword 99, 7, 2, 88, 5, 77, 66, 44, 3, 55
.code
externdef printf:proc
; Return program title to C++ program:
public getTitle
getTitle proc
lea rax, ttlStr
ret
getTitle endp
; quicksort-
;
; Sorts an array using the quicksort algorithm.
;
; Here's the algorithm in C, so you can follow along:
;
; void quicksort(int a[], int low, int high)
; {
; int i,j,Middle;
; if( low < high)
; {
; Middle = a[(low+high)/2];
; i = low;
; j = high;
; do
; {
; while(a[i] <= Middle) i++;
; while(a[j] > Middle) j--;
; if( i <= j)
; {
; swap(a[i],a[j]);
; i++;
; j--;
; }
; } while( i <= j );
;
; // recursively sort the two sub arrays
;
; if( low < j ) quicksort(a,low,j-1);
; if( i < high) quicksort(a,j+1,high);
; }
; }
;
; Args:
; RCX (_a): Pointer to array to sort
; RDX (_lowBnd): Index to low bound of array to sort
; R8 (_highBnd): Index to high bound of array to sort
_a equ [rbp+16] ;Ptr to array
_lowBnd equ [rbp+24] ;Low bounds of array
_highBnd equ [rbp+32] ;High bounds of array
; Local variables (register save area)
saveR9 equ [rbp+40] ;Shadow storage for R9
saveRDI equ [rbp-8]
saveRSI equ [rbp-16]
saveRBX equ [rbp-24]
saveRAX equ [rbp-32]
; Within the procedure body, these registers
; have the following meaning:
;
; RCX: Pointer to base address of array to sort
; EDX: Lower bound of array (32-bit index).
; r8d: Higher bound of array (32-bit index).
;
; edi: index (i) into array.
; esi: index (j) into array.
; r9d: Middle element to compare against
quicksort proc
push rbp
mov rbp, rsp
sub rsp, 32
; This code doesn't mess with RCX. No
; need to save it. When it does mess
; with RDX and R8, it saves those registers
; at that point.
; Preserve other registers we use:
mov saveRAX, rax
mov saveRBX, rbx
mov saveRSI, rsi
mov saveRDI, rdi
mov saveR9, r9
mov edi, edx ;i=low
mov esi, r8d ;j=high
; Compute a pivotal element by selecting the
; physical middle element of the array.
lea rax, [rdx+r8*1] ; RAX=low+high
shr rax, 1 ; (low+high)/2
mov r9d, [rcx][rax*4] ;Middle = ary[(i+j)/2]
; Repeat until the edi and esi indexes cross one
; another (edi works from the start towards the end
; of the array, esi works from the end towards the
; start of the array).
rptUntil: cmp edi, esi ;while( i <= j)
jnle sortPartitions
; Scan from the start of the array forward
; looking for the first element greater or equal
; to the middle element).
dec edi ;to counteract inc, below
while1: inc edi ;i = i + 1
cmp [rcx][rdi*4], r9d ;While ary[i] < middle
jl while1
; Scan from the end of the array backwards looking
; for the first element that is less than or equal
; to the middle element.
inc esi ;To counteract dec, below
while2: dec esi ;j = j - 1
cmp [rcx][rsi*4], r9d ;while ary[j] < Middle
jg while2
; If we've stopped before the two pointers have
; passed over one another, then we've got two
; elements that are out of order with respect
; to the middle element, so swap these two elements.
cmp edi, esi ;If i <= j
jnle sortPartitions
push r9
mov eax, [rcx][rdi*4] ;Swap ary[i] and ary[j]
mov r9d, [rcx][rsi*4]
mov [rcx][rsi*4], eax
mov [rcx][rdi*4], r9d
pop r9
inc edi ;i = i + 1
dec esi ;j = j - 1
endif1: cmp edi, esi ;Until i > j
jng rptUntil
; We have just placed all elements in the array in
; their correct positions with respect to the middle
; element of the array. So all elements at indexes
; greater than the middle element are also numerically
; greater than this element. Likewise, elements at
; indexes less than the middle (pivotal) element are
; now less than that element. Unfortunately, the
; two halves of the array on either side of the pivotal
; element are not yet sorted. Call quicksort recursively
; to sort these two halves if they have more than one
; element in them (if they have zero or one elements, then
; they are already sorted).
sortPartitions:
cmp edx, esi ;if lowBnd < j
jnl endif2
; Note: a is still in RCX,
; Low is still in RDX
; Need to preserve R8 (High)
; Note: quicksort doesn't require stack alignment
cmp edx, esi ;if( low < j )
jnl endif2
push rcx
push r8
mov r8d, esi
call quicksort ;( a, low, j )
pop r8
pop rcx
; Note: a is still in RCX,
; High is still in R8d
; Need to preserve RDX (low)
; Note: quicksort doesn't require stack alignment
;call printArray
endif2: cmp edi, r8d ;if( i < high )
jnl endif3
push rcx
push rdx
mov edx, edi
call quicksort ;( a, i, High )
pop rdx
pop rcx
; Restore registers and leave:
endif3:
mov rax, saveRAX
mov rbx, saveRBX
mov rsi, saveRSI
mov rdi, saveRDI
mov r9, saveR9
leave
ret
quicksort endp
; Little utility to print the array elements:
printArray proc
push r15
push rbp
mov rbp, rsp
sub rsp, 40 ;Shadow parameters
lea r9, theArray
mov r15d, 0
whileLT10: cmp r15d, numElements
jnl endwhile1
lea rcx, fmtStr2
lea r9, theArray
mov edx, [r9][r15*4]
call printf
inc r15d
jmp whileLT10
endwhile1: lea rcx, fmtStr3
call printf
leave
pop r15
ret
printArray endp
; Here is the "asmMain" function.
public asmMain
asmMain proc
push rbp
mov rbp, rsp
sub rsp, 32 ;Shadow storage
; Display unsorted array:
lea rcx, fmtStr1
call printf
call printArray
; Sort the array
lea rcx, theArray
xor rdx, rdx ;low = 0
mov r8d, numElements-1 ;high= 9
call quicksort ;(theArray, 0, 9)
; Display sorted results:
lea rcx, fmtStr4
call printf
call printArray
leave
ret ;Returns to caller
asmMain endp
end
Errata Table 2-9
Report Quote
Unread post by alfredmyers » Fri Oct 29, 2021 4:28 pm
I wasn't able to find a place to submit errata, so I hope it's OK here.
On page 71, Table 2-9, item "Carry" where read
Note that subtracting 1 from 0 will also clear the carry flag (that is, 0 – 1 is equivalent to 0 + (–1), and –1 is 0FFh in two’s complement form).
should read:
Note that subtracting 1 from 0 will also set the carry flag
Also of note, I found the setence a little bit confusing, because despite 0-1 and 0 + (-1) resulting in the same bit pattern, the first will set the carry flag, while the second will clear the carry flag.
Re: Errata Table 2-9
Report Quote
Unread post by alfredmyers » Mon Nov 01, 2021 4:55 am
On page 937, item 8
where answer c reads
65,636
should read:
65,536
Re: Errata Table 2-9
Report Quote
Unread post by alfredmyers » Mon Nov 01, 2021 4:10 pm
On page 78, second paragraph, where read:
If the shift count is 1, these two instructions copy the bit shifted out of
the destination operand into the carry flag,
should read:
If the shift count is non-zero, these two instructions copy the last bit shifted out of
the destination operand into the carry flag,
Re: Errata Table 2-9
Report Quote
Unread post by alfredmyers » Fri Nov 05, 2021 3:04 am
On page 112, Figure 3-2, where read:
Offset 0FFFh
in page xxxx + 1
should read:
"Offset 0
in page xxxx + 1"
Re: Errata Table 2-9
Report Quote
Unread post by alfredmyers » Fri Nov 05, 2021 3:15 pm
On page 122, item 3.7.1, where read:
mov ch, cl ; Copies the value from CL into DH
The destination register in comment doesn't match the destination register in the code.
Re: Errata Table 2-9
Report Quote
Unread post by alfredmyers » Sat Nov 06, 2021 4:07 am
On page 125, the operation described in Figure 3-9
mov al, [rbx + 1100h]
is inverted in relation to the text preceding it:
mov [rbx + 1100h], al
Re: Errata Table 2-9
Report Quote
Unread post by alfredmyers » Sat Nov 06, 2021 4:42 am
On page 128, 2nd paragraph where read:
To turn off the large address–aware flag, you need to add an extra command
line option to the ml64 command.
should read:
To turn off the large address–aware flag, you need to add an extra command
line option to the cl command.
Re: Errata Table 2-9
Report Quote
Unread post by randyhyde » Tue Nov 16, 2021 3:04 pm
This is as good a place as any to post erata.
Soon, I will start collecting these notes and adding them to the Ao64A website.
Thanks for the updates.
Cheers,
Randy Hyde
Re: Errata Table 2-9
Report Quote
Unread post by alfredmyers » Wed Nov 24, 2021 3:10 am
On page 123, second to last paragraph where read:
For example, if the next
instruction’s opcode is sitting in memory at location 8000h (the end of the
current instruction), then MASM will encode the value 88h as a 32-bit signed
constant for j in the instruction opcode.
Will only be true if the address for j is 8088h (RIP + 88h).
But this can be a little bit confusing given that the address for j in the preceeding text and diagram was RIP + 8088h.
Errata: Unions
Report Quote
Unread post by iuavvz » Fri Jan 07, 2022 3:19 am
On page 208:
...With a declaration like this, you can manipulate an uns32 object by accessing ...
What is a uns32?! We never mentioned that before.
Re: Errata: Unions
Report Quote
Unread post by randyhyde » Sun Feb 13, 2022 6:58 am
Sorry, that was a lack from translation from the original 32-bit edition (HLA has an uns32 type, which is just dword in MASM).
Cheers,
Randy Hyde
Errata: Redundant jz test
Report Quote
Post by stack2170 » Wed Jan 12, 2022 1:33 pm
In section 14.1.3, page 832, there's the following listing:
CODE: SELECT ALL
Code: Select all
mov rcx, Length ; Compute (Length mod 8)
and rcx, 111b ; Execute movsb only if # of bytes/8 <> 0
jz divisibleBy8 ; Copy the remaining 1 to 7 bytes
rep movsb
divisibleBy8:
Re: Errata: Redundant jz test
Report Quote
Post by randyhyde » Sun Feb 13, 2022 6:57 am
Noted.
Cheers,
Randy Hyde
Errata: Arithmetic Idioms
Report Quote
Unread post by iuavvz » Mon Jan 17, 2022 6:54 pm
Page 311:
CODE: SELECT ALL
Code: Select all
lea eax, [eax][eax * 2] ; EAX = ECX * 3
lea eax, [eax * 4] ; EAX = ECX * 4
CODE: SELECT ALL
Code: Select all
lea eax, [eax][eax * 2] ; EAX = EAX * 3
lea eax, [eax * 4] ; EAX = EAX * 4
Report Quote
Unread post by randyhyde » Sun Feb 13, 2022 6:54 am
Noted, will update in the next printing.
Cheers,
Randy Hyde
Errata: SSE Floating-Point Comparisons
Report Quote
Unread post by iuavvz » Tue Feb 01, 2022 9:38 pm
Page 372:
cmpne qss
should be:
cmpneqss
Re: Errata: SSE Floating-Point Comparisons
Report Quote
Unread post by randyhyde » Sun Feb 13, 2022 6:49 am
Noted.
Cheers,
Randy Hyde
Errata: FPU Data Types
Report Quote
Unread post by iuavvz » Mon Jan 31, 2022 11:48 pm
Page 324:
First figure: 32-bit single-precision floating-point format has 7 bits for the exponent instead of 8.
Top
randyhyde
Site Admin
Posts: 68
Joined: Wed Jan 13, 2021 11:01 am
Re: Errata: FPU Data Types
Report Quote
Unread post by randyhyde » Sun Feb 13, 2022 6:48 am
Yes indeed.
I will note that for the next printing.
Cheers,
Randy Hyde
Errata: Mantissa
Report Quote
Unread post by iuavvz » Sat Jan 22, 2022 12:08 am
Page 313:
For example, in the number 3.456e+12, the mantissa consists of 3.456, and the exponent digits are 12.
Isn't mantissa 0.456, and not 3.456?
From American Heritage Dictionary:
man·tis·sa (măn-tĭs'ə)
n.
The decimal part of a logarithm. In the logarithm 2.95424, the mantissa is 0.95424.
Top
randyhyde
Site Admin
Posts: 68
Joined: Wed Jan 13, 2021 11:01 am
Re: Errata: Mantissa
Report Quote
Unread post by randyhyde » Sun Feb 13, 2022 6:43 am
The American Heritage Dictionary is describing the original (English/mathematic) definition. In binary machine code, the mantissa and exponent fields are defined by their bit position in the floating-point format. In that context, the book is correct.
Cheers,
Randy Hyde
Errata: Answers to Questions in Chapter 6
Report Quote
Unread post by iuavvz » Tue Feb 01, 2022 10:40 pm
Page 945:
Answer to this question:
x = -((x*y)/z)
is:
Code: Select all
mov eax, x
imul y ; Note: Sign-extends into EDX
idiv z
mov x, eax
CODE: SELECT ALL
Code: Select all
neg eax
Top
randyhyde
Site Admin
Posts: 68
Joined: Wed Jan 13, 2021 11:01 am
Re: Errata: Answers to Questions in Chapter 6
Report Quote
Unread post by randyhyde » Sun Feb 13, 2022 6:41 am
Obviously, should be before the "mov x, eax" instruction.