home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Library / Assembly Programming Journal / apj_3.txt < prev    next >
Encoding:
Text File  |  2000-05-25  |  80.9 KB  |  2,272 lines

  1. ::/ \::::::.
  2. :/___\:::::::.
  3. /|    \::::::::.
  4. :|   _/\:::::::::.
  5. :| _|\  \::::::::::.                                               Feb/March 98
  6. :::\_____\::::::::::.                                              Issue      3
  7. ::::::::::::::::::::::.........................................................
  8.  
  9.             A S S E M B L Y   P R O G R A M M I N G   J O U R N A L
  10.                       http://asmjournal.freeservers.com
  11.                            asmjournal@mailcity.com
  12.  
  13.  
  14.  
  15.  
  16. T A B L E   O F   C O N T E N T S
  17. ----------------------------------------------------------------------
  18. Introduction...................................................mammon_
  19.  
  20. "An Introduction to SPARC assembly"............................+Spath.
  21.  
  22. "Extending NASM"...............................................mammon_
  23.  
  24. Column: Win32 Assembly Programming
  25.     "NASM specific Win32 coding".......................Tamas Kaproncai
  26.     "More about Text".........................................Iczelion
  27.     "Keyboard Input"..........................................Iczelion
  28.  
  29. Column: The C standard library in Assembly
  30.     "C string functions: introduction, _strlen".................Xbios2
  31.     "C string functions: _strcpy"...............................Xbios2
  32.  
  33. Column: The Unix World
  34.     "X-Windows in Assembly Language: Part II"..................mammon_
  35.  
  36. Column: Virtual Machines
  37.     "An Intro to the Java Virtual Machine"............Cynical Pinnacle
  38.  
  39. Column: Assembly Language Snippets
  40.     "NumFactors"..........................................Troy Benoist
  41.  
  42. Column: Issue Solution
  43.     "6-byte Solution"..........................................mammon_
  44. ----------------------------------------------------------------------
  45.      ++++++++++++++++++++++++Issue  Challenge+++++++++++++++++++++
  46.      Write a routine for converting ASCII hex to binary in 6 bytes
  47. ----------------------------------------------------------------------
  48.  
  49.  
  50. ____________________________________________________________________________                                                                               
  51.     ___ .___     __) (__    _____  ______                                   ```   
  52.   ._____|   \____\  ___/__._)   /._) _  (_.                                  \\  
  53.   |     |   _\   |_ \     |   \/ |        |CE                                 ,
  54. .=|_____|___)\___|(_______|______|        |===============[ Introduction ]===.
  55. '================================|        :=================================='
  56.                                  :        .                          by mammon_
  57.  
  58.                                                                     
  59. The first thing that you will notice about this issue --well, that it is late--
  60. will probably be the section headers designed by iCE. I had to add a top/upper
  61. left border to them [the horizontal and slanted lines] in order to make them 
  62. standout when scrolling though a 100K file such as this one, but other than 
  63. they are all his: comments, etc welcome.
  64.  
  65. I don't have much to say about this issue: I went overboard with the NASM stuff 
  66. this month as I have been doing a lot of 'research' work in that area recently; 
  67. my articles have been supplemented with Tamas Kaproncai's Win32 NASM pointers. 
  68.  
  69. Iczelion and XBios2 have both produced --as usual-- 2 quality articles this 
  70. month, Iczelion's based on his win32 asm tutorial 'the MASM way', and XBios2 
  71. once again continuing to replace C with assembler.
  72.  
  73. +Spath. has produced an excellent article on SPARC assembly language; I was 
  74. hoping to debut the 'other CPU' scene with a MIPS article I had planned but it 
  75. looks like +Spath has beat me to it. 
  76.  
  77. On a similar note, I mentioned on the Message Board wanting to start a Virtual
  78. Machines column. Cynical Pinnacle has started the column off this month with an 
  79. article on programming the Java VM in its native 'assembly language'; in 
  80. subsequent issues I and perhaps others will be adding articles here as well.
  81.  
  82. A final note, I have not come up with a challenge for the next issue; anyone 
  83. with good ideas is welcome to post one to the Message Board or to the APJ 
  84. email address.
  85.  
  86. Enjoy the mag!
  87.  
  88. _m
  89.  
  90.  
  91. ::/ \::::::.
  92. :/___\:::::::.
  93. /|    \::::::::.
  94. :|   _/\:::::::::.
  95. :| _|\  \::::::::::.
  96. :::\_____\:::::::::::...........................................FEATURE.ARTICLE
  97.                                               An introduction to SPARC assembly
  98.                                               by +Spath.
  99.  
  100.  
  101. The goal of this article is to introduce SPARC v8 architecture and SPARC 
  102. assembly ; I hope it can also constitute a good introduction to RISC 
  103. philosophy.  
  104.  
  105.  
  106. What is SPARC ?
  107. -----------------
  108. The principles of RISC (Reduced Instructions Set Computer) are born in the 
  109. early 80's in two universities (Berkeley and Stanford) ; its philosophy is 
  110. the quest for simplicity and CPU speed. SPARC (Scalable Processor ARChitecture)
  111. is a 32 bits RISC architecture created by Sun in 1987. It's an open 
  112. architecture, so that any manufaturer can make SPARC processors (like Philips, 
  113. VLSI, T.I., Fujitsu... already did). Its key features are :
  114.  
  115. - a load/store architecture : this means that only registers can be used
  116.   in data manipulation operations, and not memory locations. Memory is 
  117.   organised in a linear address space of 2^32 bits which use "big-endian" 
  118.   organisation (the MSB is stored first) ; a word is 32 bits wide (a 16 bits 
  119.   data is a halfword).
  120.  
  121. - a large number of registers : from 2 to 32 sets of 24 general purpose 
  122.   registers are available ; these 24 registers are local registers %l[0-7], 
  123.   in registers %i[0-7] and out registers %o[0-7], all working in an 
  124.   overlapping windows mechanism that will be explained later. The SPARC 
  125.   architecture also provides 8 global registers %g[0-7], 32 registers for 
  126.   floating-point operations (%f[0-31]) and some specific registers (%pc, %sp, 
  127.   %psr, %y,...).
  128.  
  129. - a small set of simple instructions : to avoid translation from machine code
  130.   to microcode, SPARC instructions are directly implemented in hardware, and  
  131.   therefore are very basic (mainly load/store, logical, arithmetic, branching).
  132.   All instructions are 4 bytes long, and most of them use 3 registers (source1,
  133.   source2, destination in that order). Assemblers also provide a set of 
  134.   synthetic instructions, which are more "coder friendly", but does not really 
  135.   exist for the processor (and therefore must be carefully used). These 
  136.   synthetic instructions have most of the time less operands, so that the 
  137.   corresponding real instructions often use %g0, a read-only register stuck 
  138.   at 0 ; here are some aliases :
  139.  
  140.   synthetic instruction     |     real opcode      
  141.   nop                      <=>    sethi  0, %g0          
  142.   ret                      <=>    jmpl   %i7+8, %g0
  143.   mov  reg_or_imm, reg     <=>    or     %g0, reg_or_imm, reg 
  144.   cmp  reg, reg_or_imm     <=>    subcc  reg, reg_or_imm, %g0 
  145.  
  146. Enough with theory, let's see some code.
  147.  
  148.  
  149. SPARC assembly basics
  150. -----------------------
  151. Let's start with an in-season "hello world" style program : '!' is used
  152. for single line comments, /* .. */ is used for multiple lines comments). 
  153.  
  154. !8<------------------------------------------------------------------------
  155. /*   FILE : hello.s                                                      */
  156.  
  157. .section        ".rodata"             ! read-only initialised datas 
  158. .MyText:                              ! define our string label
  159.         .asciz  "Happy new year %i \n"! define a null-terminated string
  160. .Year:
  161.         .word   1999                  ! define a word constant
  162.  
  163. .section        ".text"               ! read-only object code (instructions)
  164.         .global main                  ! Make function name globally visible
  165.    
  166. main:
  167.         save   %sp, -112, %sp         ! allocate space for stack    
  168.         sethi  %hi(.MyText), %o1      ! load higher part of string offset
  169.         or     %o1, %lo(.MyText), %o0 ! add lower part of offset    
  170.         set    (.Year), %l1           ! get year address            
  171.         ld     [%l1], %o1             ! load year into %o1          
  172.         call   printf                 ! print the string
  173.         nop                           ! do nothing (BDS)                   
  174.           
  175.         ret                           ! Return to caller
  176.         restore                       ! Restore register windows (BDS)   
  177. Endmain:                              ! Tell the linker how big the
  178.         .size    main,(.-main)        ! procedure is ("." is current address).
  179. !8<-------------------------------------------------------------------------
  180.  
  181. Every procedure must save some memory space for itself ; this stack space 
  182. will be used to store the out and local registers and all the datas needed by 
  183. the procedure (the minimal space is 64 bytes for %o and %l registers). The 
  184. stack grows from higher to lower addresses, so that allocating a stack space 
  185. is implemented by substracting a value from the current stack pointer ; the
  186. previous stack pointer is called the frame pointer (%fp).
  187.  
  188. Registers %o0 - %o5 are used to pass the first six parameters to a procedure, 
  189. because the current stack pointer (%sp) is stored in %o6 and the calling 
  190. program counter (%pc, used to calculate the return address) is stored in %o7. 
  191. If a procedure has more than six parameters, the remaining parameters are 
  192. passed using the stack space (eg for a caller's stack space of 92 bytes, the 
  193. child procedure can get the seventh parameter at [%fp+92]). 
  194.  
  195. As I said before, all instructions are 32 bits long, so that you must use 
  196. two steps (with sethi and or) to load a 32 bits data. Note that %hi refers 
  197. to the most significant 22 bits and %lo refers to the least significant 10 
  198. bits of a register.
  199.  
  200. Like most RISC machines, a SPARC processor uses a branch delay slot (BDS) to 
  201. optimize pipeline efficiency : this means that by default, the instruction 
  202. following a branching is executed regardless of whether or not the branch is 
  203. taken. So the coder must move (when possible) an instruction from before the 
  204. branch to after the branch. Another possibility is to use the 'nop' instruction
  205. or to add the ',a' suffix to the branch instruction, which annul the next 
  206. operation. 
  207.  
  208.  
  209. Calling and branching
  210. -----------------------
  211. Let's take another example to better illustrate the calling process : this
  212. is a recursive implementation of the Fibonacci numbers, which are defined as :
  213.  
  214. fib(N) = fib(N-1) + fib(N-2)
  215. fib(0) = fib(1) = 1 
  216.  
  217. !8<--------------------------------------------------------------------------
  218. /*  FILE: fib.s                                                            */
  219.  
  220. .section        ".rodata"           ! read-only initialised datas (constants)
  221.         .align 8                    ! datas must be double-words aligned 
  222. .MyText:                            ! define our string label
  223.         .asciz  "Fib(%i) = %i \n"   ! define a null-terminated string
  224.  
  225. ! ------- FIB : handles F(0) and F(1) --------
  226. .section        ".text"             ! read-only object code (instructions)
  227.         .align 4                    ! code must be word-aligned (4 bytes)
  228.         .global fib                 ! Make function name globally visible
  229. fib:
  230.         save  %sp, -112, %sp        ! save stack space
  231.         mov   %i0, %o0              ! 1st parameter may be needed for calling
  232.         cmp   %o0, 1                ! asked for F(0) of F(1) ? 
  233.         ble   F1orF0                ! yes : take the branch
  234.         mov   1, %i0                ! return value = 1 (BDS)
  235.         
  236.         call  fibcall               ! 
  237.         nop                         ! do nothing (BDS)
  238.         mov   %o0, %i0              ! return value = fibcall return value
  239. F1orF0:
  240.         ret                         ! Return to caller
  241.         restore                     ! Restore register windows (BDS)
  242. Endfib:
  243.         .size    fib,(.-fib)
  244.  
  245. ! ----- FIBCALL : calls F(N-1) and F(N-2) -----
  246.         .global fibcall             ! Make function name globally visible
  247. fibcall:
  248.         save  %sp,-112,%sp          ! save stack space
  249.         mov   %i0,%l0               ! save N in %l0
  250.         call  fib                   ! call F(N-1) 
  251.         sub   %l0,1,%o0             ! compute N-1 (BDS)
  252.         
  253.         mov   %o0,%i0               ! save result in %i0
  254.         call  fib                   ! call F(N-2)
  255.         sub   %l0,2,%o0             ! compute N-2 (BDS)
  256.         
  257.         ret                         ! Return to caller
  258.         restore %i0,%o0,%o0         ! return F(N-1) + F(N-2) (BDS)
  259. Endfibcall:
  260.         .size    fibcall,(.-fibcall)
  261.  
  262. !-------- MAIN --------------------------------
  263.         .global main                ! Make function name globally visible
  264. main:               
  265.         save   %sp,-112,%sp         ! save stack space
  266.         call   fibcall              ! calculate fib number 7
  267.         mov    7,%o0                ! (BDS)
  268.         
  269.         mov    %o0,%o2              ! result is second parameter
  270.         sethi  %hi(.MyText),%o0     ! load higher part of string offset
  271.         or     %o0,%lo(.MyText),%o0 ! add lower part of offset
  272.         call   printf         
  273.         mov    7,%o1                ! number is the first parameter (BDS)
  274.         
  275.         ret                         ! Return to caller
  276.         restore                     ! Restore register windows (BDS)
  277. Endmain:
  278.         .size    main,(.-main)
  279. !8<--------------------------------------------------------------------------
  280.  
  281. All procedures share the global registers (%g[0-7]), the remaining registers
  282. %l[0-7], %i[0-7], %o[0-7] constitute the register window. When a procedure 
  283. starts execution, it allocates 16 registers (input and local), the output 
  284. registers are overlapped with the subroutine's input registers. Here's what 
  285. happens if procedure A calls procedure B which calls procedure C :
  286.  
  287. proc A     in  |  local  |   out  | 
  288.                          |        |
  289. proc B                   |   in   |  local  |  out  |
  290.                                             |       |
  291. proc C                                      |  in   |   local   |   out
  292.  
  293.  
  294. As you see, for each procedure, the parameters passed to and received from a
  295. subroutine are stored in %o registers. The same way, the parameters taken from 
  296. and passed to the calling procedure are stored in %i registers. The current 
  297. window pointer (CWP) identifies the current register window : it is stored in 
  298. the least significant 5 bits of %psr, and is modified by the 'save' and 
  299. 'restore' commands.
  300.  
  301. The condition code register (another part of %psr) contains four flags : Z 
  302. (zero), N (negative), C (carry), and V (overflow) ; contrary to x86 assembly, 
  303. these bits are not updated by standard arithmetic operations, but by special 
  304. instructions (with 'cc' suffix, like 'cmp' which is in fact a 'subcc').
  305. For instance, you have these equivalences :
  306.  
  307.     SPARC                       x86          
  308. subcc  r1, r2, r1    <=>    sub  r1, r2   ; keep result and flags
  309. subcc  r1, r2, %g0   <=>    cmp  r1, r2   ; discard result, keep flags
  310. sub    r1, 0, r2     <=>    mov  r2, r1   ; keep result, discard flags
  311.  
  312.  
  313. As last example, here's a simple anti-cracking method : a checksum on
  314. our own code :
  315.  
  316. !8<-----------------------------------------------------------------------
  317. /*  FILE: cksum.s                                                       */ 
  318.  
  319. .section    ".data"             ! read-only initialised datas (constants)
  320.     .align 8                    ! datas must be double-words aligned
  321. .CRCError:     
  322.     .asciz  "Wrong CRC !! \n"   !
  323.             
  324. .section    ".text"             ! read-only object code (instructions)
  325.         .align 4                    ! code must be word-aligned (4 bytes)
  326. cksum:  
  327.         save   %sp,-64,%sp          ! save minimal stack space
  328.         mov    %i0, %l0             ! %l0 is the base address
  329.         sub    %i1, %i0, %l1        ! %l1 is the decreasing index
  330.         mov    %g0, %l2             ! %l2 is the running sum    
  331. loop:
  332.     ld     [%l0+%l1], %o0       ! fetch the next element
  333.         add    %l2, %o0, %l2        ! add it to the running sum
  334.         subcc  %l1, 4, %l1          ! one fewer element
  335.     
  336.         bge,a  loop                 ! if %o0 >= 0 get next element
  337.                                     ! (delay slot result is annulled)
  338.         mov    %l2, %o0             ! store the result in sum (BDS)
  339.  
  340.         ret                        ! Return to caller
  341.         restore                     ! Restore register windows (BDS) 
  342. endcksum:                           ! Tell the linker how big the
  343.         .size  cksum,(.-cksum)      ! procedure is.
  344.  
  345. !-------------------- MAIN -------------------------
  346.         .global main
  347. main:
  348.         save   %sp,-64,%sp               ! allocate space for stack
  349.         set    main, %o0                 ! start address for cksum
  350.         sethi  %hi(EndOfCRCZone),%o1     ! high part of end address
  351.         call   cksum                     ! calculate cksum
  352.         or     %o1,%lo(EndOfCRCZone),%o1 ! low part of end address (BDS)
  353.     
  354. EndOfCRCZone:
  355.     set    0x10954, %o1           ! load precalculated checksum     
  356.     cmp    %o0, %o1               ! is checksum correct ?
  357.         be     End                    ! yes : exit 
  358.     nop                           ! do nothing (BDS)
  359.     
  360. Error:                                ! no : display message
  361.     sethi  %hi(.CRCError ),%o0    ! load higher part of string offset
  362.         call   printf                 ! print the string
  363.         or     %o0,%lo(.CRCError),%o0 ! add lower part of string offset (BDS)
  364.  
  365. End:
  366.         ret                           ! Return to caller
  367.         restore                       ! Restore register windows (BDS)
  368.     
  369. EndMain:                              ! Tell the linker how big the
  370.         .size    main,(.-main)          ! procedure is.
  371. !8<-----------------------------------------------------------------------
  372.  
  373.  
  374. Tools and references
  375. ----------------------
  376. Here are the tools I use when I play with SPARC assembly ; some are SunOS 
  377. specific tools, some are multi-platforms ones. The code you read here has 
  378. been tested on various Sun workstations (using SPARC and UltraSPARC 
  379. processors). With very little modifications, it also worked on ISEM, a SPARC 
  380. emulator for Linux (see below).
  381.  
  382. - assembling : I use gcc for that job, which itself uses as and ld (assembler 
  383.   and linker) to create ELF executables. CC and cc also work well ; these 3 
  384.   compilers can also be used to generate ASM source code from C source code 
  385.   with the "-S" option, which is IMHO a great method to learn assembly on 
  386.   a new platform.
  387.  
  388. - debugging : I use adb, which is very basic but also very powerful, but gdb 
  389.   and dbx may also work.
  390.  
  391. - reversing : all the previous tools are useful ; I also use a disassembler
  392.   (SunOS dis), but some exist for other platforms (see Bruce Ediger's 
  393.   homepage).
  394.  
  395.  
  396. If you plan to give a try to SPARC assembly, here are some links : 
  397.  
  398. http://www.cs.unm.edu/~maccabe/classes/341/labman/labman.html
  399. ISEM (Instructional Sparc EMulator) homepage.
  400.  
  401. http://www.csn.net/~bediger/
  402. Bruce Ediger Homepage
  403.  
  404. http://www.cs.earlham.edu/~mutioke/cs63/
  405. a good introduction to SPARC with plenty of links.
  406.  
  407. http://www.sics.se/~psm/sparcstack.html
  408. a very good overview of SPARC stack and registers.
  409.  
  410.  
  411. Final Words
  412. ------------
  413. If you use a SPARC based machine, give a try to assembly, it's quite fun. 
  414. If not, remember that the best you know your processor, the best you 
  415. can code ASM.
  416.  
  417.  
  418. ::/ \::::::.
  419. :/___\:::::::.
  420. /|    \::::::::.
  421. :|   _/\:::::::::.
  422. :| _|\  \::::::::::.
  423. :::\_____\:::::::::::...........................................FEATURE.ARTICLE
  424.                                                                  Extending NASM
  425.                                                                  by mammon_
  426.  
  427.  
  428. Programmers transitioning to NASM from a commercial assembler such as MASM or 
  429. TASM immediately notice the lack of any high-level language structures -- the 
  430. assembly syntax accepted by NASM is only slightly more sophisticated than what 
  431. you would find in a debugger. While this has its good side --smaller code size, 
  432. nothing hidden from the programmer-- it does make coding a bit more tedious.
  433.  
  434. For this reason NASM comes with a preprocessor that is both simple and powerful;
  435. by writing NASM macros, the high-level functionality of other assemblers can be 
  436. emulated rather easily. As thw following macros will demonstrate, most of the 
  437. high-level asm features in commercial assemblers really do not do anything very
  438. elaborate; they simply are more convenient for the programmer.
  439.  
  440. The macros that I will detail below provide some basic C and ASM constructs for
  441. use in NASM. I have made the complete file available at
  442.   http://www.eccentrica.org/Mammon/macros.asm
  443. The macro file can be included in a .asm file with the NASM directive
  444.   %INCLUDE "macros.asm"
  445. Comments on the usage of each macro are included in the file.
  446.  
  447. Macro Basics
  448. ------------
  449. The fundamenal structure of a NASM macro is
  450. %macro {macroname} {# parameters}
  451. %endmacro
  452. The actual code resides on the line between the %macro and %endmacro tags; this 
  453. code will be inserted into your program wherever NASM finds {macroname}. Thus 
  454. you could create a macro to push the contents of each register such as:
  455. %macro SAVE_REGS 0
  456.     push eax
  457.     push ebx
  458.     push ecx
  459.     push edx
  460. %endmacro
  461. Once you have defined this macro, you can use it in your code like:
  462.     SAVE_REGS
  463.     call ReadFile
  464. ...which the preprocessor will expand to
  465.     push eax
  466.     push ebx
  467.     push ecx
  468.     push edx
  469.     call ReadFile
  470. before assembling. It should be noted that all preprocessing takes place in a 
  471. single stage immediately  before compiling starts; to preview what the pre-
  472. processor will send to the assembler, you can invoke nasm with the -e option.
  473.  
  474. The %macro tag requires that you declare the number of paramters that will be 
  475. passed to the macro. This can be a single number or a range, with a few quirks:
  476.     %macro LilMac 0             ; takes 0 arguments
  477.     %macro LilMac 5             ; takes 5 arguments
  478.     %macro LilMac 0-3           ; takes 0-3 arguments
  479.     %macro LilMac 1-*           ; takes 1 to unlimited arguments
  480.     %macro LilMac 1-2+          ; takes 1-2 arguments
  481.     %macro LilMac 1-3 0, "OK"   ; takes 1-3 arguments, 2-3 default to 0 & "OK"
  482. The last three examples bear some explanation. The "-*" operator in the %macro 
  483. tag specifies that the macro can handle any number of parameters; in other 
  484. words, there is no maximum number, and the minimum is whatever number is to the 
  485. left of the "-*" operator. The "+" operator means that any additional arguments 
  486. will be appended to the last argument instead of causing an error, so that:
  487.     LilMac 0, OK, This argument is one too many
  488. will result in argument 1 being 0 and argument 2 being "OK, This argument is 
  489. one too many." Note that this is a good way to pass commas as part of an argu-
  490. ment (normally they are only separators). Providing defualt arguments after the 
  491. number of arguments allows a macro to be called with fewer arguments than it 
  492. expects.
  493.     %macro SAVE_VARS 1-4 ecx, ebx, eax
  494. will fill a missing 4th argument with eax, 3rd with ebx, and 2nd with ecx. Note 
  495. that you have to provide defaults starting with the last argument and working 
  496. backwards.
  497.  
  498. The parameters to the macro are available as %1 for the first argument, %2 for 
  499. the second, and so on, with %0 containing a count of all the arguments. There 
  500. is an equivalent to the DOS "SHIFT" command called %rotate which will rotate 
  501. the parameters to either the left or to the right depending on whether a 
  502. positive or negative value was supplied:
  503.    Before: %1 %2 %3 %4      Before: %1 %2 %3 %4     Before: %1 %2 %3 %4 
  504.    %rotate 1                %rotate -1              %rotate 2
  505.    After:  %4 %1 %2 %3      After:  %2 %3 %4 %1     After:  %3 %4 %1 %2
  506. So that rotating by 1 will put the value at %1 into %4, and rotating by -1 will
  507. put the value of %1 into %2.
  508.  
  509.  
  510. High-Level Calls
  511. ----------------
  512. Perhaps the buggest complaint about NASM is its primitive call syntax. In MASM 
  513. and TASM, the parameters to a call may be appended to the call itself:
  514.     call MessageBox, hOwner, lpszText, lpszTitle, fuStyle
  515. where in NASM the parameters must be pushed onto the stack prior to the call:
  516.     push fuStyle
  517.     push lpszTitle
  518.     push lpszText
  519.     push hOwner
  520.     call MessageBox
  521. Using NASM's "-*" macro feature along with the %rep directive make a high-level 
  522. call easy to replicate:
  523.  %macro call 2-*
  524.  %define _func %1
  525.  %rep &0-1
  526.    %rotate 1
  527.    push %1
  528.  %endrep
  529.    call _func
  530.  %endmacro
  531. The %define directive simply defines the variable _func [underscores should 
  532. prefix variable names in macros so you do not mistakenly use the same name 
  533. later in the program] as %1, the name of the function to call. The %rep and 
  534. %endrep directives enclose the instructions to be repeated, and %rep takes as a 
  535. parameter the number of repetitions [in this case set to the number of macro 
  536. parameters minus 1]. Thus, the above macro cycles through the arguments to call 
  537. and pushes them last-argument first [C syntax] before making the call.
  538.  
  539. Overloading an existing instruction such as call will cause warnings at compile 
  540. time [remember, the preprocessor thinks you are doing a recursive macro invoke] 
  541. so usually you will want to name the macro "c_call" or something similar. The 
  542. following macros provide facilities for C, Pascal, fastcall, and stdcall call
  543. syntaxes.
  544. ;==============================================================-High-Level Call
  545. ;   ccall    FuncName, param1, param2, param 3... ;Pascal: 1st-1st, no clean
  546. ;   pcall    FuncName, param1, param2, param 3... ;C: Last-1st, stack cleanup
  547. ;   stdcall  FuncName, param1, param2, param 3... ;StdCall: last-1st, no clean
  548. ;   fastcall FuncName, param1, param2, param 3... ;FastCall: registers/stack
  549. %macro pcall 2-*               
  550. %define _j %1
  551. %rep %0-1
  552.     %rotate -1
  553.     push %1
  554. %endrep
  555.     call _j
  556. %endmacro
  557.  
  558. %macro ccall 2-*                        
  559. %define _j %1
  560. %assign __params %0-1
  561. %rep %0-1
  562.     %rotate -1
  563.     push %1
  564. %endrep
  565.     call _j
  566.     %assign __params __params * 4
  567.     add esp, __params
  568. %endmacro
  569.  
  570. %macro stdcall 2-*          
  571. %define _j %1
  572. %rep %0-1
  573.     %rotate -1
  574.     push %1
  575. %endrep
  576.     call _j
  577. %endmacro
  578.  
  579. %macro fastcall 2-*                
  580. %define _j %1
  581. %assign __pnum 1
  582. %rep %0-4
  583.     %rotate -1
  584.     %if __pnum = 1
  585.      mov eax, %1
  586.     %elif __pnum = 2
  587.      mov edx, %1
  588.     %elif __pnum = 3
  589.      mov ebx, %1
  590.     %else
  591.      push %1
  592.     %endif
  593.     %assign __pnum __pnum+1
  594. %endrep
  595.     call _j
  596. %endmacro
  597. ;==========================================================================-END
  598.  
  599.  
  600. Switch-Case Blocks
  601. ------------------
  602. One of the most awkward C constructs to code in assembly is the SWITCH-CASE 
  603. block. It is also rather difficult to re-create as a macro due to variable 
  604. number and length of CASE statements.
  605.  
  606. NASM's preprocessor has a context stack which allows you to create a set of 
  607. local variables and addresses which is specific to a particular invocation of a
  608. macro. Thus it becomes possible to refer to labels which will be created in a 
  609. future macro by giving them context-dependent names:
  610.  %macro MacPart1 0
  611.   %push mac             ;create a context called "mac"
  612.     jmp %$loc           ;jump to context-specific label "loc"
  613.  %endmacro
  614.  
  615.  %macro MacPart2 0
  616.   %ifctx mac            ;if we are in context 'mac'
  617. %$loc:                  ;define label 'loc'
  618.     xor eax, eax        ;code at this label...
  619.     ret
  620.   %endif                ;end the if block
  621.   %pop                  ;destroy the 'mac' context
  622.  %endmacro
  623. As you can see, the context is created and named with a %push directive, and 
  624. destroyed with a $pop directive. NASM has a number of preprocessor conditional 
  625. IF/ELSE statements; in the above example, the %ifctx [if current context equals]
  626. directive is used to determine if a 'mac' context has been created [Note that 
  627. the 'base' NASM conditionals include %if, %elif, %else, and %endif; these carry
  628. over to the %ifctx directive, such that there is available %ifctx, %ifnctx, 
  629. %elifctx, %elifnctx, %else, and %endif; all %if directives must be closed with 
  630. an %endif directive]. Finally, %$ is used to prefix the name of a context-
  631. specific variable or label. Non-context-specific local labels use the %% prefix:
  632. %macro LOOP_XOR
  633. %%loop:
  634.     pop eax
  635.     xor eax, ebx
  636.     test eax, eax
  637.     jnz %%loop
  638. %endmacro
  639.  
  640. The SWITCH-CASE macro that follows uses the syntax:
  641.    SWITCH Variable
  642.    CASE Int
  643.         BREAK
  644.    CASE Int
  645.         BREAK
  646.    DEFAULT
  647.    ENDSWITCH 
  648. Which could be implemented as follows:
  649. card    db  0   ;card_variable
  650. Jack    EQU 11
  651. Queen   EQU 12
  652. King    EQU 13
  653. ...   
  654.     SWITCH card
  655.     CASE Jack
  656.         add edx, Jack
  657.         BREAK
  658.     CASE Queen
  659.         add edx, Queen
  660.         BREAK
  661.     CASE King
  662.         add edx, King
  663.         BREAK
  664.     DEFAULT
  665.         add d, [card]
  666.     ENDSWITCH
  667. Note that SWITCH moves the variable into eax and CASE moves the value into ebx.
  668. ;===========================================================-SWITCH-CASE Blocks
  669. %macro SWITCH 1
  670. %push switch            
  671. %assign __curr 1
  672.     mov eax, %1
  673.     jmp %$loc(__curr)
  674. %endmacro
  675.  
  676. %macro CASE 1
  677. %ifctx switch
  678.     %$loc(__curr):
  679.     %assign __curr __curr+1
  680.     mov ebx, %1
  681.     cmp eax, ebx
  682.     jne %$loc(__curr)
  683. %endif
  684. %endmacro
  685.  
  686. %macro DEFAULT 0
  687. %ifctx switch
  688.     %$loc(__curr):
  689. %endif
  690. %endmacro
  691.  
  692. %macro BREAK 0
  693.     jmp %$endswitch
  694. %endmacro
  695.  
  696. %macro ENDSWITCH 0
  697.     %ifctx switch
  698.     %$endswitch:
  699.     %pop
  700.     %endif
  701. %endmacro
  702. ;==========================================================================-END
  703.  
  704.  
  705. If-Then Blocks
  706. --------------
  707. While the preprocessor provides support for if-then directives, it is a slight 
  708. bit of work to cause that to generate the equivalent assembly language 'if' 
  709. code [ the preprocessor 'if' is resolved before compile time, not at run time].
  710. Using macros, you can create if-then blocks with the following structure:
  711.    IF Value, Cond, Value
  712.         ;if code here
  713.    ELSIF Value, Cond, Value
  714.         ;else-if code here
  715.    ELSE
  716.         ;else code here
  717.    ENDIF
  718. An example being:
  719.     IF [Passwd], e, [GoodVal]       ;e == equals or je
  720.         jmp Registered
  721.     ELSE
  722.         jmp FormatHardDrive
  723.     ENDIF
  724. The trickiest part about this macro sequence is the 'Cond' parameter. NASM 
  725. allows condition codes [the 'cc' in 'jcc' that you findin opcode refs] to be 
  726. passed to macros; these condition codes are simply the 'jcc' with the 'j' cut 
  727. off --  'jnz' becomes 'nz', 'jne' becomes 'ne', 'je' becomes 'e', and so on. 
  728. The reason for this is that the condition code is appended to a 'j' later in 
  729. the macro:
  730.  %macro Jumper %1 %2 %3    ;JUMPER Reg1, cc, Reg2
  731.     cmp %1, %3
  732.     j%+2 Gotcha
  733.     jmp error
  734.  %endmacro
  735. The above code appends %2 to the 'j' with the directive j%+2. Note that if you 
  736. use j%- instead of j%+, NASM will insert the *inverse* condition code, so that
  737. jz becomes jnz, etc. For example, calling the macro
  738.  %macro Jumper2 %1
  739.     j%-1 JmpHandler
  740.  %endmacro
  741. with the invocation 'Jumper2 nz' would assemble the code 'jz JmpHandler'.
  742.  
  743. The condition codes can be a bit tricky to work with; it is advisable to add a 
  744. sequence such as the following to the macro file:
  745. %define EQUAL       e
  746. %define NOTEQUAL    ne
  747. %define G-THAN      g
  748. %define L-THAN      l
  749. %define G-THAN-EQ   ge
  750. %define L-THAN-EQ   le
  751. %define ZERO        z
  752. %DEFINE NOTZERO     nz
  753. so that you could call the IF macro as follows:
  754.     IF PassWd, EQUAL, GoodVal
  755.         ;if code here
  756. ...etc etc. Note also that the IF-THEN-ELSE macros put the passed values into 
  757. eax and ebx for compatison, so these registers will need to be preserved.
  758.  
  759. ;===========================================================-IF-THEN-ELSE Loops
  760. %macro IF 3
  761.  %push if
  762.  %assign __curr 1
  763.     mov eax, %1
  764.     mov ebx, %3
  765.     cmp eax, ebx
  766.     j%+2 %%if_code
  767.     jmp %$loc(__curr)
  768. %%if_code:
  769. %endmacro
  770.  
  771. %macro ELSIF 3
  772.   %ifctx if
  773.     jmp %$end_if
  774. %$loc(__curr):
  775.   %assign __curr __curr+1
  776.     mov eax, %1
  777.     mov ebx, %3
  778.     cmp eax, ebx
  779.     j%+2 %%elsif_code
  780.     jmp %$loc(__curr)
  781. %%elsif_code:
  782.  %else
  783.    %error "'ELSIF' can only be used following 'IF'"
  784.  %endif
  785. %endmacro
  786.  
  787. %macro ELSE 0
  788.  %ifctx if
  789.     jmp %$end_if
  790. %$loc(__curr):
  791. %assign __curr __curr+1
  792.  %else
  793.   %error "'ELSE' can only be used following an 'IF'"
  794.  %endif
  795. %endmacro
  796.  
  797. %macro ENDIF 0
  798. %$loc(__curr):
  799. %$end_if:
  800. %pop
  801. %endmacro
  802. ;==========================================================================-END
  803.  
  804. For/While Loops
  805. ---------------
  806. The DO...FOR and DO...WHILE do nothing differnet from the previous macros, but 
  807. are simply a different application of the same principles. The syntax for 
  808. calling these macros is:
  809.    DO
  810.     ;code to do here
  811.    FOR min, Cond, max, step
  812.  
  813.    DO
  814.     ;code to do here
  815.    WHILE variable, Cond, value
  816. It is perhaps easiest to illustrate this by comparing the macros with C code.
  817.     for( x = 0; x <= 100; x++) { SomeFunc() }
  818. Equates to:
  819.   DO
  820.     call SomeFunc
  821.   FOR 0, l, 100, 1
  822. Likewise, 
  823.     for( x = 0; x != 100; x--) { SomeFunc() }
  824. Equates to:
  825.   DO
  826.     call SomeFunc
  827.   FOR 0, e, 100, -1
  828. The WHILE macro is similar:
  829.     while( CurrByte != BadAddr) {SomeFunc() }
  830. Equates to:
  831.   DO
  832.     call SomeFunc
  833.   WHILE CurrByte, ne, BadAddr
  834. Once again, eax and ebx are used in the FOR and WHILE macros.
  835.  
  836. ;====================================================-DO-FOR and DO-WHILE Loops
  837. %macro DO 0
  838.  %push do
  839.     jmp %$init_loop
  840. %$start_loop:
  841.     push eax
  842. %endmacro
  843.  
  844. %macro FOR 4
  845.  %ifctx do
  846.     pop eax
  847.     add eax, %4
  848.     cmp eax, %3
  849.     j%-2 %%end_loop
  850.     jmp %$start_loop
  851. %$init_loop:
  852.     mov eax, %1
  853.     jmp %$start_loop
  854. %%end_loop:
  855.  %pop
  856.  %endif
  857. %endmacro
  858.  
  859. %macro WHILE 3
  860.  %ifctx do
  861.     pop eax
  862.     mov ebx, %3
  863.     cmp eax, ebx
  864.     j%+2 %%end_loop
  865.     jmp %$start_loop
  866. %$init_loop:
  867.     mov eax, %1
  868.     jmp %$start_loop
  869. %%end_loop:
  870.  %pop
  871.  %endif
  872. %endmacro
  873. ;==========================================================================-END
  874.  
  875.  
  876. Data Declarations
  877. -----------------
  878. Declaring data is relatively simple in assembly, but sometimes it helps to make 
  879. code more clear if you create macros that assign meaningful data types to 
  880. variables, even if those macros simply resolve to a DB or a DD. The following 
  881. macros demonstrate this concept. They are invoked as follows:
  882.  CHAR   Name, String            ;e.g. CHAR  UserName, "Joe User"
  883.  INT    Name, Byte              ;e.g. INT   Timeout,  30
  884.  WORD   Name, Word              ;e.g. WORD Logins
  885.  DWORD  Name, Dword             ;e.g. DWORD Password
  886. Note that when invoked with a name but not a value, these macros create empty 
  887. [DB 0] variables.
  888. ;============================================================-Data Declarations
  889. %macro CHAR 1-2 0
  890. %1: DB   %2,0
  891. %endmacro
  892.  
  893. %macro INT 1-2 0
  894. %1: DB   %2
  895. %endmacro
  896.  
  897. %macro WORD 1-2 0
  898. %1: DW   %2
  899. %endmacro
  900.  
  901. %macro DWORD 1-2 0
  902. %1: DD   %2
  903. %endmacro
  904. ;==========================================================================-END
  905.  
  906. Procedure Declarations
  907. ----------------------
  908. Procedure declarations are another matter of convenience. It is often useful in 
  909. your code to clearly delineate the start and end of a procedure; each of the 
  910. PROC macros below does that, as well as creating a stack fram for the procedure.
  911. The ENTRYPROC macro creates a procedure named 'main' and declares main as a 
  912. global symbol; the standard PROC declares the provided name as global. These 
  913. macros can be used as follows: 
  914. PROC ProcName Parameter1, Parameter2, Parameter3
  915.    ;procedure code here
  916. ENDP
  917.  
  918. ENTRYPROC
  919.     ;entry-procedure code here
  920. ENDP
  921. Note that the Parameters to PROC are set up to EQU to offsets from ebp, e.g. 
  922. ebp-4, ebp-8, etc. I have also included support for local variables, which 
  923. will EQU to positive offsets from ebp' these may be used as follows:
  924. PROC ProcName Parameter1, Parameter2, Parameter3...
  925.     LOCALDD Dword_Variable
  926.     LOCALDW Word_Variable 
  927.     LOCALDB Byte_Variable 
  928.         ;procedure code here
  929. ENDP 
  930.  
  931. ;=======================================================-Procedure Declarations
  932. %macro PROC 1-9
  933. GLOBAL %1
  934. %1:
  935.  %assign _i 4
  936.  %rep %0-1
  937.     %2 equ [ebp-_i]
  938.  %assign _i _i+4
  939.  %rotate 1
  940.  %endrep
  941.     push ebp
  942.     mov ebp, esp
  943.  %push local
  944.  %assign __ll 0
  945. %endmacro
  946.  
  947. %macro ENDP 0
  948.  %ifctx local
  949.   %pop
  950.  %endif
  951.     pop ebp
  952. %endmacro
  953.  
  954. %macro ENTRYPROC 0
  955. PROC main
  956. %endmacro
  957.  
  958. %macro LOCALVAR 1
  959.     sub esp, 4
  960.     %1 equ [ebp + __ll]
  961. %endmacro
  962.  
  963. %macro LOCALDB 1
  964.   %assign __ll __ll+1
  965.   LOCALVAR %1
  966. %endmacro
  967.  
  968. %macro LOCALDW 1
  969.   %assign __ll __ll+2
  970.   LOCALVAR %1
  971. %endmacro
  972.  
  973. %macro LOCALDD 1
  974.   %assign __ll __ll+4
  975.   LOCALVAR %1
  976. %endmacro
  977. ;==========================================================================-END
  978.  
  979. Further Extension
  980. -----------------
  981. Continued experimentation will of course prove fruitful. It is recommended that 
  982. you read/print out chapter 4 of the NASM manual for reference. In addition, it 
  983. is very helpful to test your macros by cpmpiling the source with "nasm -e", 
  984. which will output the preprocessed source code to stdout and will not compile
  985. the program.
  986.  
  987.  
  988. ____________________________________________________________________________
  989.                   ______               _____.  ____                         ```
  990.   ._____/\______.________._________. ._\___ |__\_ /.                         \\
  991.   |             |        |   _     | |   (_ |  __/ |CE                        ,
  992. .=|_____/\______|        |----)____| |______|______|======[   Win 32 ASM ]===.
  993. '===============|        :==================================================='
  994.                                                      NASM specific Win32 coding
  995.                                                      by Tamas Kaproncai
  996.  
  997.  
  998. Contents
  999. ========
  1000. 0. Preface
  1001. 1. Compiling
  1002. 2. Include files
  1003. 3. Library files
  1004. 4. Importing API functions
  1005. 5. Calling API functions
  1006. 6. WinMain
  1007. 7. Window procedure
  1008. 8. Sections
  1009. 9. Self modification
  1010.  
  1011.  
  1012. 0. Preface
  1013. ==========
  1014. I will introduce the win32 coding and I will focus on the NASM specific part.
  1015.  
  1016. Downloadable working examples:
  1017. ftp://ftp.szif.hu/pub/demos/tool/w32nasm.zip
  1018. http://rs1.szif.hu/~tomcat/win32
  1019.  
  1020. There is another tutorial on this topic, called:
  1021. "The Win32 NASM Coding Toolkit v0.02 by Gij"
  1022. that uses the LCC linker and the resource compiler which comes with LCC.
  1023.  
  1024.  
  1025. 1. Compiling
  1026. ============
  1027. I'm working with the following free programs in connection with NASM:
  1028. - linker: ALINK v1.5 by Anthony A.J. Williams.
  1029. - resource compiler: GoRC v0.50b by Jeremy Gordon.
  1030.  
  1031. The process of compiling a win32 program involves a number of steps which can 
  1032. be divided into three main processes: preparing the include files, preparing 
  1033. the library files, and writing the actual program.
  1034.  
  1035. The compiling flow chart
  1036. ------------------------
  1037. .h -> ? -> .inc
  1038.               \
  1039.        .asm -> NASM -> .obj
  1040.                           \
  1041.     .rc -> GORC -> .res -> ALINK -> .exe
  1042.                           /
  1043.     .dll -> IMPLIB -> .lib                            (? means handwork)
  1044.  
  1045.  
  1046. 2. Include files
  1047. ================
  1048. The include files (*.inc) must be generated from existing header files (*.h) 
  1049. that come with win32-compatible C or Pascal compilers. Files needed:
  1050.     WIN32N.INC (Thanks for the inital MASM version to S.L.Hutchesson).
  1051. The compiler will be NASM version 0.97
  1052.     http://www.cryogen.com/nasm
  1053. Usage: nasmw -fobj -w+orphan-labels -pwin32n.inc %1.asm
  1054.  
  1055.  
  1056. 3. Library files
  1057. ================
  1058. Files Needed:
  1059. WIN32.LIB
  1060. The linker will be ALINK
  1061.   http://www.geocities.com/SiliconValley/Network/4311/#alink    
  1062. Usage: alink -oPE %1 win32.lib %1.res %2 %3
  1063.  
  1064. More lib files can be created with IMPLIB.
  1065. Example: IMPLIB DDRAW.DLL
  1066.  
  1067.  
  1068. 4. Importing API functions
  1069. ==========================
  1070. EXTERN MessageBoxA
  1071. IMPORT MessageBoxA use32.dll
  1072.  
  1073.  
  1074. 5. Calling API functions
  1075. ========================
  1076. PUSH UINT MB_OK
  1077. PUSH LPCTSTR title1
  1078. PUSH LPCTSTR string1
  1079. PUSH HWND NULL
  1080. CALL [MessageBoxA]
  1081.  
  1082.  
  1083. 6. WinMain
  1084. ==========
  1085. You don't need to use the name, WinMain:
  1086. You must start the program with the label, ..start:
  1087.  
  1088. At the begening there is nothing special in the stack, so you should call
  1089. GetModuleHandleA for hInstance and GetCommandLineA for the command line.
  1090. (Command line consists the full path, the file name and the parameters).
  1091.  
  1092. You can exit the program with: RETN
  1093. or you should call the ExitProcess function:
  1094. PUSH UINT 0 ; the error code
  1095. CALL [ExitProcess]
  1096.  
  1097.  
  1098. 7. Window procedure
  1099. ===================
  1100. There are four parameters on the top of the stack:
  1101. PUSH EBP
  1102. MOV EBP,ESP
  1103. %DEFINE hwnd    EBP+8  ;handle of window
  1104. %DEFINE message EBP+12 ;message
  1105. %DEFINE wParam  EBP+16 ;first message parameter
  1106. %DEFINE lParam  EBP+20 ;second message parameter
  1107.  
  1108. You can handle the messages depends on WPARAM [wParam]
  1109. and the rest you can pass to DefWindowProcA:
  1110. PUSH LPARAM [lParam]
  1111. PUSH WPARAM [wParam]
  1112. PUSH UINT [message]
  1113. PUSH HWND [hwnd]
  1114. CALL [DefWindowProcA]
  1115. POP EBP
  1116. RETN 16
  1117.  
  1118.  
  1119. 8. Sections
  1120. ===========
  1121. You need a code section:
  1122. SECTION CODE USE32 CLASS=CODE
  1123. and a data section:
  1124. SECTION DATA USE32 CLASS=DATA
  1125.  
  1126. You don't need bss section, instead of you should append
  1127. every RESB, RESW, RESD, RESQ to the end of the source code.
  1128. This zero data not will be included to the exe file.
  1129.  
  1130.  
  1131. 9. Self modification
  1132. ====================
  1133. You can include your code and data together in one section:
  1134. SECTION CODE USE32 CLASS=CODE
  1135.  
  1136. In that case you need another object file, with only one line source:
  1137. SECTION CODE USE32 CLASS=DATA
  1138.  
  1139. ALINK will combine the properties of these two sections.
  1140.  
  1141. EXTERN MessageBoxA
  1142. EXTERN ExitProcess
  1143.  
  1144. SECTION CODE USE32 CLASS=CODE
  1145. ..start:
  1146.  
  1147. PUSH UINT MB_OK
  1148. PUSH LPCTSTR title1
  1149. PUSH LPCTSTR string1
  1150. PUSH HWND NULL
  1151. CALL MessageBoxA
  1152.  
  1153. PUSH UINT NULL
  1154. CALL ExitProcess
  1155.  
  1156. SECTION DATA USE32 CLASS=DATA
  1157. string1: db 'Hello world!',13,10,0
  1158. title1: db 'Hello',0
  1159.  
  1160.  
  1161.  
  1162. ____________________________________________________________________________
  1163.                   ______               _____.  ____                         ```
  1164.   ._____/\______.________._________. ._\___ |__\_ /.                         \\
  1165.   |             |        |   _     | |   (_ |  __/ |CE                        ,
  1166. .=|_____/\______|        |----)____| |______|______|======[   Win 32 ASM ]===.
  1167. '===============|        :==================================================='
  1168.                                                                 More about Text
  1169.                                                                 by Iczelion
  1170.  
  1171.  
  1172. We will experiment more with text attributes, ie. font and color.
  1173.  
  1174. Preliminary:
  1175. ------------
  1176.  
  1177. Windows color system is based on RGB values, R=red, G=Green, B=Blue. If you
  1178. want to specify a color in Windows, you must state your desired color in
  1179. terms of these three major colors. Each color value has a range from 0 to
  1180. 255 (a byte value). For example, if you want pure red color, you should use
  1181. 255,0,0. Or if you want pure white color, you must use 255,255,255. You can
  1182. see from the examples that getting the color you need is very difficult
  1183. with this system since you have to have a good grasp of how to mix and
  1184. match colors.
  1185.  
  1186. For text color and background, you use SetTextColor and SetBkColor, both of
  1187. them require a handle to device context and a 32-bit RGB value. The 32-bit
  1188. RGB value's structure is defined as:
  1189.  
  1190. RGB_value struct
  1191.     unused   db 0
  1192.     blue       db ?
  1193.     green     db ?
  1194.     red        db ?
  1195. RGB_value ends
  1196.  
  1197. Note that the first byte is not used and should be zero. The order of the
  1198. remaining three bytes is reversed,ie. blue, green, red. However, we will
  1199. not use this structure since it's cumbersome to initialize and use. We will
  1200. create a macro instead. The macro will receive three parameters: red, green
  1201. and blue values. It'll produce the desired 32-bit RGB value and store it in
  1202. eax. The macro is as follows:
  1203.  
  1204. RGB macro red,green,blue
  1205.     xor    eax,eax
  1206.     mov  ah,blue
  1207.     shl     eax,8
  1208.     mov  ah,green
  1209.     mov  al,red
  1210. endm
  1211.  
  1212. You can put this macro in the include file for future use.
  1213.  
  1214. You can "create" a font by calling CreateFont or CreateFontIndirect. The
  1215. difference between the two functions is that CreateFontIndirect receives
  1216. only one parameter: a pointer to a logical font structure, LOGFONT.
  1217. CreateFontIndirect is the more flexible of the two especially if your
  1218. programs need to change fonts frequently. However, in our example, we will
  1219. "create" only one font for demonstration, we can get away with CreateFont.
  1220. After the call to CreateFont, it will return a handle to a font which you
  1221. must select into the device context. After that, every text API function
  1222. will use the font we have selected into the device context.
  1223.  
  1224.  
  1225. Content:
  1226. --------
  1227.  
  1228. Below is our source code:
  1229. ;======================================================================TEXT.ASM
  1230. include windows.inc
  1231. includelib user32.lib
  1232. includelib kernel32.lib
  1233. includelib gdi32.lib
  1234.  
  1235. RGB macro red,green,blue
  1236.         xor eax,eax
  1237.         mov ah,blue
  1238.         shl eax,8
  1239.         mov ah,green
  1240.         mov al,red
  1241. endm
  1242.  
  1243. .data
  1244. ClassName   db "SimpleWinClass",0
  1245. AppName     db "Our First Window",0
  1246. TestString  db "Win32 assembly is great and easy!",0
  1247. FontName    db "script",0
  1248.  
  1249. .data?
  1250. hInstance HINSTANCE ?
  1251. CommandLine LPSTR ?
  1252.  
  1253. .code
  1254.  start:
  1255.     invoke GetModuleHandle, NULL
  1256.     mov    hInstance,eax
  1257.     invoke GetCommandLine
  1258.     invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
  1259.     invoke ExitProcess,eax
  1260.  
  1261. WinMain proc
  1262. hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:SDWORD
  1263.     LOCAL wc:WNDCLASSEX
  1264.     LOCAL msg:MSG
  1265.     LOCAL hwnd:HWND
  1266.     mov   wc.cbSize,SIZEOF WNDCLASSEX
  1267.     mov   wc.style, CS_HREDRAW or CS_VREDRAW
  1268.     mov   wc.lpfnWndProc, OFFSET WndProc
  1269.     mov   wc.cbClsExtra,NULL
  1270.     mov   wc.cbWndExtra,NULL
  1271.     push  hInstance
  1272.     pop   wc.hInstance
  1273.     mov   wc.hbrBackground,COLOR_WINDOW+1
  1274.     mov   wc.lpszMenuName,NULL
  1275.     mov   wc.lpszClassName,OFFSET ClassName
  1276.     invoke LoadIcon,NULL,IDI_APPLICATION
  1277.     mov   wc.hIcon,eax
  1278.     mov   wc.hIconSm,0
  1279.     invoke LoadCursor,NULL,IDC_ARROW
  1280.     mov   wc.hCursor,eax
  1281.     invoke RegisterClassEx, addr wc
  1282.     invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
  1283.            WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
  1284.            CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
  1285.            hInst,NULL
  1286.     mov   hwnd,eax
  1287.     invoke ShowWindow, hwnd,SW_SHOWNORMAL
  1288.     invoke UpdateWindow, hwnd
  1289.         .WHILE TRUE
  1290.                 invoke GetMessage, ADDR msg,NULL,0,0
  1291.                 .BREAK .IF (!eax)
  1292.                 invoke TranslateMessage, ADDR msg
  1293.                 invoke DispatchMessage, ADDR msg
  1294.         .ENDW
  1295.         mov     eax,msg.wParam
  1296.         ret
  1297. WinMain endp
  1298.  
  1299. WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
  1300.     LOCAL hdc:HDC
  1301.     LOCAL ps:PAINTSTRUCT
  1302.     LOCAL hfont:HFONT
  1303.  
  1304.     mov   eax,uMsg
  1305.     .IF eax==WM_DESTROY
  1306.         invoke PostQuitMessage,NULL
  1307.     .ELSEIF eax==WM_PAINT
  1308.         invoke BeginPaint,hWnd, ADDR ps
  1309.         mov    hdc,eax
  1310.         invoke CreateFont,24,16,0,0,400,0,0,0,OEM_CHARSET,\
  1311.  
  1312. OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
  1313.                                        DEFAULT_QUALITY,DEFAULT_PITCH or
  1314. FF_SCRIPT,\
  1315.                                        ADDR FontName
  1316.         invoke SelectObject, hdc, eax
  1317.         mov    hfont,eax
  1318.         RGB    200,200,50
  1319.         invoke SetTextColor,hdc,eax
  1320.         RGB    0,0,255
  1321.         invoke SetBkColor,hdc,eax
  1322.         invoke TextOut,hdc,0,0,ADDR TestString,SIZEOF TestString
  1323.         invoke SelectObject,hdc, hfont
  1324.         invoke EndPaint,hWnd, ADDR ps
  1325.     .ELSE
  1326.         invoke DefWindowProc,hWnd,uMsg,wParam,lParam
  1327.         ret
  1328.     .ENDIF
  1329.     xor    eax,eax
  1330.     ret
  1331. WndProc endp
  1332.  
  1333. end start
  1334. ;===========================================================================EOF
  1335.  
  1336. Let's begin our analysis : )
  1337.  
  1338.         invoke CreateFont,24,16,0,0,400,0,0,0,OEM_CHARSET,\
  1339.                     OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
  1340.                     DEFAULT_QUALITY,DEFAULT_PITCH or FF_SCRIPT,\
  1341.                     ADDR FontName
  1342.  
  1343. CreateFont creates a logical font that is the closest match to the given
  1344. parameters and the font data available. This function has more parameters
  1345. than any other function in Windows. It returns a handle to logical font to
  1346. be used by SelectObject function. We will examine its parameters in detail.
  1347.  
  1348. HFONT CreateFont(int nHeight, int nWidth, int nEscapement, int
  1349.     nOrientation, int nWeight, BYTE cItalic, BYTE cUnderline, BYTE cStrikeOut,
  1350.     BYTE cCharSet, BYTE cOutputPrecision, BYTE cClipPrecision, BYTE cQuality,
  1351.     BYTE cPitchAndFamily, LPSTR lpFacename);
  1352.  
  1353. nHeight -->  The desired height of the characters . 0 means use default size.
  1354. nWidth  --> The desired width of the characters. Normally this value should be
  1355.     0 which allows Windows to match the width to the height. However, in our
  1356.     example, the default width makes the characters hard to read, so I use the
  1357.     width of 16 instead.
  1358. nEscapement -->  Specifies the orientation of the next character output
  1359.     relative to the previous one in tenths of a degree. Normally, set to 0. Set
  1360.     to 900 to have all the characters go upward from the first character, 1800
  1361.     to write backwards, or 2700 to write each character from the top down.
  1362. nOrientation -->  Specifies how much the character should be rotated when
  1363.     output in tenths of a degree. Set to 900 to have all the characters lying
  1364.     on their backs, 1800 for upside-down writing, etc.
  1365. nWeight -->  Sets the line thickness of each character. Windows defines the
  1366.     following sizes:
  1367.  
  1368.      FW_DONTCARE        equ 0
  1369.      FW_THIN            equ 100
  1370.      FW_EXTRALIGHT      equ 200
  1371.      FW_ULTRALIGHT      equ 200
  1372.      FW_LIGHT           equ 300
  1373.      FW_NORMAL          equ 400
  1374.      FW_REGULAR         equ 400
  1375.      FW_MEDIUM          equ 500
  1376.      FW_SEMIBOLD        equ 600
  1377.      FW_DEMIBOLD        equ 600
  1378.      FW_BOLD            equ 700
  1379.      FW_EXTRABOLD       equ 800
  1380.      FW_ULTRABOLD       equ 800
  1381.      FW_HEAVY           equ 900
  1382.      FW_BLACK           equ 900
  1383.  
  1384. cItalic  --> 0 for normal, any other value for italic characters.
  1385. cUnderline -->  0 for normal, any other value for underlined characters.
  1386. cStrikeOut  --> 0 for normal, any other value for characters with a line
  1387.     through the center.
  1388. cCharSet --> The character set of the font. Normally should be OEM_CHARSET
  1389.     which allows Windows to select font which is operating system-dependent.
  1390. cOutputPrecision --> Specifies how much the selected font must be closely
  1391.     matched to the characteristics we want. Normally should be
  1392.     OUT_DEFAULT_PRECIS which defines default font mapping behavior.
  1393. cClipPrecision --> Specifies the clipping precision. The clipping precision
  1394.     defines how to clip characters that are partially outside the clipping
  1395.     region. You should be able to get by with CLIP_DEFAULT_PRECIS which defines
  1396.     the default clipping behavior.
  1397. cQuality  -->Specifies the output quality. The output quality defines how
  1398.     carefully GDI must attempt to match the logical-font attributes to those of
  1399.     an actual physical font. There are three choices: DEFAULT_QUALITY,
  1400.     PROOF_QUALITY and  DRAFT_QUALITY.
  1401. cPitchAndFamily --> Specifies pitch and family of the font. You must combine
  1402.     the pitch value and the family value with "or" operator.
  1403.     lpFacename  A pointer to a null-terminated string that specifies the
  1404.     typeface of the font.
  1405.  
  1406. The description above is by no means comprehensive. You should refer to
  1407. your Win32 API reference for more details.
  1408.  
  1409.         invoke SelectObject, hdc, eax
  1410.         mov    hfont,eax
  1411.  
  1412. After we get the handle to the logical font, we must use it to select the
  1413. font into the device context by calling SelectObject. SelectObject puts the
  1414. new GDI objects such as pens, brushs, and fonts into the device context to
  1415. be used by GDI functions. It returns the handle to the replaced object
  1416. which we should save for future SelectObject call. After SelectObject call,
  1417. any text output function will use the font we just selected into the device
  1418. context.
  1419.  
  1420.         RGB    200,200,50
  1421.         invoke SetTextColor,hdc,eax
  1422.         RGB    0,0,255
  1423.         invoke SetBkColor,hdc,eax
  1424.  
  1425. Use RGB macro to create a 32-bit RGB value to be used by SetColorText and
  1426. SetBkColor.
  1427.  
  1428.         invoke TextOut,hdc,0,0,ADDR TestString,SIZEOF TestString
  1429.  
  1430. Call TextOut function to draw the text on the client area. The text will be
  1431. in the font and color we specified previously. The syntax of TextOut is as
  1432. follows:
  1433.  
  1434. BOOL TextOut(
  1435.  
  1436.     HDC  hdc,                  // handle of device context
  1437.     int  nXStart,               // x-coordinate of starting position
  1438.     int  nYStart,               // y-coordinate of starting position
  1439.     LPCTSTR  lpString, // address of string
  1440.     int  cbString               // number of characters in string
  1441.    );
  1442.  
  1443.         invoke SelectObject,hdc, hfont
  1444.  
  1445. When we are through with the font, we should restore the old font back into
  1446. the device context. You should always restore the object that you replaced
  1447. in the device context.
  1448.  
  1449.  
  1450. ____________________________________________________________________________
  1451.                   ______               _____.  ____                         ```
  1452.   ._____/\______.________._________. ._\___ |__\_ /.                         \\
  1453.   |             |        |   _     | |   (_ |  __/ |CE                        ,
  1454. .=|_____/\______|        |----)____| |______|______|======[   Win 32 ASM ]===.
  1455. '===============|        :==================================================='
  1456.                                                                  Keyboard Input
  1457.                                                                  by Iczelion
  1458.  
  1459.  
  1460. We will learn how a Windows program receives keyboard input.
  1461.  
  1462. Preliminiary:
  1463. ------------
  1464.  
  1465. Since there's only one keyboard in each PC, all running Windows programs
  1466. must share it between them. Windows is responsible for sending the key
  1467. strokes to the window which has the input focus.
  1468.  
  1469. Although there may be several windows on the screen, only one of them has
  1470. the input focus. The window which has input focus is the only one which can
  1471. receive key strokes. You can differentiate the window which has input focus
  1472. from other windows by looking at the title bar which is highlighted.
  1473. Actually, there are two main types of keyboard message. You can view a
  1474. keyboard as a group of keys. For example, if you press the "a" key, Windows
  1475. sends a WM_KEYDOWN message to the window which has input focus, notifying
  1476. that a key is pressed. When you release the key, Windows sends a WM_KEYUP
  1477. message. In this case, you treat a key as a button. Another way to look at
  1478. the keyboard is that it's a character input device. When you press "a" key,
  1479. Windows sends a WM_CHAR message to the window which has input focus,
  1480. telling it that the user sends "a" character to it. In fact, Windows sends
  1481. WM_KEYDOWN, WM_CHAR, and WM_KEYUP messages to the window which has input
  1482. focus. The window procedure may decide to process all three messages or
  1483. only the messages it's interested in. Most of the time, you can ignore
  1484. WM_KEYDOWN and WM_KEYUP since TranslateMessage function call in the message
  1485. loop translate WM_KEYDOWN and WM_KEYUP messages to a WM_CHAR message. We
  1486. will focus on WM_CHAR in this tutorial.
  1487.  
  1488.  
  1489. Content:
  1490. -------
  1491. ;=======================================================================KEY.ASM
  1492. include windows.inc
  1493. includelib user32.lib
  1494. includelib kernel32.lib
  1495. includelib gdi32.lib
  1496.  
  1497. .data
  1498. ClassName   db "SimpleWinClass",0
  1499. AppName     db "Our First Window",0
  1500. char WPARAM 20h              ; the character the program receives from keyboard
  1501.  
  1502. .data?
  1503. hInstance HINSTANCE ?
  1504. CommandLine LPSTR ?
  1505.  
  1506. .code
  1507. start:
  1508.     invoke GetModuleHandle, NULL
  1509.     mov    hInstance,eax
  1510.     invoke GetCommandLine
  1511.     invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
  1512.     invoke ExitProcess,eax
  1513.  
  1514. WinMain proc
  1515. hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:SDWORD
  1516.     LOCAL wc:WNDCLASSEX
  1517.     LOCAL msg:MSG
  1518.     LOCAL hwnd:HWND
  1519.     mov   wc.cbSize,SIZEOF WNDCLASSEX
  1520.     mov   wc.style, CS_HREDRAW or CS_VREDRAW
  1521.     mov   wc.lpfnWndProc, OFFSET WndProc
  1522.     mov   wc.cbClsExtra,NULL
  1523.     mov   wc.cbWndExtra,NULL
  1524.     push  hInstance
  1525.     pop   wc.hInstance
  1526.     mov   wc.hbrBackground,COLOR_WINDOW+1
  1527.     mov   wc.lpszMenuName,NULL
  1528.     mov   wc.lpszClassName,OFFSET ClassName
  1529.     invoke LoadIcon,NULL,IDI_APPLICATION
  1530.     mov   wc.hIcon,eax
  1531.     mov   wc.hIconSm,0
  1532.     invoke LoadCursor,NULL,IDC_ARROW
  1533.     mov   wc.hCursor,eax
  1534.     invoke RegisterClassEx, addr wc
  1535.     invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
  1536.            WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
  1537.            CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
  1538.            hInst,NULL
  1539.     mov   hwnd,eax
  1540.     invoke ShowWindow, hwnd,SW_SHOWNORMAL
  1541.     invoke UpdateWindow, hwnd
  1542.     .WHILE TRUE
  1543.                 invoke GetMessage, ADDR msg,NULL,0,0
  1544.                 .BREAK .IF (!eax)
  1545.                 invoke TranslateMessage, ADDR msg
  1546.                 invoke DispatchMessage, ADDR msg
  1547.         .ENDW
  1548.     mov     eax,msg.wParam
  1549.     ret
  1550. WinMain endp
  1551.  
  1552. WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
  1553.     LOCAL hdc:HDC
  1554.     LOCAL ps:PAINTSTRUCT
  1555.  
  1556.     mov   eax,uMsg
  1557.     .IF eax==WM_DESTROY
  1558.         invoke PostQuitMessage,NULL
  1559.     .ELSEIF eax==WM_CHAR
  1560.         push wParam
  1561.         pop  char
  1562.         invoke InvalidateRect, hWnd,NULL,TRUE
  1563.     .ELSEIF eax==WM_PAINT
  1564.         invoke BeginPaint,hWnd, ADDR ps
  1565.         mov    hdc,eax
  1566.         invoke TextOut,hdc,0,0,ADDR char,1
  1567.         invoke EndPaint,hWnd, ADDR ps
  1568.     .ELSE
  1569.         invoke DefWindowProc,hWnd,uMsg,wParam,lParam
  1570.         ret
  1571.     .ENDIF
  1572.     xor    eax,eax
  1573.     ret
  1574. WndProc endp
  1575. end start
  1576. ;===========================================================================EOF
  1577.  
  1578. Let's analyze it:
  1579.  
  1580. char WPARAM 20h                         ; the character the program
  1581. receives from keyboard
  1582.  
  1583. This is the variable that stores the character received from the keyboard.
  1584. Since the character is sent in WPARAM of the window procedure, we define
  1585. the variable as type WPARAM for simplicity. The initial value is 20h or the
  1586. space since when our window refreshes its client area the first time, there
  1587. is no character input. So we want to display space instead.
  1588.  
  1589.     .ELSEIF eax==WM_CHAR
  1590.         push wParam
  1591.         pop  char
  1592.         invoke InvalidateRect, hWnd,NULL,TRUE
  1593.  
  1594. This is added in the window procedure to handle the WM_CHAR message. It
  1595. just puts the character into the variable named "char" and then calls
  1596. InvalidateRect. InvalidateRect makes a specified rectangle in the client
  1597. area invalid which forces Windows to send WM_PAINT message to the window
  1598. procedure. Its syntax is as follows:
  1599.  
  1600. BOOL InvalidateRect(
  1601.     HWND  hWnd,              // handle of window with changed update region
  1602.     CONST RECT  * lpRect,     // address of rectangle coordinates
  1603.     BOOL  bErase                       // erase-background flag
  1604.    );
  1605.  
  1606. lpRect is a pointer to the rectagle in the client area that we want to
  1607. declare invalid. If this parameter is null, the entire client area will be
  1608. marked as invalid.
  1609. bErase is a flag telling Windows if it needs to erase the background. If
  1610. this flag is TRUE, then Windows will erase the backgroud of the invalid
  1611. rectangle when BeginPaint is called.
  1612.  
  1613. So the strategy we used here is that: we store all necessary information
  1614. about how to paint the client area and generate WM_PAINT message to paint
  1615. the client area. Of course, the codes in WM_PAINT section must know
  1616. beforehand what's expected of them. This seems a roundabout way of doing
  1617. things but it's the way of Windows.
  1618.  
  1619. Actually we can paint the client area during processing WM_CHAR message by
  1620. calling GetDC and ReleaseDC pair. There is no problem there. But the fun
  1621. begins when our window needs to repaint its client area. Since the codes
  1622. that paint the character are in WM_CHAR section, the window procedure will
  1623. not be able to repaint our character in the client area. So the bottom line
  1624. is: put all necessary data and codes that do painting in WM_PAINT. You can
  1625. send WM_PAINT message from anywhere in your code anytime you want to
  1626. repaint the client area.
  1627.  
  1628.         invoke TextOut,hdc,0,0,ADDR char,1
  1629.  
  1630. When InvalidateRect is called, it sends a WM_PAINT message back to the
  1631. window procedure. So the codes in WM_PAINT section is called. It calls
  1632. BeginPaint as usual to get the handle to device context and then call
  1633. TextOut which draws our character in the client area at x=0, y=0. When you
  1634. run the program and press any key, you will see that character echo in the
  1635. upper left corner of the client window. And when the window is minimized
  1636. and maximized again, the character is still there since all the codes and
  1637. data essential to repaint are all gathered in WM_PAINT section.
  1638.  
  1639.  
  1640. ____________________________________________________________________________
  1641.   ::::::::::.___    .                                                       ```
  1642.   ::::::::::| _/__. |__   ____    .      __.  ____  ____   __.               \\
  1643.   ::::::    |____ | __/_ _\_ (.___|  .___) |__\_ (._)  /___) |                ,
  1644.   ::::::::::/   / | \   |  -  |   \  |  -  |   -  |  \/|  -  |
  1645. .=:::::::::/______|_____|_____|  (___|_____|______|____|_____|===============.
  1646. '=::::::::::==================|   . ____ | (____====[ The C Standard lib ]==='
  1647.   ::::::::::                  |   |------|  -   |                       
  1648.   ::::::::::                  |   |______|______|CE                     
  1649.                               .   :
  1650.                                       C string functions: introduction, _strlen
  1651.                                       by Xbios2
  1652.  
  1653.  
  1654. I. INTRODUCTION
  1655. ---------------
  1656. Beware: this is going to be long...
  1657.  
  1658. String handling in assembly is - anyway - a difficult subject. There are few 
  1659. string-oriented x86 opcodes, and most of them are slow. There is not a standard 
  1660. library providing even basic functions. There is no string specific syntax in 
  1661. assembly, like C's printf('hello world') or, even worse, BASIC's a$=b$+'hello'. 
  1662. In a few words, if easy string-related programming is your goal, maybe you 
  1663. should consider PERL, or another text-manipulation language.
  1664.  
  1665. Yet, string functions are really needed, since almost any program in assembly 
  1666. uses text for I/O. (An alternative to this would be using animated paper-clips 
  1667. to communicate with the user :)).
  1668.  
  1669. Furthermore, coding those functions in assembly allows for smaller and faster 
  1670. functions. Actually many of the string functions in C _were_ written in 
  1671. assembly (e.g. strlen, strcat, strcpy, etc). Those can be divided in two 
  1672. categories:
  1673.  
  1674. -'Traditional' functions, using the x86 string instructions
  1675. -'Modern' functions, which run faster by being Pentium-optimized
  1676.  
  1677. Borland C++ 4.02 and KERNEL32.DLL only have traditional functions. Borland's 
  1678. C++ Builder v1.0 (once given free as a demo) includes both types. MSVCRT.DLL 
  1679. (version 5) contains 'modern' versions.
  1680.  
  1681. The three main aspects considered in these articles (and generally when compar-
  1682. ing different versions of the same function) are speed, size and common sense. 
  1683.  
  1684. 'Common sense' indicates how easy it is to understand the way a function 
  1685. operates by reading the source code, how 'elegant' the code is. In a library 
  1686. module distributed as a binary (in a 'static' reuse of code), common sense is 
  1687. not important. It becomes important when the source code is distributed too, 
  1688. because it allows 'dynamic' reuse. 'Elegant' code can be easily optimized for 
  1689. specific needs or expanded to become a more general function.
  1690.  
  1691. 'Size' is, obviously, the size of the resulting code. Besides creating smaller 
  1692. files, small size has two interesting 'side-effects'. It (usually) creates more 
  1693. elegant code and faster code (it decreases k, but it usually increases l (for 
  1694. an explanation of k and l see 'speed'). For very small functions like strlen it 
  1695. has the added advantage of allowing the code to be inlined without wasting too 
  1696. much space, thus decreasing k even more.
  1697.  
  1698. 'Speed' indicates the number of cycles needed to execute the function. For 
  1699. simple string functions the number of cycles needed can be expressed as
  1700.  
  1701.  c=k+l*n
  1702.  
  1703. where c is the total number of cycles, k is the number of cycles needed to 
  1704. 'prepare' the function, l is the number of cycles needed to process each chara-
  1705. cter and n is the number of characters in the string. It is obvious that small 
  1706. values of c mean faster execution. In order to compare two versions of a 
  1707. function that run at speeds of
  1708.  
  1709.  c1=k1+l1*n    and   c2=k2+l2*n
  1710.  
  1711. the ratio of c1/c2 is calculated:
  1712.  
  1713.     c1   k1+l1*n
  1714.  r=----=---------
  1715.     c2   k2+l2*n
  1716.  
  1717. if r=1 then both versions run at the same speed.
  1718. if r>1 then version 2 is faster. if r<1 then version 1 is faster.
  1719. Simple maths prove that:
  1720.  
  1721. 1. When n becomes infinite, r becomes equal to l1/l2. Especially if l1=l2,
  1722.    then r=1
  1723.  
  1724. 2. If k1<k2 but l1>l2, c1<c2 (version 1 is faster) if n<(k2-k1)/(l1-l2).
  1725.  
  1726. Point 1 means that for long strings speed is (almost) independent of the value 
  1727. of k. Especially if l1=l2 both versions will run at (almost) the same speed.
  1728. Point 2 means that for small strings k strongly affects the value of c.
  1729.  
  1730. For those of you that are fed up with maths, here is a simple example that 
  1731. demonstrates what I've been trying to say all this time :)
  1732.  
  1733. If version 1 runs at c1=10+3*n and version 2 at c2=30+1*n then:
  1734.  
  1735. -For strings up to 9 chars version 1 is faster
  1736. -For strings of 10 chars both versions run at the same speed
  1737. -For strings of 11 or more version 2 is faster
  1738. -For strings of 50 chars, version 2 is 2x faster than version 1
  1739. -For strings of 770 chars version 2 is 2.9x faster than version 1
  1740.  
  1741. The problem is that none of the above versions can be classified as better than 
  1742. the other. Think of the parser of a compiler. It receives as input lines from a 
  1743. text file, which are strings longer than 10 characters, but also has to deal 
  1744. with tokens, which are short strings (in an assembler, three-char tokens are 
  1745. very common).
  1746.  
  1747. Keep in mind that, while l depends only on the method used to implement the 
  1748. function, k also depends on the 'push arg/call/prepare stack/resore stack/ 
  1749. ret/get arg' times. So if n is low, overall speed can be increased by inlining 
  1750. the code, thus subtracting from k the time needed to call the function.
  1751.  
  1752. Well, I think you've had enough. Let's see all this stuff in practice.
  1753.  
  1754.  
  1755. II. THE _STRLEN FUNCTION
  1756. ------------------------
  1757. Attention: especially for _strlen, ALL versions I have either written or found 
  1758. in libraries will be explained. This means you'll get source code for 8 
  1759. functions...
  1760.  
  1761. size_t strlen(const char *s);
  1762.  
  1763. Calculates the length of a string. strlen returns the number of characters in 
  1764. s, not counting the null-terminating character.
  1765.  
  1766. _strlen is the simplest of the string functions. The 'traditional' way to 
  1767. implement it is through 'repne scasb'. BC 4.02 implements it as:
  1768.  
  1769. ; ------------ version 1 ------------
  1770. ; Borland C++ 4.02
  1771. ; 25 bytes
  1772. ; c=27+4*n
  1773.  
  1774. _strlen    proc near
  1775.     push    ebp
  1776.     mov    ebp, esp
  1777.     push    edi
  1778.     mov    edi, [ebp+8]
  1779.     mov    ecx, -1
  1780.     xor    al, al
  1781.     cld    
  1782.     repne scasb
  1783.     not    ecx
  1784.     lea    eax, [ecx-1]
  1785.     pop    edi
  1786.     pop    ebp
  1787.     retn
  1788. _strlen    endp
  1789. ; -----------------------------------
  1790.  
  1791. A shorter, and a bit faster version of this would be:
  1792.  
  1793. ; ------------ version 2 ------------
  1794. ; Improved 'repne scasb'
  1795. ; 18 bytes
  1796. ; c=21+4*n
  1797.  
  1798. _strlen    proc near
  1799.     xor    eax, eax
  1800.     push    edi
  1801.     mov    edi, [esp+8]
  1802.     or    ecx, -1
  1803.     repne scasb
  1804.     sub    eax, 2
  1805.     pop    edi
  1806.     sub    eax, ecx
  1807.     retn    
  1808. _strlen    endp
  1809. ; -----------------------------------
  1810.  
  1811. The win32 API also includes a strlen function, called lstrlenA. It is based on 
  1812. 'repne scasb' as well, but you are _strongly_ advised to avoid it. It runs at 
  1813. c=56+4*n cycles.
  1814.  
  1815. The most 'common sense' function (IMHO) is also the smallest:
  1816.  
  1817. ; ------------ version 3 ------------
  1818. ; Elegant and very small
  1819. ; 15 bytes
  1820. ; c=27+4*n
  1821. ; k is so big because we have a retn immediately after a jump
  1822. ; if a nop is added between those two, k drops to 13
  1823.  
  1824. _strlen    proc near
  1825.     or    eax, -1
  1826.     mov    ecx, [esp+4]
  1827. loop1:    inc    eax
  1828.     cmp    byte ptr [ecx+eax], 0
  1829.     jnz    short loop1
  1830.     ; nop
  1831.     retn
  1832. _strlen    endp
  1833. ; -----------------------------------
  1834.  
  1835. Which gets a little less elegant but faster if tweaked a little:
  1836. (The trick is that the carry flag is set by the 'cmp' instruction if the byte 
  1837. read is 0, else it is cleared. The 'inc' instruction doesn't affect the carry 
  1838. flag).
  1839.  
  1840. ; ------------ version 4 ------------
  1841. ; Very small and faster than repne scasb
  1842. ; 15 bytes
  1843. ; c=12+3*n
  1844.  
  1845. _strlen    proc near
  1846.     mov    ecx, [esp+4]
  1847.     xor    eax, eax
  1848. loop1:    cmp    byte ptr [ecx+eax], 1
  1849.     inc    eax
  1850.     jnc    short loop1
  1851.     dec    eax
  1852.     retn
  1853. _strlen    endp
  1854. ; -----------------------------------
  1855.  
  1856. But it gets even better as inlined code, as a macro:
  1857.  
  1858. ; ------------ version 4.5 ------------
  1859. ; Very small, extremely elegant macro
  1860. ; 10 bytes
  1861. ; c=8+3*n
  1862.  
  1863. strlen    macro srcreg, cntreg
  1864.     xor    cntreg, cntreg
  1865.     cmp    byte ptr [srcreg+cntreg], 1
  1866.     inc    cntreg
  1867.     jnc    $-5
  1868.     dec    eax
  1869.     endm
  1870. ; -----------------------------------
  1871.  
  1872. This macro returns in cntreg the length of the string at srcreg.
  1873. It uses no other registers, srcreg is unchanged, it is only 10 bytes long and 
  1874. it runs at a speed of only 8+3*n cycles. It also returns its value in any 
  1875. register, without altering the other registers.
  1876.  
  1877. Suppose we need in ecx the length of the string at esi. The following code:
  1878.  
  1879.     push    esi
  1880.     call    _strlen
  1881.     pop    ecx    ; restore stack
  1882.     mov    ecx, eax
  1883.  
  1884. takes 9 bytes, only one less than the macro version. Plus, of course, the at 
  1885. least 15 bytes of code in _strlen.
  1886.  
  1887. Another 'elegant' version, which is also small and much faster is the following:
  1888.  
  1889. ; ------------ version 5 ------------
  1890. ; Elegant, small and fast
  1891. ; 16 bytes
  1892. ; c=12+2*n
  1893.  
  1894. _strlen    proc near
  1895.     mov    ecx, [esp+4]
  1896.     xor    eax, eax
  1897. loop1:    mov    dl, [ecx+eax]
  1898.     inc    eax
  1899.     or    dl, dl
  1900.     jnz    short loop1
  1901.     dec    eax
  1902.     retn
  1903. _strlen    endp
  1904. ; -----------------------------------
  1905.  
  1906. I believe that version 5 is the best version that could have elegance, speed 
  1907. and small size together. It can also be converted to a macro and inlined to 
  1908. drop to a speed of c=8+2*n (it will use one register more, but this register 
  1909. would anyway be lost if a call to the function was made).
  1910.  
  1911. It also has what I believe is the smallest value of k. However, it doesn't have 
  1912. the smallest value of l. To reduce the cycles needed, data can be read not byte 
  1913. after byte but dword after dword. Here is a routine given by Agner Fog in his 
  1914. document on Pentium optimization (which you are _strongly_ advised to read):
  1915.  
  1916. ; ------------ version 6 ------------
  1917. ; [by Agner Fog] Very fast
  1918. ; 61 bytes
  1919. ; c=18+1*n (not exactly, as data is read in 4 byte blocks)
  1920.  
  1921. _strlen    proc
  1922.     mov    eax, [esp+4]        ; get pointer
  1923.     mov    edx, 7
  1924.     add    edx, eax        ; pointer+7 used in the end
  1925.     push    ebx
  1926.     mov    ebx, [eax]        ; read first 4 bytes
  1927.     add    eax, 4            ; increment pointer
  1928. l1:    lea    ecx, [ebx-01010101h]    ; subtract 1 from each byte
  1929.     xor    ebx, -1            ; invert all bytes
  1930.     and    ecx, ebx        ; and these two
  1931.     mov    ebx, [eax]        ; read next 4 bytes
  1932.     add    eax, 4            ; increment pointer
  1933.     and    ecx, 80808080h        ; test all sign bits
  1934.     jz    l1            ; no zero bytes, continue loop
  1935.     test    ecx, 00008080h        ; test first two bytes
  1936.     jnz    short l2
  1937.     shr    ecx, 16            ; not in the first 2 bytes
  1938.     add    eax, 2
  1939. l2:    shl    cl, 1            ; use carry flag to avoid a branch
  1940.     pop    ebx
  1941.     sbb    eax, edx        ; compute length
  1942.     ret
  1943. _strlen endp
  1944. ; -----------------------------------
  1945.  
  1946. The only problem with this routine is that it expects the string to be aligned 
  1947. on a 4 byte boundary. If the string is misaligned, the speed drops to 
  1948. c=24+1.75*n. In the extreme case that the string is misalinged AND it ends on a 
  1949. page boundary, the function will cause an access violation error.
  1950.  
  1951. The fastest version (I have found) is the one in the Borland C++ builder 
  1952. library:
  1953.  
  1954. ; ------------ version 7 ------------
  1955. ; [C++ Builder, slightly modified] Fastest
  1956. ; 88 bytes
  1957. ; c=20+0.75*n (not exactly, see notes)
  1958.  
  1959. _strlen    proc near
  1960.     mov    eax, [esp+4]
  1961.     test    al, 3
  1962.     jnz    short unalgn
  1963.  
  1964. loop1:    mov    edx, [eax]
  1965.     add    eax, 4
  1966.     mov    ecx, edx
  1967.     sub    edx, 1010101h
  1968.     and    edx, 80808080h
  1969.     jz    short loop1
  1970.     not    ecx
  1971.     and    edx, ecx
  1972.     jz    short loop1
  1973.     test    dl, dl
  1974.     jnz    short minus4
  1975.     test    dh, dh
  1976.     jnz    short minus3
  1977.     test    edx, 0FF0000h
  1978.     jnz    short minus2
  1979.     jmp    short minus1
  1980.  
  1981. unalgn:    add    eax, 3
  1982.     xor    cl, cl
  1983.     cmp    byte ptr [eax-3], cl
  1984.     jz    short minus3
  1985.     cmp    byte ptr [eax-2], cl
  1986.     jz    short minus2
  1987.     cmp    byte ptr [eax-1], cl
  1988.     jz    short minus1
  1989.     and    al, 0FCh
  1990.     jmp    short loop1
  1991.  
  1992. minus4:    dec    eax
  1993. minus3:    dec    eax
  1994. minus2:    dec    eax
  1995. minus1:    mov    ecx, [esp+4]
  1996.     dec    eax
  1997.     sub    eax, ecx
  1998.     retn    
  1999. _strlen    endp
  2000. ; -----------------------------------
  2001.  
  2002. Actually, the original version is 90 bytes long. I have only changed the 
  2003. 'unalgn:' block, to reduce k if the string is unaligned.
  2004.  
  2005. This function works well even on unaligned strings, as it first check the unali-
  2006. gned bytes, and the proceeds in the main loop with aligned data (for unaligned 
  2007. strings it runs at c=31+0.75*n cycles). Since all dwords read are aligned, 
  2008. unaligned strings that end on page boundaries don't cause problems.
  2009.  
  2010. This function is not always the fastest. If the string contains characters in 
  2011. the range 128 to 255 (i.e. signed bytes) the speed drops. If all the characters 
  2012. are signed (actually if at least one byte in every dword read), the speed 
  2013. becomes c=1.25*n. Of course most of the time (especially for english text) this 
  2014. is not the case, but if you have to process strings in another language that 
  2015. has characters in the range 128 to 255, it is a bit slower.
  2016.  
  2017. Another fast version of strlen can be found in MSVCRT.DLL (the one I checked is 
  2018. version 5.00.7303). It runs at c=20+1*n, and handles unaligned strings almost 
  2019. like the Builder version. Misaligned strings give a value of k ranging from a 
  2020. minimum of 25 to a maximum of 52.
  2021.  
  2022. What the MSVCRT function lacks completely is common sense and small size. In 
  2023. fact it is 144 bytes long and it is divided in two different pieces of the dll's 
  2024. code, causing most jumps to be in the long form.
  2025.  
  2026. The main loop MSVCRT uses is good, but the rest of the function isn't. Based on 
  2027. that function, I came up with the following one:
  2028.  
  2029. ; ------------ version 8 ------------
  2030. ; My fast version
  2031. ; 92 bytes
  2032. ; c=17+1*n
  2033.  
  2034. _strlen    proc
  2035.     mov    eax, [esp+4]
  2036.     xor    ecx, ecx
  2037. loop2:    test    al, 3
  2038.     jz    loop1
  2039.     cmp    byte ptr [eax], cl
  2040.     jz    short ret0
  2041.     cmp    byte ptr [eax+1], cl
  2042.     jz    short ret1
  2043.     cmp    byte ptr [eax+2], cl
  2044.     jnz    short adjust
  2045.     inc    eax
  2046. ret1:    inc    eax
  2047. ret0:    sub    eax, [esp+4]
  2048.     ret
  2049.  
  2050. adjust:    add    eax, 3
  2051.     and    eax, 0FFFFFFFCh
  2052.  
  2053. loop1:    mov    edx, [eax]
  2054.     mov    ecx, 81010100h
  2055.     sub    ecx, edx
  2056.     add    eax, 4
  2057.     xor    ecx, edx
  2058.     and    ecx, 81010100h
  2059.     jz    loop1
  2060.     sub    eax, [esp+4]
  2061.     shr    ecx, 9
  2062.     jc    minus4
  2063.     shr    ecx, 8
  2064.     jc    minus3
  2065.     shr    ecx, 8
  2066.     jc    minus2
  2067. minus1:    dec    eax
  2068.     ret    
  2069. minus4:    sub    eax, 4
  2070.     ret    
  2071. minus3:    sub    eax, 3
  2072.     ret    
  2073. minus2:    sub    eax, 2
  2074.     ret    
  2075. _strlen    endp
  2076. ; -----------------------------------
  2077.  
  2078. This one has the advantage of having k=17 for aligned strings and k=24 to 25 
  2079. for misaligned ones.
  2080.  
  2081. The only question left to be answered is: 'Which version should we prefer?'.
  2082.  
  2083. If your program does not include string handling in it's time-critical parts, 
  2084. I higly recommend either versions 5 or 4.5 (the inlined macro). As said before, 
  2085. the size overhead of the inlined version is very small (if any), and it has 
  2086. another advantage: it keeps the source code more readable, as it only involves 
  2087. the needed registers (input and output) in one single line.
  2088.  
  2089. If string handling IS time-critical, I recommend version 8 (of course, it's 
  2090. mine... :)). Even then, the average size of the handled strings is to be consi-
  2091. dered, as well as the percentage of unaligned strings. For unaligned strings of 
  2092. 16 or less characters, the fastest version would be an inlined version 5, 
  2093. running at c=8+2*n.
  2094.  
  2095. The choice is yours....
  2096.  
  2097.  
  2098. ____________________________________________________________________________
  2099.   ::::::::::.___    .                                                       ```
  2100.   ::::::::::| _/__. |__   ____    .      __.  ____  ____   __.               \\
  2101.   ::::::    |____ | __/_ _\_ (.___|  .___) |__\_ (._)  /___) |                ,
  2102.   ::::::::::/   / | \   |  -  |   \  |  -  |   -  |  \/|  -  |
  2103. .=:::::::::/______|_____|_____|  (___|_____|______|____|_____|===============.
  2104. '=::::::::::==================|   . ____ | (____====[ The C Standard lib ]==='
  2105.   ::::::::::                  |   |------|  -   |                       
  2106.   ::::::::::                  |   |______|______|CE                     
  2107.                               .   :
  2108.                                                     C string functions: _strcpy
  2109.                                                     by Xbios2
  2110.  
  2111.  
  2112. I. INTRODUCTION
  2113. ---------------
  2114. C syntax: char *strcpy(char *dest, const char *src);
  2115.  
  2116. _strcpy copies string src to dest, stopping after the terminating null character 
  2117. has been moved, and returns dest.
  2118.  
  2119. The 'traditional' way to do this is with the 'rep movs' instruction. BC 4.02 
  2120. and kernel32 use it. The problem is that it is rather slow (BC _strlen takes 
  2121. 53+5.5*n cycles, lstrlenA takes 74+5.5*n cycles, and optimizing their code 
  2122. leads to 46+5.5*n cycles wher n the number of chars, see part I of these 
  2123. articles). This is because even though the 'rep movs' instruction is fast it 
  2124. needs to know the number of bytes to copy in advance. So, _strcpy includes a 
  2125. _strlen function before the actual copying, which is implemented through 'repne 
  2126. scasb', a slow instruction.
  2127.  
  2128. In this article we will examine two 'modern' _strcpy functions, found in 
  2129. MSVCRT.DLL and Borland C++ Builder library. Those functions are (supposed to be) 
  2130. optimized for Pentium processors. If you're not familiar with optimization for 
  2131. Pentium processors,  I suggest you read the document on Pentium optimization by 
  2132. Agner Fog (http://announce.com/agner/assem).
  2133.  
  2134.  
  2135. II. STRCPY IN MSVCRT
  2136. --------------------
  2137. ; c=39+1.75*n / 146 bytes
  2138.  
  2139. strcpy    proc
  2140.     push    edi
  2141.     mov    edi, [esp+8]    ; dest
  2142.     mov    ecx, [esp+0Ch]    ; src
  2143.     test    ecx, 3
  2144.     jz    short loop1
  2145.  
  2146. algn:    mov    dl, [ecx]
  2147.     inc    ecx
  2148.     test    dl, dl
  2149.     jz    short one
  2150.     mov    [edi], dl
  2151.     inc    edi
  2152.     test    ecx, 3
  2153.     jnz    short algn
  2154.  
  2155. loop1:    mov    edx, -81010101h
  2156.     mov    eax, [ecx]
  2157.     add    edx, eax
  2158.     xor    eax, -1
  2159.     xor    eax, edx
  2160.     mov    edx, [ecx]
  2161.     add    ecx, 4
  2162.     test    eax, 81010100h
  2163.     jz    short nozero
  2164.     test    dl, dl
  2165.     jz    short one
  2166.     test    dh, dh
  2167.     jz    short two
  2168.     test    edx, 0FF0000h
  2169.     jz    short three
  2170.     test    edx, 0FF000000h
  2171.     jz    short four
  2172.  
  2173. nozero:    mov    [edi], edx
  2174.     add    edi, 4
  2175.     jmp    short loop1
  2176.     ;... in the DLL, there is code here, not used by strcpy
  2177.  
  2178. one:    mov    [edi], dl
  2179.     mov     eax, [esp+8]
  2180.     pop     edi
  2181.     retn
  2182.  
  2183. two:    mov    [edi], dx
  2184.     mov    eax, [esp+8]
  2185.     pop    edi
  2186.     retn
  2187.  
  2188. three:    mov    [edi], dx
  2189.     mov    eax, [esp+8]
  2190.     mov    byte ptr [edi+2], 0
  2191.     pop    edi
  2192.     retn
  2193.  
  2194. four:    mov    [edi], edx
  2195.     mov    eax, [esp+8]
  2196.     pop    edi
  2197.     retn
  2198. strcpy    endp
  2199.  
  2200. This procedure does the following:
  2201. 1. Read arguments (src, dest) from stack
  2202. 2. Check if src is aligned on a 4 byte boundary
  2203.    If not, copy byte after byte until src gets aligned
  2204. 3. Loop
  2205.    Read one dword from src
  2206.    Test if there is a zero byte in the dword
  2207.    If no zero, copy dword to dest, loop back
  2208. 4. Copy the remaining bytes
  2209. 5. Return with dest in eax
  2210.  
  2211. Actually the code above compiles to 130 bytes. The extra 16 bytes are added 
  2212. because between the loop and the 'one:' label there is the strcat function. So 
  2213. 4 conditional jumps take the 6-byte form, not the 2-byte one.
  2214.  
  2215. This function takes 39+1.75*n. This means that the loop takes 7 cycles to 
  2216. execute (since each time the loop runs, it copies 4 bytes). Here is the explan-
  2217. ation of the loop (U and V refer to the pipe the commands run in).
  2218.  
  2219. loop1:    mov    edx, -81010101h    ; U   1st
  2220.     mov    eax, [ecx]    ;  V
  2221.     add    edx, eax    ; U   2nd
  2222.     xor    eax, -1        ;  V
  2223.     xor    eax, edx    ; U   3rd
  2224.     mov    edx, [ecx]    ;  V
  2225.     add    ecx, 4        ; U   4th
  2226.     test    eax, 81010100h    ;  V
  2227.     jz    short nozero    ; U   5th
  2228.     ...
  2229. nozero:    mov    [edi], edx    ; U   6th
  2230.     add    edi, 4        ;  V
  2231.     jmp    short loop1    ; U   7th
  2232.  
  2233. The problem here is that both jumps run in the U pipe so they will not pair. 
  2234. Generally it's better to have an even number of instructions in each block of 
  2235. code. Just by moving one instruction this code will run in 6 cycles (i.e. 
  2236. 39+1.5*n cycles):
  2237.  
  2238. loop1:    mov    edx, -81010101h    ; U   1st
  2239.     mov    eax, [ecx]    ;  V
  2240.     add    edx, eax    ; U   2nd
  2241.     xor    eax, -1        ;  V
  2242.     xor    eax, edx    ; U   3rd
  2243.     mov    edx, [ecx]    ;  V
  2244.     test    eax, 81010100h    ; U
  2245.     jz    short nozero    ;  V  4th
  2246.     ...
  2247. nozero:    mov    [edi], edx    ; U   5th
  2248.     add    ecx, 4        ;  V  <<< moved instruction
  2249.     add    edi, 4        ; U
  2250.     jmp    short loop1    ;  V  6th
  2251.  
  2252. Everything pairs perfectly, and so 12 instructions only take 6 cycles. Pay 
  2253. attention to one thing: if 'add ecx, 4' and 'add edi, 4' are swapped, we get 
  2254. back to 7 cycles per loop, even though the pairing is the same. This is because 
  2255. the 'mov eax, [ecx]' instruction uses ecx to access memory, but ecx was changed 
  2256. in the previous clock cycle (add ecx, 4 / jmp short loop1). This causes an AGI 
  2257. stall (Address Generation Interlock), which wastes one cycle.
  2258.  
  2259. As you 've noticed, _strcpy makes sure that the data read from src is aligned, 
  2260. because reading aligned dwords is faster. If src is aligned, the test only takes 
  2261. one cycle more, so it shouldn't trouble us. Yet, aligning src is not always a 
  2262. good idea. Suppose that you have an unaligned string and want to copy it in a 
  2263. buffer that is aligned. So what happens is that by aligning src we misalign 
  2264. dest. The problem is that misaligned writes are more expensive in cycles than 
  2265. misaligned reads. So _strcpy should either align dest or leave everything 
  2266. untouched. (not aligning src introduces an extremely small possibility of an 
  2267. access violation error, read section V below for details).
  2268.  
  2269.  
  2270. III. STRCPY IN C++ B
  2271.  
  2272.