Given
A B C | X Y
---------+------
0 0 0 | 0 1
0 0 1 | 0 0
0 1 0 | 0 1
0 1 1 | 1 0
1 0 0 | 0 0
1 0 1 | 1 1
1 1 0 | 1 0
1 1 1 | 0 1
we see that
x = a'bc + ab'c + abc'
y = a'b'c' + a'bc' + ab'c + abc
= a'c' + ac
Also, using # to stand for NAND,
x = ((a#a)#b#c) # (a#(b#b)#c) # (a#b#(c#c))
y = ((a#a)#(c#c)) # (a # c)
Here are some x86 logic instructions to perform the following operations on the ebx register:
AND ebx, 0ffaefeafh
XOR ebx, 00fc0000h
AND ebx, 0000003fh
OR ebx, 003ffc00h
; ----------------------------------------------------------------------------
; charsbyprintf.asm
;
; NASM implementation of a program that displays characters 32 through 126
; to standard output, 16 characters per line.
; ----------------------------------------------------------------------------
global _main
extern _printf
section .text
_main:
mov edx, S1 ; edx will be next memory cell to fill
mov al, 32 ; al is next character to store
L1:
mov [edx], al ; store character in memory
inc al ; next character
inc edx ; next memory cell
cmp al, 127 ; are we done?
je L2 ; yes
test al, 15 ; should we write a newline next?
jnz L1 ; nah, just do next character
mov byte [edx], 10 ; store a newline
inc edx ; remember to "skip over" the newline
jmp L1 ; and go to next character
L2:
mov byte [edx], 0 ; store string terminator for printf
push dword S1
call _printf
add esp, 4
ret
; Store all the characters in memory. There will be 5 rows of 17 characters
; (16 + newline) and one row of 15 characters, for a total of 100 characters.
; Since we have a C library we require a 101st byte for a terminating 0.
section .bss
S1:
resb 101
; ----------------------------------------------------------------------------
; reversedarguments.asm
;
; NASM implementation of a program that displays its commandline arguements,
; one per line, in reverse order.
; ----------------------------------------------------------------------------
global _main
extern _printf
section .text
_main:
push esi ; save callee-save registers
push edi
mov esi, [esp+12] ; argc
L1:
dec esi
test esi, esi ; equal zero yet?
jz L2 ; if so, all done
mov edi, [esp+16] ; argv
push dword [edi+4*esi] ; argv[i]
push esi ; i
push dword S1
call _printf
add esp, 12
jmp L1
L2:
pop edi ; restore callee-save registers
pop esi
ret
S1: db 'argv[%d] = %s', 10, 0
; ----------------------------------------------------------------------------
; gcd.asm
;
; NASM implementation of
;
; unsigned gcd(unsigned x, unsigned y) {
; return (y == 0) ? x : gcd(y, x mod y);
; }
;
; Return value in eax, as per x86 convention.
; ----------------------------------------------------------------------------
global _gcd
section .text
_gcd:
cmp dword [esp+8], 0 ; y == 0?
jne L1 ; if not, go do work
mov eax, [esp+4] ; otherwise, just return x
ret
L1:
mov eax, [esp+4]
xor edx, edx ; edx:eax <- x
div dword [esp+8] ; edx <- remainder
push edx ; x % y
push dword [esp+12] ; y
call _gcd
add esp, 8
ret
; ---------------------------------------------------------------------------- ; callgcd.asm ; ; NASM implementation of a program that displays the GCD of its two ; command line arguments. The GCD function is external. It's not ; particularly efficient. ; ---------------------------------------------------------------------------- global _main extern _gcd extern _printf extern _atoi section .text _main: push esi ; callee save register cmp dword [esp+8], 3 ; argc == 3? je getx ; if so, get to it push dword S2 ; otherwise print error message call _printf add esp, 4 ret ; and bail getx: mov esi, [esp+12] ; esi <- argv push dword [esi+8] ; argv[2] call _atoi add esp, 4 push eax ; push for subsequent gcd call mov [y], eax ; save for later gety: mov esi, [esp+16] push dword [esi+4] ; argv[1] call _atoi add esp, 4 push eax ; argument to gcd mov [x], eax ; save for later callit: call _gcd add esp, 8 ; gcd has two parameters L1: push eax ; gcd(x, y) push dword [y] ; y push dword [x] ; x push dword S1 ; format string for success call _printf add esp, 16 pop esi ret S1: db 'GCD(%d,%d) = %d', 10, 0 S2: db 'Exactly two arguments required', 10, 0 section .bss x: resd 1 y: resd 1
/*
* callgcd.c
*
* Calls an external gcd program with the command line arguments.
*/
#include <stdio.h>
#include <stdlib.h>
extern unsigned gcd(unsigned x, unsigned y);
int main(int argc, char** argv) {
unsigned x;
unsigned y;
if (argc != 3) {
printf("Exactly two arguments required\n");
return 1;
}
x = atoi(argv[1]);
y = atoi(argv[2]);
printf("GCD of %d and %d is %d\n", x, y, gcd(x, y));
return 0;
}
Here is a solution using conditional moves and no conditional jumps. For fun, I used the technique of subtracting the minimum and the maximum from the sum. I haven't tested it.
; ----------------------------------------------------------------------------
; median3.asm
;
; Implements int median3(int threeIntegers[]); where threeIntegers is a
; pointer to three consecutive doublewords in memory.
; ----------------------------------------------------------------------------
global _median3
section .text
_median3:
mov eax, [esp+4] ; sum will go in eax
mov edx, eax ; min will go in edx
mov ecx, eax ; max will go in ecx
add eax, [x+4]
cmp edx, [x+4]
cmovl edx, [x+4]
cmp ecx, [x+4]
cmovg ecx, [x+4]
add eax, [x+8] ; now the sum is complete
cmp edx, [x+8]
cmovl edx, [x+8] ; now the min is complete
cmp ecx, [x+8]
cmovg ecx, [x+8] ; now the max is complete
sub eax, edx
sub eax, ecx ; now eax has the median
ret
Here is a solution that uses conditional jumps. For this one I imagined that (ebx,eax,ecx) was a three-word array and did an insertion sort. I haven't tested it.
mov ebx, [x] mov eax, [x+4] mov ecx, [x+8] cmp ebx, eax jl L1 xchg ebx, eax L1: cmp eax, ecx jl L2 xchg eax, ecx L2: cmp ebx, eax jl L3 xchg ebx, eax L3: ret
If you want to compute the log base 7 of x in the code, you can do this
; ----------------------------------------------------------------------------
; log7.asm
;
; NASM implementation of a function that returns the log base 7 of its sole
; argument.
;
; double log7(double x)
; ----------------------------------------------------------------------------
global _log7
section .text
_log7:
fld1 ; 1
fld qword [esp+4] ; 1 x
fyl2x ; log2(x)
fld1 ; log2(x) 1
fld qword [seven] ; log2(x) 1 7
fyl2x ; log2(x) log2(7)
fdivp st1 ; log2(x)/log2(7)
ret
seven:
dq 7.0
But you can also define the reciprocal of the log base 2 of 7 directly in the code to make the function much, much shorter. I'm not giving the answers here; that's for you to try.