Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
iakovlev.org
  Материал взят со страницы профессора университета Сан-Франциско Allan B. Cruse
  
 
  Рассмотрим первый пример - demo2  
 Он складывает два числа
 Для сборки этого примера нужно откомпилировать 2 файла .
 В первом файле - sprintf.c - находится оригинальная версия 
 библиотечной функции printf . 
 
 Для компиляции нужно выполнить 3 команды :
         as sprintf.s -o sprintf.o
         as demo2.s -o demo2.o
         ld demo2.o sprintf.o -o demo2
  
 //----------------------------------------------------------------
 //      demo2.s
 //      programmer: ALLAN CRUSE
 //      written on: 2005
 //----------------------------------------------------------------
 
         .equ    sys_exit, 1
         .equ    sys_write, 4
         .equ    device_id, 1
 
         .section        .data
 x:      .int    4
 y:      .int    5
 z:      .int    0
 fmt:    .asciz  "%d + %d = %d \n"
 buf:    .space  80
 len:    .int    0       
 
         .section        .text
 _start: # perform the assignment:  z = x + y; 
         movl    x, %eax
         addl    y, %eax
         movl    %eax, z 
 
         # call library-function:  len = sprintf( buf, fmt, x, y, z );
         pushl   z
         pushl   y
         pushl   x
         pushl   $fmt
         pushl   $buf
         call    sprintf
         addl    $20, %esp
         orl     %eax, %eax
         js      fini
         movl    %eax, len
 
         # make Linux system-call:  write( device_id, &buf, len );
         movl    $sys_write, %eax
         movl    $device_id, %ebx
         movl    $buf, %ecx
         movl    len, %edx
         int     $0x80
         
 fini:   # make Linux system-call:  exit( 0 );
         movl    $sys_exit, %eax
         movl    $0, %ebx
         int     $0x80
         
         .global _start
         .end
 
 //----------------------------------------------------------------
 //      sprintf.s
 //
 //     int sprintf( char *dst, char *fmt, ... );
 //----------------------------------------------------------------
 
         .section        .text
 numeral: .ascii   "0123456789ABCDEF"    # our translation-table
 sprintf:
         pushl   %ebp                    # preserve frame-pointer
         movl    %esp, %ebp              # setup local stack-frame
         subl    $4, %esp                # create space for radix 
         pushal                          # preserve cpu registers
         
         movl    8(%ebp), %edi           # dst parameter into EDI
         movl    12(%ebp), %esi          # fmt parameter into ESI
         movl    $0, %ecx                # initial argument-index
 
         cld                             # use forward processing
 again:
         cmpb    $0, (%esi)              # test: null-terminator?
         je      finish                  # yes, we are finished
 
         cmpb    $'%', (%esi)            # test: format-escape?
         je      escape                  # yes, insert numerals
 
         movsb                           # else copy the character
         jmp     again                   # and go back for another
 
 finish: subl    8(%ebp), %edi           # compute output length
         movl    %edi, 8(%ebp)           # and save it on stack
         jmp     return                  # then exit this function 
 
 escape: incl    %esi                    # skip past escape-code
         lodsb                           # and fetch escape-type
 
         cmpb    $'d', %al               # wanted decimal-format?
         movl    $10, -4(%ebp)           # yes, use 10 as the radix
         je      do_tx                   # convert number to string
 
         cmpb    $'X', %al               # wanted hexadecimal-format?
         movl    $16, -4(%ebp)           # yes, use 16 as the radix
         je      do_tx                   # convert number to string
 
         jmp     errorx                  # otherwise return error
 
 do_tx:
         movl    $numeral, %ebx          # point EBX to numeral-list 
         movl    16(%ebp,%ecx,4), %eax   # get next argument in EAX
         incl    %ecx                    # and advance argument-index
 
         pushl   %ecx                    # preserve argument-index
         xorl    %ecx, %ecx              # initialize digit-counter
 nxdiv:  
         xorl    %edx, %edx              # extend dividend to quadword
         divl    -4(%ebp)                # divide by selected radix
         push    %edx                    # push remainder onto stack
         incl    %ecx                    # and increment digit-count
         orl     %eax, %eax              # test: quotient was zero?
         jnz     nxdiv                   # no, another digit needed
 nxdgt:
         popl    %eax                    # saved remainder into EAX
         xlat    %cs:(%ebx)              # convert number to numeral 
         stosb                           # store numeral in buffer
         loop    nxdgt                   # go get the next remainder
 
         popl    %ecx                    # recover the argument-index
         jmp     again                   # and resume copying format
 
 errorx: movl    $-1, 8(%ebp)            # store error-indicator
 return: popal                           # restore saved registers
         movl    8(%ebp), %eax           # copy return-value to EAX
         movl    %ebp, %esp              # discard temporary storage 
         popl    %ebp                    # restore saved frame-pointer
         ret                             # return control to caller
 
         .global sprintf                 # make entry-point public
         .end                            # ignore everything beyond
 
         
         
 
 Следующий пример - squares.s
 Распечатываются квадраты первых 20 натуральных чисел .
 Прошу обратить внимание на то , что при вычислении квадратов 
 используются только 2 инструкции - add и inc :
 
 //----------------------------------------------------------------
 //      squares.s
 //                      $ gcc squares.s -o squares
 //----------------------------------------------------------------
 
         .equ            MAX, 20         # total number of lines 
 
         .section        .data
 arg:    .int            1               # stores current number
 val:    .int            1               # stores current square
 head:   .string         "\n     Table of Squares\n\n"
 body:   .string         "       %2d       %3d     \n"
 foot:   .string         "\n"            # newline format-string
 
         .section        .text
 main:   # print the table's title
         pushl           $head           # address of format-string
         call            printf          # call the runtime library
         addl            $4, %esp        # discard the one argument
 
         # program loop, to print table's body
 again:
         # print next line of the table
         pushl           val             # numerical argument #2
         pushl           arg             # numerical argument #1
         pushl           $body           # format-string argument
         call            printf          # call the runtime library
         addl            $12, %esp       # discard the 3 arguments
         # compute the next square
         movl            arg, %eax       # fetch the current number
         addl            %eax, %eax      # compute twice its value
         incl            %eax            # add one to that result
         addl            %eax, val       # add this to prior square
         # and compute next number
         incl            arg             # increment current number
         # check loop exit-condition
         cmpl            $MAX, arg       # does arg exceed maximum?  
         jle             again           # no, display another line
 
         # print a blank bottom line
         pushl           $foot           # format-string argument
         call            printf          # call the runtime library
         addl            $4, %esp        # now discard the argument
 
         ret                             # return control to caller
 
         .global         main            # makes entry-point public
 
 
  Следующий пример обрабатывает ввод с клавиатуры числа ,
 переводит набранный символ в число и организует по нему
 цикл распечатки 
 
 //----------------------------------------------------------------
 //        showdots.s
 //        assemble-and-link using:  gcc showdots.s -o showdots
 //----------------------------------------------------------------
 
 
         # our symbolic constants
         .equ    sys_write, 4            # service ID-number
         .equ    sys_read, 3             # service ID-number
         .equ    stdout_ID, 1            # device ID-number
         .equ    stdin_ID, 0             # device ID-number
 
 
         .section        .data
 msg:    .ascii  "How many dots do you want to see? "
 len:    .int    . - msg                 # number of msg characters
 inbuf:  .space  8                       # storage for user's input
 maxin:  .int    . - inbuf               # amount of storage space
 dot:    .byte   '.'                     # ascii-code for a period
 count:  .int    0                       # dot repetitions counter
 newln:  .byte   '\n'                    # ascii-code for linefeed
 
 
         .section        .text
 main:   call    obtain_input            # our 'Input' subroutine
         call    process_data            # our 'Process' subroutine
         call    print_output            # our 'Output' subroutine
         ret                             # return to command shell 
 
         .globl  main                    # make entry-point visible
 
 
 obtain_input:
         # print message asking for user's input
         movl    $sys_write, %eax        # specify system service
         movl    $stdout_ID, %ebx        # specify desired device
         movl    $msg, %ecx              # output-string's address
         movl    len, %edx               # length of output-string
         int     $0x80                   # enter the Linux kernel
 
         # input the user's response
         movl    $sys_read, %eax         # specify system service
         movl    $stdin_ID, %ebx         # specify desired device
         movl    $inbuf, %ecx            # address of input buffer
         movl    maxin, %edx             # maximum bytes to accept
         int     $0x80                   # enter the Linux kernel
         movl    %eax, maxin             # actual length of input        
         
         # TODO: we ought to terminate with an error-message if our 
         # user types in more characters than can fit in our buffer
 
         ret
 
  
 process_data:
         # We will loop though the characters in 'inbuf' until we
         # encounter an ascii-code that is NOT a decimal numeral,
         # or until we come to the last byte in our input-buffer.  
         # We shall begin with a 'count' value equal to zero, but
         # each time we encounter another valid numeral (i.e., an
         # ascii-code from '0' through '9') we will convert it to
         # its corresponding integer value, and that integer will
         # be added to ten-times-count.  (We have not yet studied 
         # the Pentium's multiplication instruction, so right now
         # we can get the effect of multiplying by ten by using a
         # series of add-instructions, since 10*x = 2*(x + 4*x).
 
         movl    $0, count               # initial count is zero
         cmpl    $0, maxin               # test: error in input?
         jle     fini                    # yes, no further work 
 
         xorl    %esi, %esi              # initial index is zero
 again:  cmpl    %esi, maxin             # input exhausted yet? 
         jle     fini                    # yes, we are finished
 
         movb    inbuf(%esi), %al        # fetch next character
         incl    %esi                    # advance source index
         
         cmpb    $'0', %al               # char preceeds '0'?
         jb      fini                    # yes, invalid numeral
         cmpb    $'9', %al               # char follows '9'?
         ja      fini                    # yes, invalid numeral
         
         subb    $'0', %al               # convert to a number
         movzx   %al, %eax               # extended to 32-bits
 
         movl    count, %edx             # prior 'count' value
         addl    count, %edx             #  is doubled in EDX
         addl    %edx, %edx              #  and doubled again
         addl    count, %edx             # now five times count
         addl    %edx, %edx              #  is added to itself
         addl    %eax, %edx              #  add the new number  
         movl    %edx, count             # store this new total
         jmp     again                   # go back for another
 fini:   ret                             # return to 'main' 
 
 
 print_output:
         # check: are any more dots to be printed? 
         cmp     $0, count               # is 'count' positive?
         jle     done                    # no, printing is done
 
         # print one dot character
         movl    $sys_write, %eax        # specify system service
         movl    $stdout_ID, %ebx        # specify desired device
         movl    $dot, %ecx              # address of output buffer
         movl    $1, %edx                # number of buffer bytes
         int     $0x80                   # enter the Linux kernel
 
         # adjust the loop counter       
         decl    count                   # decrement our counter
         jmp     print_output            # then go back for more
 
 done:
         # output the ascii 'newline' code 
         movl    $sys_write, %eax        # specify system service
         movl    $stdout_ID, %ebx        # specify desired device
         movl    $newln, %ecx            # address of output buffer
         movl    $1, %edx                # number of buffer bytes
         int     $0x80                   # enter the Linux kernel
         ret                             # return to 'main' function
 
         .end                            # assembler can stop here
 
 
 
 Следующая программа показывает использование стека
 Она предлагает вам набрать строку и потом распечатывает ее
 в обратном порядке 
 
 //----------------------------------------------------------------
 //      reverse.s
 //              assemble using:  $ as reverse.s -o reverse.o
 //              and link using:  $ ld reverse.o -o reverse
 //
 //      programmer: ALLAN CRUSE
 //      written on: 03 FEB 2005
 //----------------------------------------------------------------
 
 
         # manifest constants
         .equ    stdin_ID, 0             # input-device (keyboard)
         .equ    stdout_ID, 1            # output-device (screen)
         .equ    sys_exit, 1             # ID-number for 'exit'
         .equ    sys_read, 3             # ID-number for 'read'
         .equ    sys_write, 4            # ID-number for 'write'
 
         .section        .data
 msg1:   .ascii  "\nPlease type a sentence on the line below: \n"
 len1:   .int    . - msg1
 msg2:   .ascii  "\nHere is what you typed in backward order: \n"
 len2:   .int    . - msg2
 msg3:   .ascii  "\n"
 len3:   .int    . - msg3
 inbuf:  .space  80
 maxin:  .int    . - inbuf
 
         .section        .text
 _start: 
         # request user input
 
         movl    $sys_write, %eax        # service ID-number
         movl    $stdout_ID, %ebx        # device ID-number
         leal    msg1, %ecx              # message address
         movl    len1, %edx              # message length
         int     $0x80                   # enter the kernel
 
 
         # receive user input
 
         movl    $sys_read, %eax         # service ID-number
         movl    $stdin_ID, %ebx         # device ID-number
         leal    inbuf, %ecx             # buffer address
         movl    maxin, %edx             # buffer length
         int     $0x80                   # enter the kernel
         movl    %eax, maxin             # save input count
 
 
         # push characters onto stack
 
         leal    inbuf, %esi             # point ESI to buffer
         movl    maxin, %ecx             # setup ECX for count
         decl    %ecx                    # but omit final byte 
 nxch1:  movb    (%esi), %al             # load next character
         pushl   %eax                    # and push onto stack
         incl    %esi                    # advance array-pointer
         loop    nxch1                   # then back for another
                         
         # pop characters from stack
 
         leal    inbuf, %edi             # point EDI to buffer
         movl    maxin, %ecx             # setup ECX for count
         decl    %ecx                    # but onlt final byte
 nxch2:  popl    %eax                    # pop next character
         movb    %al, (%edi)             # and store in buffer
         incl    %edi                    # advance array-pointer
         loop    nxch2                   # then back for another
 
         
         # announce program output               
 
         movl    $sys_write, %eax        # service ID-number
         movl    $stdout_ID, %ebx        # device ID-number
         leal    msg2, %ecx              # message address
         movl    len2, %edx              # message length
         int     $0x80                   # enter the kernel
         
         # display program output
 
         movl    $sys_write, %eax        # service ID-number
         movl    $stdout_ID, %ebx        # device ID-number
         leal    inbuf, %ecx             # message address
         movl    maxin, %edx             # message length
         int     $0x80                   # enter the kernel
 
         # output one blank line 
 
         movl    $sys_write, %eax        # service ID-number
         movl    $stdout_ID, %ebx        # device ID-number
         leal    msg3, %ecx              # message address
         movl    len3, %edx              # message length
         int     $0x80                   # enter the kernel
 
 
         # terminate this program
 
         movl    $1, %eax                # service ID-number
         movl    $0, %ebx                # setup exit-code
         int     $0x80                   # enter the kernel
 
         .globl  _start                  # visible entry-point 
         .end                            # no more to assemble 
 
 
  Следующая программа в качестве параметра берет аргумент
 командной строки , и если это число , выводит все его делители 
 
 //----------------------------------------------------------------
 //      factors.s
 //      gcc factors.s -o factors
 //----------------------------------------------------------------
 
         .section        .data
 n:      .int            0
 i:      .int            0
 ten:    .int            10
 errmsg: .string         "A command-line argument is required"
 report: .string         "\nThe factors of %d are shown below: \n"
 outnum: .string         " %d "
 nxline: .string         "\n"
 
         .section        .text
 main:
         # check for a command-line argument
 
         cmpl            $1, 4(%esp)             # is argc > 1 ?
         jg              argok                   # yes, continue
 
         # if none, print an error-message and exit
 
         pushl           $errmsg
         call            printf
         addl            $4, %esp
         jmp             finis
 
         # convert argument from a digit-string to a number
 argok:
         movl            8(%esp), %ebx           # get argv
         movl            4(%ebx), %esi           # get argv[1]
         movl            $0, n                   # initial n
 
         # conversion: add next digit-value to ten times n
 nxdgt:
         movb            (%esi), %al             # get next digit
         incl            %esi                    # advance pointer
 
         cmpb            $'0', %al               # below '0'? 
         jb              inval                   # yes, not a digit
         cmpb            $'9', %al               # above '9'?
         ja              inval                   # yes, not a digit
         
         andl            $0xF, %eax              # convert ascii to number
         xchgl           %eax, n                 # xchange with prior n
         mull            ten                     # multiply n by ten
         addl            %eax, n                 # add to digit-value
         jmp             nxdgt                   # check for another digit
 inval:
 
         # print explanatory message, showing user's value for n 
 
         pushl           n
         pushl           $report
         call            printf
         addl            $8, %esp
 
         # while-loop: to check for all possible factors of n
 
         movl            $1, i                   # initialize i 
 while:  
         movl            i, %eax                 # get current i 
         cmpl            %eax, n                 # check: i <= n ?
         jl              finis                   # no, then exit 
 
         # see if integer i divides n without any remainder 
         movl            n, %eax
         xorl            %edx, %edx
         divl            i
         orl             %edx, %edx
         jnz             notf
 
         # show this factor of n
         pushl           i
         pushl           $outnum
         call            printf
         addl            $8, %esp
 notf:
         # increment the "trial" factor
         incl            i
         jmp             while
 
 finis:  # print a newline and exit
         pushl           $nxline
         call            printf
         addl            $4, %esp
         ret
 
         .globl          main
         .end
 
 
 Для компиляции следующего примера нужны 2 исходника 
 
         as softmulb.s -o softmulb.o
         as testmulb.s -o testmulb.o
         gcc testmulb.o softmulb.o -o testmulb
 
  Пользователь набирает 2 числа и получает их произведение
 
 //----------------------------------------------------------------
 //      testmulb.s
 //
 //      This interactive program tests our 'softmulb.s' function.
 //
 //----------------------------------------------------------------
 
         .section        .data
 legend: .asciz          "\nThis program computes  x  times  y \n\n"
 format: .asciz          "%d"
 report: .asciz          "OK, %d times %d equals %d \n\n" 
 ask_x:  .asciz          "Please type your x value: "
 ask_y:  .asciz          "Please type your y value: "
 x:      .int            0
 y:      .int            0
 z:      .int            0
 
         .section        .text
 main:   # show the program's legend
         pushl   $legend                 # push function argument
         call    printf                  # call library function
         addl    $4, %esp                # discard the argument
 
         # show prompt #1 and get reply
         pushl   $ask_x                  # push function argument 
         call    printf                  # call library function
         addl    $4, %esp                # discard the argument 
         pushl   $x                      # push argument #2
         pushl   $format                 # push argument #1
         call    scanf                   # call library function
         addl    $8, %esp                # discard two arguments
 
         # show prompt #2 and get reply
         pushl   $ask_y                  # push function argument
         call    printf                  # call library function
         addl    $4, %esp                # discard the argument
         pushl   $y                      # push argument #2
         pushl   $format                 # push argument #1
         call    scanf                   # call library function
         addl    $8, %esp                # discard two arguments
 
         # now compute the product
         movb    x, %al                  # copy multiplicand to AL
         movb    y, %bl                  # copy multiplier to BL
         call    softmulb                # software multiplication
         movw    %ax, z                  # copy product to storage
 
         # report the result, then exit
         pushl   z                       # push argument #4 
         pushl   y                       # push argument #3
         pushl   x                       # push argument #2
         pushl   $report                 # push argument #1
         call    printf                  # call library function
         addl    $16, %esp               # discard all arguments
         ret                             # return to the caller
         
         .global         main            # entry-point is visible
         .end                            # no further statements
 
 //----------------------------------------------------------------
 //      softmulb.s
 //
 //      This file uses shift/rotate instructions to emulate with
 //      software the Pentium's hardware multiplication operation 
 //      for the case when the multiplier is held in register BL. 
 //----------------------------------------------------------------
 
         .section        .text
 softmulb:       
 #
 #       EXPECTS:        AL = multiplicand
 #                       BL = multiplier
 #       RETURNS:        AX = product
 #
                 pushl   %ecx            # preserve register's value
         
                 movl    $9, %ecx        # setup for 8-bit multiplier
                 subb    %ah, %ah        # clear high result register
 nxbit8:         rcrw    $1, %ax         # next multiplier bit to CF
                 jnc     noadd8          # skip addition if bit == 0
                 addb    %bl, %ah        # else add the multiplicand
 noadd8:         loop    nxbit8          # and shift the result
                 subb    %ah, %cl        # set CF if 8-bits exceeded
 
                 popl    %ecx            # restore register's value
                 ret
 
         .globl          softmulb
 
 
 
  Следующий пример - си-inline-версия предыдущего
 Для его компиляции наберите команду : 
 
         g++ multest.cpp softmulb.o -o multest
 
  Она распечатывает произведения всех возможных вариантов чисел ,
 каждое из которых состоит не более чем из 2-х байтов . 
 
 //----------------------------------------------------------------
 //      multest.cpp
 //      compile using:  $ g++ multest.cpp softmulb.o -o multest
 //----------------------------------------------------------------
 
 #include               // needed for printf()
 
 extern void softmulb( void );   // function symbol
 
 unsigned int    a, b, c, d;     // global variables
 
 int main( void )
 {
         printf( "\n--a-- --b--  hardware  software \n" );
         
         // iterate over all possible pairs of 8-bit values 
         int     errors = 0;
         for (a = 0; a < 256; a++)
                 {
                 for (b = 0; b < 256; b++)
                         {
                         printf( " a=%02X  b=%02X ", a, b );
                         asm(" movb a, %al ");
                         asm(" movb b, %bl ");
                         asm(" mulb %bl ");
                         asm(" movw %ax, d ");
                         asm(" movb a, %al ");
                         asm(" movb b, %bl ");
                         asm(" call softmulb ");
                         asm(" movw %ax, c ");
                         printf( "  c=%04X    d=%04X ", c, d );
                         if ( c != d ) ++errors;
                         if ( c == d ) printf( "     ok \n" );
                         else    printf( "<--- error #%d \n", errors );
                         }
                 }
         
         printf( "\n\tNumber of errors = %d \n\n", errors );
 }
 
 
  Следующая программа распечатывает степени числа 2 : 
  
 //----------------------------------------------------------------
 //      powers.s
 //      $ g++ powers.s -o powers
 //----------------------------------------------------------------
 
         .equ            MAX, 15         # total number of lines 
 
         .section        .data
 expon:  .int            0               # stores current exponent
 power:  .int            1               # stores current power
 head:   .string         "\n     Nonnegative Powers of Two   \n\n"
 body:   .string         "        %2d          %6d             \n"
 foot:   .string         "\n"            # newline format-string
 
         .section        .text
 main:   # print the table's title
         pushl           $head           # address of format-string
         call            printf          # call the runtime library
         addl            $4, %esp        # discard the one argument
 
         # program loop, to print table's body
 again:
         # print next line of the table
         pushl           power           # numerical argument #2
         pushl           expon           # numerical argument #1
         pushl           $body           # format-string argument
         call            printf          # call the runtime library
         addl            $12, %esp       # discard the 3 arguments
         # prepare the next exponent and power
         movl            power, %eax     # get the previous power
         addl            %eax, %eax      #  now double its value
         movl            %eax, power     # save this as new power 
         incl            expon           # add one to the exponent 
         # but check loop-exit condition
         cmpl            $MAX, expon     # exponent exceeds maximum?
         jnle            finis           # yes, no more lines to do
         jmp             again           # else display another line
 finis:
         # print a blank bottom line
         pushl           $foot           # format-string argument
         call            printf          # call the runtime library
         addl            $4, %esp        # now discard the argument
 
         ret                             # return control to caller
 
         .global         main            # makes entry-point public
 
 
   В следующей программе пользователь набирает строку ,
  и программа сравнивает ее с шаблоном . 
 
 //----------------------------------------------------------------
 //      password.s
 //      gcc password.s -o password
 //----------------------------------------------------------------
 
         # manifest constants
         .equ    MAXIN, 20
         .equ    FALSE, 0
         .equ    TRUE, ~0
 
         .section        .data
 target: .ascii          "123123\n"
 pwsize: .int            . - target      
 prompt: .asciz          "\nPlease type in the secret password: "
 success:.string         "Correct password -- access granted.\n"
 failure:.string         "Invalid password -- access refused.\n" 
 buffer: .space          MAXIN
 valid:  .byte           FALSE
 
         .section        .text
 #-----------------------------------------------------------------
 main:   call    obtain_password
         call    verify_validity
         call    notify_the_user
         call    grant_or_refuse
         ret
 #-----------------------------------------------------------------
 obtain_password:
 #
 # This function requests the user to type the secret password,
 # then stores the user's response in a character-array buffer.
 #
         call    request_input
         call    receive_reply
         ret
 #-----------------------------------------------------------------
 verify_validity:
 #
 # This procedure compares the array of input-characters typed
 # by the user with the 'target' array which holds the correct
 # password.  The 'valid' flag does not remain TRUE unless all
 # of their ascii codes agree.
 # 
         xorl    %esi, %esi              # initial array index
         movl    $TRUE, valid            # starting assumption
 next:   movb    buffer(%esi), %al       # get next input-char
         cmpb    target(%esi), %al       # it matches target?
         je      incr                    # yes, advance index
         movl    $FALSE, valid           # else flag adjusted
 incr:   incl    %esi                    # advance array index
         cmpl    %esi, pwsize            # end-of-array yet?
         jg      next    # <-- bug fixed # no, check another
         ret
 #-----------------------------------------------------------------
 #-----------------------------------------------------------------
 request_input:
 #
 # This function prints an initial message which asks the user 
 # to type in the secret password.  
 #
         push    $prompt                 # argument to function
         call    printf                  # call runtime library
         addl    $4, %esp                # discard the argument
         ret
 #-----------------------------------------------------------------
 receive_reply:
 #
 # This function reads in the characters that are typed by the
 # user and returns (when the user hits the  key) with
 # the ascii character-codes stored in an array named 'buffer'.
 #
         push    stdin                   # argument #3
         push    $MAXIN                  # argument #2
         push    $buffer                 # argument #1
         call    fgets                   # call runtime library
         addl    $12, %esp               # discard arguments
         ret
 #-----------------------------------------------------------------
 notify_the_user:
 #
 # This procedure prints a diagonistic message, based on the 
 # value (TRUE or FALSE) it finds stored in the 'valid' flag.
 #
         movl    $success, %eax          # setup message-address
         cmpl    $TRUE, valid            # is it the proper one?
         je      msgok                   # yes, proceed to print
         movl    $failure, %eax          # no, use other message
 msgok:  push    %eax                    # function's argument
         call    puts                    # call runtime library
         addl    $4, %esp                # discard the argument
         ret
 #-----------------------------------------------------------------
 grant_or_refuse:
 #
 # This procedure checks the value of the 'valid' flag and 
 # leaves this function in case 'valid' is TRUE; otherwise
 # it continues executing here in an infinite loop so that
 # the user is thus prevented from making further progress.
 #
         cmpl    $TRUE, valid            # was password valid?
         je      return                  # yes, then ok to exit
 freeze: jmp     freeze                  # else continue here  
 return: ret                             
 #-----------------------------------------------------------------
         .globl          main
         .end
 
 
  Следующий пример распечатывает имя текущего пользователя
 
 //----------------------------------------------------------------
 //      mywhoami.s
 //      
 //      gcc mywhoami.s -o mywhoami
 //      
 //      This program illustrates the use of string-manipulation
 //      instructions: (1) to search for an environment variable 
 //      and (2) to copy its value into a local buffer area from
 //      which it can then be displayed.  The algorithm which is
 //      used here relies on the fact that Linux systems provide
 //      for three arguments to the function 'main()':
 //
 //         int main( int argc, char *argv[], char *envp[] );
 //
 //      Here the third argument 'envp' is a pointer to an array
 //      of character pointers (known as the 'environment list')
 //      in which each of the strings has the form 'name=value'.
 //      Among these we search here for the one in which 'USER=' 
 //      appears: its value gives the current effective user id.
 //----------------------------------------------------------------
 
         .section        .data
 target: .ascii          "USER="         # variable to search for
 tgtlen: .int            . - target      # length for target name
 user:   .zero           80              # for storing a username
 size:   .int            0               # for length of username
 fmt:    .asciz          "%s\n"          # for 'printf()' format
 
 
         .section        .text
 main:   
         # setup local frame-pointer (to access 'envp' argument)
 
         pushl   %ebp                    # preserve caller's frame
         movl    %esp, %ebp              # setup local stack frame
 
         # get 'envp' and search the list for the 'USER=' string
 
         movl    16(%ebp), %ebx          # EBX points to the array
         xorl    %edx, %edx              # use EDX for array-index
         cld                             # do 'forward' processing
 nxvar:
         # check for end-of-array (i.e., a null string)
 
         movl    (%ebx, %edx, 4), %edi   # point EDI to next string
         cmpb    $0, (%edi)              # check: is a NULL string?
         je      finis                   # yes, search unsuccessful 
 
         # compare the string's variable-name to our target name
 
         movl    $target, %esi           # point ESI to our target
         movl    tgtlen, %ecx            # setup length for target
         rep     cmpsb                   # check: do strings agree?
         je      found                   # yes, search succeessful! 
 
         # if they don't match, increment array-index and try again
 
         inc     %edx                    # else advance array-index
         jmp     nxvar                   # and examine new variable
 
 found:  # determine the length of the environment variable's value
 
         movl    %edi, %esi              # save start-address in ESI
         xorb    %al, %al                # setup EAX with null value 
         movl    $0xC0000000, %ecx       # address for top of memory
         subl    %edi, %ecx              # less address to scan from
         repne   scasb                   # scan string for null byte
         movl    %edi, size              # ok, store the end address
         subl    %esi, size              #  minus the begin address
 
         # now copy the variable's value to our local buffer
 
         movl    $user, %edi             # point EDI to local buffer
         movl    size, %ecx              # number of bytes to copy
         rep     movsb                   # perform the string-copy       
 
         # print the current effective user id 
 
         pushl   $user                   # printf argument #2
         pushl   $fmt                    # printf argument #1
         call    printf                  # call to runtime library
         addl    $8, %esp                # discard the arguments
 
         # restore caller stack-frame and exit
 finis:
         mov     %ebp, %esp              # insure stack is balanced
         popl    %ebp                    # restore caller's frame
         ret                             # and return from 'main()'
 
         .globl  main                    # make entry-point public
 
 
 
   Следующая программа распечатывает свой собственный стек 
 
 //-------------------------------------------------------------------
 //      seestack.cpp
 //
 //      g++ seestack.cpp -o seestack
 //
 //-------------------------------------------------------------------
 
 #include       // for printf() 
 
 #define KERNEL_BASE_ADDRESS 0xC0000000
 
 unsigned long tos, ebp, len;
 unsigned char *where = (unsigned char *)KERNEL_BASE_ADDRESS;    
 unsigned char ch;
 int     i, j;
 
 
 int main( int argc, char **argv, char **envp )
 {
         // insert statement that copies %esp-value to a variable
         asm(" movl %esp, tos ");
         asm(" movl %ebp, ebp ");
 
         // calculate the size of the active stack area (in bytes)
         len = KERNEL_BASE_ADDRESS - tos;        
 
         // loop to display the contents of the active stack area
         for (i = 0; i < len; i += 16)
                 {
                 where -= 16;
                 printf( "\n%08X: ", where );
                 for (j = 0; j < 16; j++) printf( "%02X ", where[j] );
                 for (j = 0; j < 16; j++)
                         {
                         ch = where[ j ];
                         if (( ch < 0x20 )||( ch > 0x7E )) ch = '.';
                         printf( "%c", ch );
                         }
                 }
         printf( "\n" );
         printf( "\n  ebp=%08X  ", ebp );        
         printf( "\n  esp=%08X  ", tos );        
         printf( "\n&argc=%08X  argc=%08X ", &argc, argc );
         printf( "\n&argv=%08X  argv=%08X ", &argv, argv );
         printf( "\n&envp=%08X  envp=%08X ", &envp, envp );
         printf( "\n\n" );
 }
 
 
  Следующая программа по набранной дате определяет ее
 день недели 
 
 //----------------------------------------------------------------
 //      xmas.s
 //
 //      gcc xmas.s -o xmas
 //      
 //----------------------------------------------------------------
 
         .section        .data
 param:  .int    2005                    # command-line parameter
 radix:  .int    10                      # base of decimal system
 seven:  .int    7                       # number of days-per-week
 four:   .int    4                       # frequency of leap-years
 years:  .int    0                       # counts years since 1900
 leaps:  .int    0                       # count of the leap-years
 days:   .int    0                       # elapsed days since 1900
 theday: .int    0                       # weekday number (0=Tues)
 daylst: .ascii  "TueWedThuFriSatSunMon" # names of days in a week
 report: .asciz  "xxx, Dec 25 \n"        # message text to display
 errmsg: .asciz  "Year cannot be before 1900\n"  # error-message
 
         .section        .text
 main:   call    obtain_input            # get the designated year
         call    process_data            # calculate Christmas day  
         call    print_output            # display results to user
         ret                             # return control to Linux 
 
 print_output:
 
         # copy day's name into report-string
 
         xorl    %edi, %edi              # array-index for dst
         imul    $3, theday, %esi        # array-index for src
         movl    $3, %ecx                # chars to be copied
 nxmv:   movb    daylst(%esi), %al       # fetch source char
         movb    %al, report(%edi)       # store dest'n char
         incl    %esi                    # advance src index
         incl    %edi                    # advance dst index
         loop    nxmv                    # copy rest of chars
 
         # print report on day when Christmas occurs
 
         pushl   $report                 # push message address 
         call    printf                  # call runtime library
         addl    $4, %esp                # discard the argument
         ret
 
 process_data:
 
         # compute the number of years since 1900
 
         movl    param, %eax             # get the parameter value
         subl    $1900, %eax             # subtract the value 1900
         movl    %eax, years             # store as count of years
 
         # compute the number of leap-years since 1900
 
         movl    years, %eax             # get the number of years               
         xorl    %edx, %edx              # extend dividend to long
         divl    four                    # perform unsigned divide  
         movl    %eax, leaps             # quotient counts leapyrs
         
         # compute the total number of days since 1900   
 
         imul    $365, years, %eax       # years * days-per-year
         addl    leaps, %eax             # plus the "extra" days 
         movl    %eax, days              # gives days since 1900
 
         # divide number of days by seven
 
         movl    days, %eax              # get the number of days
         xorl    %edx, %edx              # extended as a dividend 
         divl    seven                   # divide by days-in-week
         movl    %edx, theday            # remainder is day-of-week
         ret                             # return to caller
 
 
 obtain_input:
 
         movl    12(%ebp), %eax          # get number of arguments
         cmpl    $1, %eax                # check: does argc == 1?
         je      argx                    # yes, use a default year
 
         movl    16(%ebp), %ebx          # get argv[] base-address
         movl    $1, %edx                # setup 1 as array-index 
         movl    (%ebx,%edx,4), %esi     # get pointer to argument
         call    ascii_to_int            # convert ascii to number
         movl    %eax, param             # save the argument-value       
                 
         cmpl    $1900, param            # check: 1900 > param ?
         jge     argx                    # no, parameter accepted
         
         pushl   $errmsg                 # error-message address
         call    printf                  # call runtime library
         addl    $4, %esp                # discard the argument
 
         pushl   $1                      # exit-function argument
         call    exit                    # call runtime library
 
 argx:   ret                             # return to the caller
 
 
 
 ascii_to_int:
 #
 # This procedure converts a string of decimal digits, located at 
 # the memory-address found in register %esi, into its numerical
 # value, and returns that value in register %eax.  Upon return,
 # register %esi points to the first non-digit that occurs in the 
 # string.  The contents of other general registers is unchanged.
 #
         pushl   %ecx                    # preserve work registers 
         pushl   %edx
         
         xorl    %eax, %eax              # initialize accumulator
 nxdgt:  
         movb    (%esi), %cl             # fetch next ascii-code
         cmpb    $'0', %cl               # is it below '0'?
         jb      cvtxx                   # yes, not a digit              
         cmpb    $'9', %cl               # is it above '9'?
         ja      cvtxx                   # yes, not a digit              
 
         andl    $0xF, %ecx              # convert digit to integer
         mull    radix                   # ten times previous total
         addl    %ecx, %eax              # plus the newest integer
         incl    %esi                    # advance source pointer
         jmp     nxdgt                   # check for more digits
 cvtxx:
         popl    %edx                    # restore saved registers
         popl    %ecx
         ret
 
         .globl  main                    # make entry-point public
         .end
 
 
 
 
   Следующая программа генерит новый текстовой файл 
 
 //----------------------------------------------------------------
 //      out2file.s
 //
 //          assemble with:  $ as out2file.s -o out2file.o
 //          and link with:  $ ld out2file.o -o out2file
 //
 //----------------------------------------------------------------
 
         # manifest constants
         .equ    STDERR, 2
         .equ    sys_EXIT, 1
         .equ    sys_WRITE, 4
         .equ    sys_OPEN, 5
         .equ    sys_CLOSE, 6
         .equ    O_CREAT, 0100
         .equ    O_TRUNC, 01000
         .equ    O_WRONLY, 01
         .equ    S_ACCESS, 00600
 
 
         .section        .text
 #-----------------------------------------------------------------
 _start: call    create_file
         call    output_data
         call    commit_file
         call    notify_user
         call    termination
 #-----------------------------------------------------------------
 
 
         .section        .data
 #-----------------------------------------------------------------
 flags:          .int    O_CREAT | O_WRONLY | O_TRUNC 
 access:         .int    S_ACCESS        # define file-permissions
 handle:         .int    -1              # used as file identifier 
 filename:       .asciz  "mycookie.dat"  # name for file to create
 #-----------------------------------------------------------------
 fileinfo:       .ascii  "Computer Science 210\n"
                 .ascii  "Spring 2005\n"
                 .ascii  "University of San Francisco\n" 
                 .equ    infosize, . - fileinfo
 #-----------------------------------------------------------------
 
 
         .section        .text
 #-----------------------------------------------------------------
 create_file:    movl    $sys_OPEN, %eax         # service-number
                 movl    $filename, %ebx         # address of name
                 movl    flags, %ecx             # mode-settings 
                 movl    access, %edx            # file-permissions  
                 int     $0x80                   # enter the kernel 
                 movl    %eax, handle            # save return-code
 
                 or      %eax, %eax              # check: success?
                 jns     creatx                  # yes, finished
 
                 pushl   $size05                 # message-length 
                 pushl   $fail05                 # message-address
                 pushl   $exitmsg                # function-address
 
 creatx:         ret                             # transfer control
 #-----------------------------------------------------------------
 fail05:         .ascii  "Could not create file.\n\n"
                 .equ    size05, . - fail05
 #-----------------------------------------------------------------
 output_data:    movl    $sys_WRITE, %eax        # service-number
                 movl    handle, %ebx            # specify the file
                 movl    $fileinfo, %ecx         # buffer's address
                 movl    $infosize, %edx         # buffer's length
                 int     $0x80                   # enter the kernel
 
                 or      %eax, %eax              # check: success?
                 jns     writex                  # yes, finished
 
                 pushl   $size04                 # message-length
                 pushl   $fail04                 # message-address
                 pushl   $exitmsg                # function-address
 
 writex:         ret                             # transfer control
 #-----------------------------------------------------------------
 fail04:         .ascii  "Could not write to file.\n\n"
                 .equ    size04, . - fail04
 #-----------------------------------------------------------------
 commit_file:    movl    $sys_CLOSE, %eax        # service-number
                 movl    handle, %ebx            # specify the file
                 int     $0x80                   # enter the kernel
 
                 or      %eax, %eax              # check: success?
                 jns     closex                  # yes, finished
 
                 pushl   $size06                 # message-length
                 pushl   $fail06                 # message-address
                 pushl   $exitmsg                # function-address
 
 closex:         ret                             # transfer control
 #-----------------------------------------------------------------
 fail06:         .ascii  "Could not close file.\n\n"
                 .equ    size06, . - fail06
 #-----------------------------------------------------------------
 #-----------------------------------------------------------------
 notify_user:    movl    $sys_WRITE, %eax        # service-number
                 movl    $STDERR, %ebx           # device-handle
                 movl    $message, %ecx          # buffer's address
                 movl    $msgsize, %edx          # buffer's length
                 int     $0x80                   # enter the kernel
                 ret                             # transfer control
 #-----------------------------------------------------------------
 message:        .ascii  "\nNew file successfully created\n\n"
                 .equ    msgsize, . - message
 #-----------------------------------------------------------------
 #
 # This is our common error-handling routine, which only executes
 # in case one of our kernel system-calls returns a failure-code.
 # Upon entry, this routine assumes that the address of a message
 # (and the length of that message) will be found atop the stack.  
 #
 #-----------------------------------------------------------------
 exitmsg:        # first show the name of this program (so a user
                 # will know the source of the message to follow)
         
                 movl    $sys_WRITE, %eax        # service-number
                 movl    $STDERR, %ebx           # device-handle
                 movl    $exitfmt, %ecx          # string's address
                 movl    $fmtsize, %edx          # string's length
                 int     $0x80                   # enter the kernel
         
                 # then show the diagnostic error-message (whose
                 # address and length are popped from the stack)
         
                 movl    $sys_WRITE, %eax        # service-number
                 movl    $STDERR, %ebx           # device-handle
                 popl    %ecx                    # string's address 
                 popl    %edx                    # string's length
                 int     $0x80                   # enter the kernel
 
                 # finally, fall through to the program-exit code
 termination:
                 movl    $sys_EXIT, %eax         # service-number
                 xorl    %ebx, %ebx              # return-code
                 int     $0x80                   # enter the kernel
 #-----------------------------------------------------------------
 exitfmt:        .ascii  "\nout2file: "
                 .equ    fmtsize, . - exitfmt
 #-----------------------------------------------------------------
                 .globl  _start
                 .end
 
 
 
   Следующая программа читает и выводит на экран текстовой файл 
 
 //----------------------------------------------------------------
 //      readdemo.s
 //
 //          assemble using:  $ as readdemo.s -o readdemo.o
 //          and link using:  $ ld readdemo.o -o readdemo
 //----------------------------------------------------------------
 
         # manifest constants
         .equ    STDOUT, 1
         .equ    SEEK_SET, 0
         .equ    SEEK_END, 2
         .equ    O_RDONLY, 0
         .equ    sys_EXIT, 1
         .equ    sys_READ, 3
         .equ    sys_WRITE, 4
         .equ    sys_OPEN, 5
         .equ    sys_LSEEK, 19
         .equ    sys_BRK, 45 
 
         .data
 filnam: .asciz  "mycookie.dat"
 handle: .int    -1
 filesz: .int    -1
 bufadr: .int    -1              
 
         .text
 #-----------------------------------------------------------------
 _start: call    open_file_ro
         call    get_filesize
         call    allocate_ram
         call    read_in_file
         call    display_info
         call    exit_to_bash
 #-----------------------------------------------------------------
 open_file_ro:   
         movl    $sys_OPEN, %eax
         movl    $filnam, %ebx
         movl    $O_RDONLY, %ecx
         movl    $0, %edx
         int     $0x80
         movl    %eax, handle
 
         orl     %eax, %eax
         jns     openx
 
         pushl   $mlen5
         pushl   $fail5
         pushl   $exitmsg
 
 openx:  ret
 #-----------------------------------------------------------------
 fail5:  .ascii  "Could not open the file \n"
         .equ    mlen5, . - fail5
 #-----------------------------------------------------------------
 get_filesize:
         movl    $sys_LSEEK, %eax
         movl    handle, %ebx
         xorl    %ecx, %ecx
         movl    $SEEK_END, %edx
         int     $0x80
         movl    %eax, filesz
 
         orl     %eax, %eax
         js      skerr
 
         movl    $sys_LSEEK, %eax
         movl    handle, %ebx
         xorl    %ecx, %ecx
         movl    $SEEK_SET, %edx
         int     $0x80
 
         orl     %eax, %eax
         jns     seekx
 
 skerr:  pushl   $mlen19
         pushl   $fail19
         pushl   $exitmsg
 
 seekx:  ret
 #-----------------------------------------------------------------
 fail19: .ascii  "Could not do lseek. \n"
         .equ    mlen19, . - fail19
 #-----------------------------------------------------------------
 allocate_ram:
         movl    $sys_BRK, %eax
         xorl    %ebx, %ebx              # we want current 'brk'
         int     $0x80
         movl    %eax, bufadr
 
         movl    $sys_BRK, %eax
         movl    bufadr, %ebx
         addl    filesz, %ebx            # here we set new 'brk'
         int     $0x80
 
         cmp     $-1, %eax
         jne     alocx
 
         pushl   $mlen45
         pushl   $fail45
         pushl   $exitmsg
 
 alocx:  ret
 #-----------------------------------------------------------------
 fail45: .ascii  "Could not allocate memory. \n"
         .equ    mlen45, . - fail45
 #-----------------------------------------------------------------
 read_in_file:
         movl    $sys_READ, %eax
         movl    handle, %ebx
         movl    bufadr, %ecx
         movl    filesz, %edx
         int     $0x80
         
         orl     %eax, %eax
         jns     readx
 
         pushl   $mlen3
         pushl   $fail3
         pushl   $exitmsg
 
 readx:  ret
 #-----------------------------------------------------------------
 fail3:  .ascii  "Could not read from file. \n"
         .equ    mlen3, . - fail3
 #-----------------------------------------------------------------
 display_info:
         movl    $sys_WRITE, %eax
         movl    $STDOUT, %ebx
         movl    bufadr, %ecx
         movl    filesz, %edx
         int     $0x80
         ret
 #-----------------------------------------------------------------
 exitmsg:
         movl    $sys_WRITE, %eax
         movl    $STDOUT, %ebx
         movl    $idmsg, %ecx
         movl    $idlen, %edx
         int     $0x80
 
         movl    $sys_WRITE, %eax
         movl    $STDOUT, %ebx
         popl    %ecx
         popl    %edx
         int     $0x80
 
 exit_to_bash:
         movl    $sys_EXIT, %eax
         movl    $0, %ebx
         int     $0x80
 #-----------------------------------------------------------------
 idmsg:  .ascii  "readdemo: "
         .equ    idlen, . - idmsg
 #-----------------------------------------------------------------
         .globl  _start
         .end
 
 
 
 
  Следующий пример показывает использование 'fork' system-call 
 
 //----------------------------------------------------------------
 //      tryfork.s       
 //
 //      This program directly invokes the 'fork' system-call in
 //      order to create a 'child' process; the 'parent' process
 //      then issues the 'waitpid' system-call, causing it to be
 //      'blocked' until the child-process has terminated.  Both
 //      processes display a small number of their topmost stack
 //      elements, for comparison purposes.  
 //
 //           assemble using:  $ as tryfork.s -o tryfork.o
 //           and link using:  $ ld tryfork.o -o tryfork
 //----------------------------------------------------------------
 
         # manifest constants
         .equ    sys_EXIT, 1
         .equ    sys_FORK, 2
         .equ    sys_WRITE, 4
         .equ    sys_WAITPID, 7
         .equ    STDOUT, 2
 
 
         .section        .data
 pid:    .int    -1                      # holds the process-ID
 hexlst: .ascii  "0123456789ABCDEF"      # list of hex numerals
 status: .int    0                       # status for 'waitpid'
 pfini:  .ascii  "\nparent is finished.\n\n"
         .equ    pfsz, . - pfini
 cfini:  .ascii  "\nchild is finished.\n\n"
         .equ    cfsz, . - pfini
 
 
         .section        .text
 _start: 
         # issue the 'fork' system-call
         movl    $sys_FORK, %eax         # service ID-number
         int     $0x80                   # enter the kernel
         movl    %eax, pid               # save return-value
 
         # branch to different threads
         orl     %eax, %eax              # was zero returned?
         jnz     parent                  # no, it's the parent
         jmp     child                   # else it's the child
 
 
 terminate:
         # issue the 'exit' system-call
         movl    $sys_EXIT, %eax         # service ID-number
         movl    $0, %ebx                # process exit-code
         int     $0x80                   # enter the kernel
 
 
 #-----------------------------------------------------------------
 parent: 
         # go to sleep until the child-process has terminated
         movl    $sys_WAITPID, %eax      # service ID-number
         movl    pid, %ebx               # process to wait for
         movl    $status, %ecx           # address for status
         movl    $0, %edx                # service options
         int     $0x80                   # enter the kernel
 
         # display the topmost stack-elements
         call    show_stack              # display stack items
 
         # print a termination notification
         movl    $sys_WRITE, %eax        # service ID-number
         movl    $STDOUT, %ebx           # device-handle
         movl    $pfini, %ecx            # message address
         movl    $pfsz, %edx             # message length
         int     $0x80                   # enter the kernel
         jmp     terminate               # goto exit-routine
 #-----------------------------------------------------------------
 child:
         # display the topmost stack-elements
         call    show_stack              # display stack items
 
         # print a termination notification
         movl    $sys_WRITE, %eax        # service ID-number
         movl    $STDOUT, %ebx           # device-handle
         movl    $cfini, %ecx            # message address
         movl    $cfsz, %edx             # message length
         int     $0x80                   # enter the kernel
         jmp     terminate               # goto exit-routine
 #-----------------------------------------------------------------
 show_stack:
 #
 # This procedure is called by both of the processes, to display
 # a few of the topmost elements on their stacks.  (It allocates
 # some storage-space (128 bytes) on their respective stacks for 
 # its temporary use as a buffer-area, but releases that storage
 # before exiting back to the calling procedure.)  
 #
         push    %ebp                    # save frame-pointer
         movl    %esp, %ebp              # setup our own frame
         subl    $128, %esp              # allocate buffer area
         pushal                          # preserve registers
 
         # prepare registers for string-processing
         leal    -128(%ebp), %edi        # point EDI to buffer-area
         movl    %ebp, %esi              # point ESI to stack-frame
         cld                             # use forward processing
 
         # write stack-frame's address to buffer-area
         movl    %esi, %eax              # copy address into EAX
         call    eaxout                  # write EAX as hex-value
         movb    $':', %al               # then append a colon
         stosb                           #  following the address
 
         # write topmost stack elements to buffer-area
         movl    $7, %ecx                # number of stack-items
 nxdwd:  
         movb    $' ', %al               # prepend a blank space 
         stosb                           #  before next hex-value
         lodsl                           # fetch next stack-item
         call    eaxout                  # write item as hex-value
         loop    nxdwd                   # process remaining items
 
         # display the sequence of stack elements
         movl    $sys_WRITE, %eax        # service ID-number
         movl    $STDOUT, %ebx           # device-handle
         leal    -128(%ebp), %ecx        # message address
         movl    %edi, %edx              # end-of-message
         subl    %ecx, %edx              # minus its start
         int     $0x80                   # enter the kernel      
 
         popal                           # restore registers
         movl    %ebp, %esp              # discard buffer area
         pop     %ebp                    # recover frame-pointer
         ret                             # return to caller
 
 #-----------------------------------------------------------------
 eaxout:
 #
 # This helper-function converts the value found in register EAX
 # to its representation as a hexadecimal digit-string at (EDI),
 # and advances the address in EDI to the next buffer position.
 #
         pushl   %eax                    # preserve work registers
         pushl   %ebx
         pushl   %ecx
         pushl   %edx
 
         movl    %eax, %edx              # copy EAX value to EDX
         movl    $hexlst, %ebx           # point EBX to digit-list
         movl    $8, %ecx                # the number of nybbles
 nxnyb:  roll    $4, %edx                # next nybble into DL
         movb    %dl, %al                # copy nybble into AL
         andb    $0xF, %al               # isolate the nybble
         xlat                            # convert nybble to hex
         stosb                           # store digit to buffer
         loop    nxnyb                   # process rest of nybbles
 
         popl    %edx                    # restore saved registers
         popl    %ecx
         popl    %ebx
         popl    %eax
         ret                             # return to caller
 #-----------------------------------------------------------------
         .globl  _start                  # make symbol visible
         .end                            
 
 
 
  
  В следующем примере показана работа с сигналами ,
 где реализован вызов  sys_sigaction
 
 //----------------------------------------------------------------
 //      sigdemo1.s
 //
 //          assemble using:  $ as sigdemo1.s -o sigdemo1.o
 //          then link with:  $ ld sigdemo1.o -o sigdemo1
 //
 //----------------------------------------------------------------
 
         .equ    SIGSEGV, 11             # ID-number of the signal 
         .equ    sys_exit, 1             # system-call's ID-number
         .equ    sys_sigaction, 67       # system-call's ID-number
         .equ    SA_SIGINFO, 0x00000004  # bitmask for flag value 
 
         .section        .data
 sa:     # this labels the beginning of our 'struct sigaction' object
 sa_handler:     .long   action          # __sighandler_t   sa_handler
 sa_mask:        .long   0               # sigset_t         sa_mask
 sa_flags:       .long   SA_SIGINFO      # unsigned long    sa_flags
 sa_restorer:    .long   0               # __sig_restore_t  sa_restorer
 
         .section        .text
 action: # this is the entry-point to our signal-handling function       
         # exit( 1 ) 
         movl    $sys_exit, %eax         # system-call ID-number
         movl    $1, %ebx                # value for exit-status
         int     $0x80                   # enter the Linux kernel
 
 subrtn: # try writing 0 to the supplied memory-address 
         movl    4(%esp), %edi           # get function-argument
         movb    $0, (%edi)              # store 0 into address
         ret                             # return to the caller
 
 _start: # sigaction( SIGSEGV, &mysa, NULL );    
         movl    $sys_sigaction, %eax    # system-call ID-number
         movl    $SIGSEGV, %ebx          # ID-number for signal
         movl    $sa, %ecx               # address of sa struct
         movl    $0, %edx                # null-pointer
         int     $0x80                   # enter the Linux kernel
 
         # subrtn( NULL );
         pushl   $0                      # push function argument
         call    subrtn                  # call the function
         addl    $4, %esp                # discard the argument
 
         # exit( 0 );
         movl    $sys_exit, %eax         # system-call ID-number
         movl    $0, %ebx                # value for exit-status
         int     $0x80                   # enter the Linux kernel
 
         .global _start                  # program-entry is public
         .end                            # no instructions follow
 
 
 
  
  Следующий пример распечатывает факториал первых 12 целых чисел
 с использованием рекурсивной функции на ассемблере 
 
 //-------------------------------------------------------------------
 //      fact.cpp
 //
 //      compile using:  $ g++ fact.cpp fact.s -o fact
 //-------------------------------------------------------------------
 
 #include       // for printf() 
 
 #define NMAX    12      // maximum function-argument
 
 extern "C" unsigned int fact( unsigned int n );
 
 int main( int argc, char **argv )
 {
         printf( "\n\t\t         N         N!         " );
         printf( "\n\t\t------------------------------" );
         for (int n = 0; n <= NMAX; n++)
                 printf( "\n\t\t%10u %10u ", n, fact(n) );       
         printf( "\n\t\t------------------------------" );
         printf( "\n\n" );
 }
 
 //----------------------------------------------------------------
 //      fact.s
 //
 //      Here is an implementation in assembly language for the
 //      famous factorial function, defined recursively for any
 //      nonnegative integer  n  by this two-part rule:
 //      
 //              unsigned int fact( unsigned int n )
 //              {
 //                      if ( n == 0 ) return 1;
 //                      else return  n*fact( n-1 );
 //              }
 //
 //----------------------------------------------------------------
 
         .text
 fact:   # setup access to the stack-frame 
         pushl   %ebp            # preserve former frame-pointer
         movl    %esp, %ebp      # establish access to new frame
 
         # test for branching to the two-part rule
         cmpl    $0, 8(%ebp)     # function argument equals zero?
         jne     recur           # no, then do the recursive case
 
         # here we handle the base case
         movl    $1, %eax        # else setup one as return-value
         jmp     factx           # and exit to the calling routine
 
 recur:  # here we handle the recursion case     
         push    %edx            # preserve caller's value in EDX 
 
         # prepare function-argument for recursive call
         movl    8(%ebp), %eax   # copy current function-argument 
         decl    %eax            # decrement argument for call
  
         # this is the recursive call to obtain:  fact( n-1 )
         pushl   %eax            # push the new argument  n-1
         call    fact            # call the factorial function
         addl    $4, %esp        # discard argument from stack
         
         # now the function-value in EAX gets multiplied by  n   
         mull    8(%ebp)         # multiplies 'fact( n-1 )' by n
         popl    %edx            # restore caller's value to EDX
 factx:
         popl    %ebp            # restore former frame-pointer
         ret                     # and return conrol to caller
 
         .global fact            # entry-point is a public symbol
         .end                    # no further statements follow 
 
 
 
  Следующая утилита наполняет экран символами , давая возможность
 набирать свои . Выход - Ctrl-C :
 //	    assemble using:  $ as alphabet.s -o alphabet.o
 //	    and link using:  $ ld alphabet.o -o alphabet
 
 	.equ	sys_write, 4		# service ID-number
 	.equ	dev_stdout, 1		# device ID-number
 
 
 	.data
 outln:	.space	2000			# no. of screen cells
 total:	.long	26			# no. of alphabet letters
 count:	.long	0			# current loop iteration 
 
 
 	.text
 _start:
 	call	do_fill			# fill the output buffer 
 	call	do_draw			# write buffer to screen
 	call	do_wait			# perform a brief delay
 	call	do_incr			# increment cycle count
 	jmp	_start			# repeat loop forever
 
 do_fill:
 	# fill buffer with copies of ascii character-code
 	pushal
 	movl	count, %eax		# get iteration counter
 	addl	$'A', %eax		# add ascii-code for 'A'
 	lea	outln, %edi		# point ES:EDI to buffer
 	cld				# do forward processing
 	movl	$2000, %ecx		# setup character count
 	rep	stosb			# fill the entire buffer
 	popal
 	ret
 	
 do_draw:
 	# write contents of buffer to standard output device
 	pushal
 	movl	$sys_write, %eax	# service ID-number
 	movl	$dev_stdout, %ebx	# device ID-number
 	lea	outln, %ecx		# buffer offset
 	movl	$2000, %edx		# buffer length
 	int	$0x80			# enter the kernel
 	popal
 	ret
 
 do_wait:
 	# do a timed delay of approximately 500-million cpu-cycles 
 	pushal	
 	rdtsc				# read timestamp counter
 	addl	$500000000, %eax	# increment the quadword 
 	adcl	$0x0000000, %edx	# counter by 500-million
 	movl	%eax, %ebx		# copy bits 31..0 to EBX
 	movl	%edx, %ecx		# and bits 63..32 to ECX
 .L2:	rdtsc				# read timestamp again
 	subl	%ebx, %eax		# subtract saved quadword
 	sbbl	%ecx, %edx		#  from latest timestamp
 	js	.L2			# negative? read it again
 	popal
 	ret
 
 do_incr:
 	# advance the cycle-count by 1 (with wrapping at 26)
 	pushal
 	incl	count			# add 1 to the count
 	movl	count, %eax		# get new count value
 	xorl	%edx, %edx		# extend to quadword
 	divl	total			# divide by letter-count
 	movl	%edx, count		# remainder is new count
 	popal
 	ret
 
 	.global	_start
 
   Следующая программа выводит системную дату :
 
 //		assemble using:  $ as showdate.s -o showdate.o
 //		and link using:  $ ld showdate.o -o showdate
 	
 	.equ	sys_EXIT, 1		# ID-number for 'exit'
 	.equ	sys_WRITE, 4		# ID-number for 'write'
 	.equ	sys_IOPL, 110		# ID-number for 'iopl'
 	.equ	dev_STDOUT, 1		# ID-number for STDOUT
 
 
 	.section	.data
 dayname: .ascii	"    Sun Mon Tue Wed Thu Fri Sat "
 monname: .ascii	"    Jan Feb Mar Apr May Jun Jul "
 	 .ascii	"Aug Sep Oct Nov Dec "  
 message: .ascii	"                            \n\r"
 len:	.int	. - message		# count of characters
 
 
 	.section	.text
 _start:	# adjust this task's IO Privilege-Level	
 	movl	$sys_IOPL, %eax		# system-call ID-number
 	movl	$3, %ebx		# new value for IOPL
 	int	$0x80			# enter the kernel
 
 	# read the current day-of-the-week 		
 	movb	$6, %al			# select register-number
 	out	%al, $0x70		#   to be accessed
 	in	$0x71, %al		# read selected register
 
 	# use day-number to lookup weekday name
 	movzx	%al, %eax		# extend byte to dword
 	movl	dayname(,%eax,4), %edx	# lookup weekday's name
 	mov	%edx, message		# insert name in message
 
 	# read the current day-of-the-month
 	movb	$7, %al			# select register-number
 	out	%al, $0x70		#   to be accessed
 	in	$0x71, %al		# read selected register
 
 	# convert BCD value to decimal-string	
 	mov	%al, %ah		# copy BCD value to AH
 	rol	$4, %al			# exchange the nybbles
 	and	$0x0F0F, %ax		# mask isolates nybbles
 	or	$0x3030, %ax		# convert to numerals
 	mov	%ax, message+4		# insert into message
 
 	# read current month-of-the-year
 	movb	$8, %al			# select register-number
 	out	%al, $0x70		#   to be accessed
 	in	$0x71, %al		# read selected register
 	
 	# use month-number to lookup month's name
 	movzx	%al, %eax		# extend byte to dword
 	movl	monname(,%eax,4), %edx	# lookup name for month
 	mov	%edx, message+7		# insert name in message
 
 	# read the current year	
 	movb	$9, %al			# select register-number
 	out	%al, $0x70		#   to be accessed
 	in	$0x71, %al		# read selected register
 	
 	# convert BCD value to decimal-string	
 	mov	%al, %ah		# copy BCD value to AH
 	rol	$4, %al			# exchange the nybbles
 	and	$0x0F0F, %eax		# mask isolates nybbles
 	rol	$16, %eax		# swap hiword and loword
 	or	$0x30303032, %eax	# convert into numerals
 	mov	%eax, message+11	# insert into message
 	
 	# display message showing the current date
 	mov	$sys_WRITE, %eax	# system-call ID-number
 	mov	$dev_STDOUT, %ebx	# ID-number for device
 	lea	message, %ecx		# message's offset
 	mov	len, %edx		# message's length
 	int	$0x80			# enter the kernel
 
 	# terminate this application
 	mov	$sys_EXIT, %eax		# system-call ID-number
 	mov	$0, %ebx		# value for exit-code
 	int	$0x80			# enter the kernel
 
 	.globl	_start			# entry-point is public
 
 
 
 
 
 
 
 
Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье