CIS-261 Home http://www.c-jump.com/bcc/
Download sample program add_16_bytes.asm ( download ).
Current version of the program is summing an array of 16 bytes. The steps are:
Load starting address of the array into ESI.
Loop for each element in the array.
Get the value using the offset in ESI via indirect memory addressing.
Add the value to the running total in register AL.
Update the offset in ESI to point to the next element of the array.
Update loop counter.
If counter is not zero, repeat from step 4.
; CIS-261 ; add_16_bytes.asm ; .586P .MODEL FLAT ; Flat memory model option casemap:none ; Treat labels as case-sensitive .CONST ; Constant data segment .STACK 100h ; (default is 1-kilobyte stack) .DATA ; Begin initialized data segment values db 16 DUP( 5 ) ; 16 bytes of values "5" ; Code segment .CODE ; Begin code segment _main PROC ; Beginning of code mov eax, 0 ; clear result mov bl, 16 ; init loop counter lea esi, values ; init data pointer addup: add al, [esi] ; add byte to sum inc esi ; increment data pointer dec bl ; decrement loop counter jnz addup ; if BL not zero, continue mov [esi], al ; save sum ret ; Exit _main ENDP END _main ; Marks the end of the module and sets the program entry point label
Command
dumpbin /exports C:\Windows\System32\kernel32.dll
prints a list of windows API functions available to a console application.
The following C++ program demonstrates a loop of 500-millisecond Beeps with rising tone frequency.
One of the APIs is a Beep function, which generates simple tone using the sound card.
The Beep call doesn't wait for the sound card to complete the playback; the tone is generated asynchronously. To synchronize frequency display with the sound, the program pauses by calling Sleep, which waits for the duration of the tone in milliseconds.
The std::flush
output manipulator is making std::cout
display the output immediately.
Alltogether the combination of the above steps simulates a synchronous (sequential) output of the frequency and sound.
#include <iostream> #include <windows.h> int main() { int ms = 500; // sound duration in milliseconds // frequency (hertz) must be in range 37 through 32767 for ( int frequency = 500; frequency < 2000; frequency += 200 ) { // display sound frequency in hertz before each tone. std::cout << frequency << " " << std::flush; Beep( frequency, ms ); Sleep( ms ); } return 0; }
Most kernel32 API calls return result in EAX reqister.
If Beep function succeeds, the return value is nonzero.
If the function fails, the return value is zero. To get extended error information, application can call GetLastError API:
// C example: DWORD result = Beep( frequency, ms ); if ( result == 0 ) { DWORD error_code = GetLastError(); }
The next program, M09_prototype.asm ( download ) demonstrates Beep API call, made from an assembly program.
; CIS-261 Lab exercise M09 ; M09_prototype.asm ; Program that beeps ; .386 ; Tells MASM to use Intel 80386 instruction set. .MODEL FLAT ; Flat memory model option casemap:none ; Treat labels as case-sensitive EXTERN _Beep@8:NEAR ; takes 2 DWORD parameters EXTERN _Sleep@4:NEAR ; takes 1 DWORD parameter .CONST ; Constant data segment .DATA ; Begin initialised data segment .CODE ; Begin code segment _main PROC ; Main entry point into program ; __stdcall calling convention: args pushed R to L mov eax, 500 ; duration, milliseconds push eax mov eax, 1000 ; frequency, Hertz push eax call _Beep@8 ; Beep( frequency, duration ); mov eax, 500 ; sleep time in milliseconds push eax ; param on the stack call _Sleep@4 ret _main ENDP END _main ; Marks the end of the module and sets the program entry point label
The EXTERN MASM directive,
EXTERN _Beep@8:NEAR
defines a program symbol _Beep@8 with a NEAR type, which is needed by the assembler to generate the appropriate CALL instruction.
The linker gets the kernel32.lib object library on command line from the list of Additional Dependencies provided by the project settings.
The library provides the actual binary definition of the Beep system function.
Almost all Windows system functions use __stdcall calling convention . The system function removes its own arguments from the stack.
The __stdcall convention also requires a
function name prefixed by _underscore, and
appended function name suffix @, followed by the decimal number of bytes in the argument list. For example,
EXTERN _Beep@8:NEAR ; Function uses two DWORD arguments EXTERN _GetLastError@0:NEAR ; Function has no arguments .. call _Beep@8 call _GetLastError@0
Under __stdcall convention, function arguments are passed on the stack in right to left order. Download cjumpcxx.exe program, and click
Functions -> Stack Frames
to view animation of the function call.
Please note that the Beep call is not portable and is largely dependent on the OS that we are using.
The closest "beep" behavior that you can get in standard a C/C++ is to send the '\a' escape sequence to the standard output, that is, either
to the stdout stream,
printf( "\a" );
or to the std::cout object, for example,
std::cout << "\a";
The C++ standard inherits this from C standard:
"\a (alert) produces an audible or visible alert without changing the active cursor position."
On most common systems '\a' produces a short beep.
Modify the original add_16_bytes.asm program as follows:
Change the type of "values" array to a 32-bit doubleword.
While making changes,
Every CPU instruction in your program must have a brief comment.
Use .CONST memory segment to define necessary constants.
Use LENGTHOF and TYPE operators to refer to the number of elements in the array and size of each array element, respectively.
Replace LEA instructions by MOV instructions with OFFSET operators.
Add console I/O to prompt for the user input, and then have the user input a certain number of values.
Instead of calculating the sum, write assembly code to generate tones on the system speaker by calling Beep. Interpret array of integers as pairs of duration and frequency values.
Note : the Beep function modifies all general purpose registers EAX, EDX, ECX, and so on. If you rely on values in those registers to control your loops, memory addresses, offsets, etc., etc., please be sure to preserve your registers before the Beep call and restore the registers upon return from the call. One way to preserve the values is to push them on the stack, and restore them by popping in the reversed order. However, this needs to happen before duration and frequency parameters are pushed on the stack. Alternatively, you can have dedicated memory locations to temporarily preserve your registers.
Add logic to handle potential Beep error codes:
If the function fails, the return value in EAX register is zero and no additional action is required.
If the Beep function succeeds, the return value in EAX is nonzero. In that case, to get extended error information, call GetLastError API function.
The GetLastError returns the error code in EAX. Program should print this error code on the screen.
As the sound is produced, display the tone frequency and duration on the console screen. Delay the program after each beep by calling kernel32 Sleep function.
Ask the user if they wish to retry, and if so, start over. Exit the program otherwise.
Optional (15 xtra pts.) The original size of "values" array is 16 elements. However, the program could ask the user how many sample values they wish to enter.
What to submit:
Submit only your ASM source file (not the EXE or project.)