Простые программы на ассемблере

Аннотация

Целью первой лабораторной работы является восстановление и закрепление навыков программирования, в том числе на уровне архитектуры компьютера, полученных ранее при изучении дисциплин "Основы информатики и программирования" и "Введение в архитектуру ЭВМ", в частности, организации рабочей среды и управления файлами и процессами в режиме диалога с системой с использованием командного интерпретатора, подготовки программного кода на языке ассемблера, трансляции программы и исполнения в отладчике.

Ход работы

  1. Создайте в домашнем каталоге каталог для файлов лабораторных работ по курсу "Архитектура современных ЭВМ".
  2. Создайте каталог для файлов данной лабораторной работы.
  3. Создайте файл исходного кода hello.S в любом текстовом редакторе (nano, vim, emacs, и т.п.), скопируйте в него следующий текст.
    /**
     * hello.S -- выводит приветственную строку на стандартный вывод
     *
     * Copyright (c) 2014 Petrozavodsk State University
     *
     * Permission is hereby granted, free of charge, to any person obtaining
     * a copy of this software and associated documentation files (the
     * "Software"), to deal in the Software without restriction, including
     * without limitation the rights to use, copy, modify, merge, publish,
     * distribute, sublicense, and/or sell copies of the Software, and to
     * permit persons to whom the Software is furnished to do so, subject to
     * the following conditions:
     *
     * The above copyright notice and this permission notice shall be
     * included in all copies or substantial portions of the Software.
     */
    
    /* Секция данных */
    
    .data
    
        /* Размещаем нуль-терминальную строку в области глобальных
           инициализированных данных, метка greeting адресует строку */
    
        greeting: .asciz "Hello from Assembler!\n"
    
    
    /* Секция команд процессора */
    
    .text
    
        /* Метка _start адресует точку входа - первую инструкцию в секции
           команд процессора, которая будет исполнена при загрузке программы */
        .global _start
        _start:                           
    
        /* Выводим строку на экран с помощью системного вызова write ОС Linux */
    
        movl $4, %eax           # помещаем номер системного вызова write
                                # в регистр eax,                            
        movl $1, %ebx           # помещаем номер дескриптора файла в регистр ebx,
                                # единица соответствует стандартному выводу, stdout
        leal greeting, %ecx     # помещаем адрес выводимой строки в регистр ecx
                                # (объясните, почему не movl greeting, %ecx
        movl $22, %edx          # помещаем в регистр edx количество байт, начиная с
                                # заданного адреса, которые нужно отправить в файл
        int  $0x80	            # обращаемся к обработчику системных вызовов
                                # ОС Linux, который выполняет вызов по его номеру
    
        /* Завершаем выполнение программы с помощью системного вызова _exit */
    
        movl $1, %eax           # помещаем номер системного вызова _exit
                                # в регистр eax
        movl $0, %ebx           # помещаем код возврата в регистр ebx,
                                # нулевой код соответствует успешному завершению
        int  $0x80              # обращаемся к ОС
    
    
    .end                        # последняя строка исходного текста
    
  4. Выполните ассемблирование и компоновку:
    user@linux~> as -ahlsm=hello.lst -gstabs+ --32 -o hello.o hello.S
    user@linux~> ld -m elf_i386 -o hello hello.o
    
  5. Запустите программу, убедитесь, что строка выводится на стандартный вывод, а программа затем корректно завершается:
    user@linux~> ./hello
    user@linux~> echo $?
  6. Откройте программу в отладчике gdb, включите режим отображения регистров
    user@linux~> gdb -tui ./hello
    (gdb) layout reg
  7. Выполните программу по шагам, отслеживая изменение значений регистров, помимо непосредственно задействованных в инструкциях регистров, обращайте внимание на изменение регистра флагов (eflags) и счетчика команд (eip).
  8. Создайте файл исходного кода greetings.S в любом текстовом редакторе (nano, vim, emacs, и т.п.), скопируйте в него следующий текст.
  9. /**
     * greetings.S -- выводит приветственную строку несколько раз
     *
     * Copyright (c) 2014 Petrozavodsk State University
     *
     * Permission is hereby granted, free of charge, to any person obtaining
     * a copy of this software and associated documentation files (the
     * "Software"), to deal in the Software without restriction, including
     * without limitation the rights to use, copy, modify, merge, publish,
     * distribute, sublicense, and/or sell copies of the Software, and to
     * permit persons to whom the Software is furnished to do so, subject to
     * the following conditions:
     *
     * The above copyright notice and this permission notice shall be
     * included in all copies or substantial portions of the Software.
     */
    
    
    /* Секция данных */
    
    .data
    
        /* Размещаем нуль-терминальную строку в области глобальных
           инициализированных данных, метка greeting адресует строку */
        greeting: .asciz "Hello from Assembler!\n"
    
    
    /* Секция команд процессора */
    
    .text
    
        /* Метка _start адресует точку входа - первую инструкцию в секции
           команд процессора, которая будет исполнена при загрузке программы */
           
        .global _start
        _start:                           
    
        /* Многократно выводим строку на экран */
        
        movl $22, %esi          # фиксируем счетчик повторений
      
      next:
      
        movl $4, %eax           # помещаем номер системного вызова write
                                # в регистр eax                            
        movl $1, %ebx           # помещаем номер дескриптора файла в регистр ebx,
                                # единица соответствует стандартному выводу, stdout
        leal greeting, %ecx     # помещаем адрес выводимой строки в регистр ecx
                                # (объясните, почему не movl greeting, %ecx
        movl $22, %edx          # помещаем в регистр edx количество байт, начиная с
                                # заданного адреса, которые нужно отправить в файл
        int  $0x80	            # обращаемся к обработчику системных вызовов
                                # ОС Linux, который выполняет вызов по его номеру
    
        subl $1, %esi           # уменьшаем счетчик
        cmpl $0, %esi           # если требуемое число повторений достигнуто,
        je done                 # переходим к завершению программы
        jmp next                # иначе повторяем еще раз
    
      done:                            
    
        /* Завершаем выполнение программы с помощью системного вызова _exit */
        
        movl $1, %eax           # помещаем номер системного вызова _exit
                                # в регистр eax
        movl $0, %ebx           # помещаем код возврата в регистр ebx,
                                # нулевой код соответствует успешному завершению
        int  $0x80              # обращаемся к ОС
    
    .end                        # последняя строка исходного текста
    
  10. Выполните ассемблирование и компоновку программы по аналогии с предыдущим примером.
  11. Запустите программу, изучите ее вывод.
  12. Откройте программу в отладчике.
  13. Установите контрольную точку на следующую за строкой movl $22, %edx строку.
  14. Запустите программу и остановившись в контрольной точке подмените значение регистра edx средствами отладчика меньшим значением.
  15. Модифицируйте программу так, чтобы каждая выведенная строка была на один символ короче предыдущей (т.е. треугольником, см. пример ниже), убедитесь, что программа не выводит избыточных пустых строк, в том числе до и после текста:
    Hello from Assembler!
    Hello from Assembler
    Hello from Assemble
    Hello from Assembl
    Hello from Assemb
    Hello from Assem
    Hello from Asse
    Hello from Ass
    Hello from As
    Hello from A
    Hello from 
    Hello fro
    Hello fr
    Hello f
    Hello 
    Hello
    Hell
    Hel
    He
    H
    
  16. Модифицируйте программу так, чтобы строки выводились в форме песочных часов (см. пример ниже), убедитесь, что программа не выводит избыточных пустых строк, в том числе до и после текста:
    Hello from Assembler!
     ello from Assembler
      llo from Assemble
       lo from Assembl
        o from Assemb
          from Assem
          from Asse
           rom Ass
            om As
             m A
               
             m A
            om As
           rom Ass
          from Asse
          from Assem
        o from Assemb
       lo from Assembl
      llo from Assemble
     ello from Assembler
    Hello from Assembler!