Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 Languages
 С
 GNU С Library 
 Qt 
 STL 
 Threads 
 C++ 
 Samples 
 stanford.edu 
 ANSI C
 Libs
 LD
 Socket
 Pusher
 Pipes
 Encryption
 Plugin
 Inter-Process
 Errors
 Deep C Secrets
 C + UNIX
 Linked Lists / Trees
 Asm
 Perl
 Python
 Shell
 Erlang
 Go
 Rust
 Алгоритмы
NEWS
Последние статьи :
  Тренажёр 16.01   
  Эльбрус 05.12   
  Алгоритмы 12.04   
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
 
TOP 20
 Secure Programming for Li...6507 
 Linux Kernel 2.6...5279 
 Trees...1115 
 Максвелл 3...1050 
 William Gropp...986 
 Go Web ...957 
 Ethreal 3...929 
 Ethreal 4...915 
 Gary V.Vaughan-> Libtool...912 
 Ext4 FS...901 
 Clickhouse...900 
 Rodriguez 6...899 
 Ethreal 1...896 
 Steve Pate 1...884 
 C++ Patterns 3...860 
 Assembler...851 
 Ulrich Drepper...844 
 DevFS...786 
 MySQL & PosgreSQL...769 
 Стивенс 9...756 
 
  01.01.2024 : 3621733 посещений 

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
 
 
 
 
 
 
 
 
Оставьте свой комментарий !

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

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