Как вывести hello world на ассемблере

от admin

Name already in use

If nothing happens, download GitHub Desktop and try again.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching Xcode

If nothing happens, download Xcode and try again.

Launching Visual Studio Code

Your codespace will open once ready.

There was a problem preparing your codespace, please try again.

Latest commit

Git stats

Files

Failed to load latest commit information.

README.md

This year I studied computer’s organisation II in College. I’ve been fascinated thus far with how computation is done on an assembler language and I want to share with you a little of my knowledge.

Maybe this will become a series because I’m finding myself really captivated with this subject and I think a lot of people will understand better how programming works with this info.

But first things first

ASM, short for Assembler (or assembly), is not a unique language such as C, Java, Go or whatever, it is instead a program that converts code into machine language. This means there’s assembler languages for the different types of machines. For example: There is assembler for the Intel and AMD processor’ architectures (x86_64) and there’s another for ARM architectures.

This tutorial is going to be oriented toward Intel’s Architecture

�� What are we going to use?

Alt Text

For this short program we are going to use NASM and whatever text editor you like. In my case, I’m going to use VS Code since it has some nice plugins.

To install NASM on Debian systems (Ubuntu, PopOs!, Linux Mint, etc..)

I’m only going to show this example in a linux system since the sys calls are different for mac, hence the example won’t work in that system (believe me, this post was intended for mac as well. )

��️ Structure of an ASM program

Ok, now we have our assembler and our Text Editor or IDE. What now?

Let’s create a new file and name it helloWorld.asm

Alt Text

Now that we have our empty file. We need to determine how the file is going to be used. In ASM each file has 4 sections. This sections will always exist even if you don’t define them. However, if you need one, you will have to do it.

The 4 sections are:

.data : where we are going to declare our global initialised variables

.rodata : where we are going to declare our global un-itialised constants

.bss : where we are going to declare our global un-initialised variables

.text : where we are going to define our code

Ok, so what we are trying to build here is a CLI program that prints Hello World!. Sounds fairly easy. But in order to do so, we need to inform the processor that this function that we are going to name ‘start’ is global to all the system. so we add our .text section with the ‘start’ function and the global statement outside the section. Like this:

Alt Text

Since we don’t want to use any fancy C functions, nor none of those other high level languages functions for the matter, we are going to rely on Syscalls.

Without digging that deep, Syscalls are just calls to the OS. We need to call the 0x80 interruption (on UNIX systems) and pass to that interruption the parameters we want it to handle.

For the function that we are going to use (sys_write) the interruption receives 4 parameters:

  1. The function number (RAX)
  2. Where do we want it to execute (RBX)
  3. The direction of the memory we want to execute (RCX)
  4. The size of the message in bytes (RDX)

RAX, RBX, RCX and RDX are just multi-purpose registers that we are going to use and that I’m going to explain in further chapters of this series. So bare with me for now.

So let’s define the message first and let’s call int 0x80 after that.

Alt Text

A lot of new info here. Let’s go line by line.

This is the section were we are going to define our ‘Hello World!’ string variable. Since it will be already initialised, we declare in .data

This is our new string. It’s declared under the name msg and we initialise it with DB (define byte) the characters that will be displayed and a ‘, 10’ which is going to be our \n character. What I want you to get out of this step is that Each char comprising ‘Hello World!’ takes one byte of memory. So by using DB we are asking the processor for a memory slot that will take 13 bytes (counting the space and \n char).

This one is a little bit tougher. We are declaring a variable call msgSize that is going to step on the right end of Hello World! ($) and will subtract the address were your msg variable began. Thus leaving us with the bytes used for msg

We have our message, let’s display it now!

Alt Text

Again, let’s explain what is happening here

Intel has a very weird way of doing things most of the time. So each line of text will be divided into 4 fragments again

  1. Mov : an instruction which moves the elements from B to A
  2. A : the destiny Register/Memory
  3. B : the origin Register/Memory
  4. comments : where the comments are :p

So what we are doing in here is moving the number 4 to our RAX register (because sys_write is our function number 4 on UNIX). We move the number 1 to RBX (representing STDOUT). Then the memory in which msg is defined will be stored on RCX and finally the size on RCX. By calling int 0x80 we are asking the interruption 0x80 to handle all the parameters we threw to it and do what it’s supposed to do.

Alt Text

Our final step is to exit the program. And guess what? that requires another Syscall. In this case, our function will be number 1 (exit) and our parameter will be 0 (because that’s the number we want to return. 0 usually means that the program was executed successfully while 1 means that it wasn’t)

�� Assembling and Linking

Let’s save our file as helloWorld.asm and head over to the terminal.

If you have already installed NASM, head to the folder where you saved your .asm file and assemble and link it.

And that’s it for today. You should get a ‘Hello World message on your terminal.

Hello World на Ассемблере

После примеров простых программ на Паскале и С++ вы, наверно, не ожидали что я сразу перепрыгну на Ассемблер. Но вот перепрыгнул. И сегодня мы поприветствуем мир на языке ассемблера.

Итак, вот сразу пример, а потом его рассмотрим:

Как видите, программа на ассемблере, даже такая простая, содержит исходный текст значительно большего размера по сравнению с аналогичной программой на С++, а уж тем более на Паскале.

С другой стороны, это не так уж и страшно, как иногда думают те, кто никогда не программировал на Ассемблере.

Во всех подробностях разбирать этот код не будем — подробности в другой раз. Рассмотрим только основные инструкции.

Программа начинается с метки begin . В отличие, например, от Паскаля, это слово может быть каким угодно, например, start . Это всего лишь метка, которая обозначает начало какого-то участка кода.

К конце программы мы видим END begin . Инструкция END говорит ассемблеру, что следующее за ней слово означает конец блока кода, обозначенного этим словом. В нашем примере это означает, что здесь кончается блок кода, начинающийся со слова begin .

Далее уже начинается программа. Сначала в регистр АН мы записываем номер функции, которую собираемся потом выполнить. Номер 9 — это функция BIOS, которая выполняет вывод на устройство вывода. По умолчанию это монитор.

Затем в регистр DX мы записываем адрес строки. Адрес вычисляется с помощью оператора OFFSET . Например:

Здесь мы получаем адрес первого байта блока данных, обозначенного идентификатором Msg .

Затем мы вызываем прерывание 21h . Это прерывание выполняет функцию, номер которой записан в регистре АН. Поскольку у нас там записана функция 9, то прерывание выведет на экран строку.

Команда RET выполняет выход из процедуры или из программы. В нашем случае из программы. Таким образом программа завершается и мы возвращаемся в операционную систему.

Ещё несколько слов об объявлении строки:

Msg DB ‘Hello, World. $’

Вначале мы записываем идентификатор (в нашем случае Msg , но может быть и любой дугой), чтобы было проще работать со строкой. Затем пишем DBDefine Byte — Определить Байт. В нашем случае это будет массив байтов, в котором каждый элемент имеет размер один байт.

Потом пишем саму строку. Каждый символ занимает один байт, поэтому мы и объявили массив байтов. Знак доллара означает конец строки. Так функция вывода понимает, где она должна завершить вывод. Если этот знак не поставить, то будет выведено множество символов — сначала наша строка, а потом разный мусор, содержащийся в ячейках памяти, следующих за нашей строкой. А в эмуляторах это вообще может считаться ошибкой и вывода не будет.

Ну вот мы и написали свою первую программу на языке ассемблера. Если что-то пропустили, то посмотрите видео:

Programming a “hello world!” in assembly from the first line to the end (x86)

Hello everyone, I’m Pablo Corbalán and this is my first Medium post, I’ll be using Medium as a little blog because I’m to lazy for programming a blog myself.

In this post I’m going to explain how you can code a “Hello world!” program using assembly, more specifically x86 Linux assembly. But first of all, what’s assembly?

This article is going to be divided in three sections

  1. What is assembly and how do computers understand code
  2. Programming a Hello World in assembly
  3. Running the program in your computer

What is “the assembly language”?

A bit of history

Computers can’t understand a human language, they understand electric current, this “electric current” can be represented as a set of instructions the computer should reproduce, we call this “machine language”, the language that computers can understand. At the end computers only understand binary instructions that are evaluated using logic gates, but that is hardware stuff, and we are here to build software!

It is due to this that throughout history programmers have tried to make the computer understand languages ​​more and more similar to real human language. Nowadays we have programming languages that are really similar to human language, for example Python. You can understand basic Python code with a quick look at it. For example the expression

makes sense in a Python program and in a Cambridge exam.

However, to achieve this, programming languages ​​have had to evolve little by little. We haven’t created a language like Python in a week

So, how do computers understand other languages?

Programmers have programmed special programs to “translate” other languages to a language that computers can actually understand. For example imagine that you just now how to speak English, you’ll have troubles if a Korean tries to maintain a conversation with you, however if you have a translator that can translate from Korean to English, you’ll not have any problems. The same applies in computers, a computer can’t directly understand Python or Golang, however Python or Golang can be translated to binary so that the computer can understand the program.

This programs that “translate” the languages are called compilers or interpreters (or semi-compilers) depending on the process they use for “translating” the language, there are interpreted languages (as Python), compiled programming languages (as Golang) and a special type called “semi-compiled” (for example, Java is a semi-compiled programming language). You can read about the differences between compiled and interpreted languages in this article.

We can call the languages as Python or Golang “high-level programming languages”, because they are very similar to human language and they are really different from what a computer can understand. There are “low-level programming languages”, for example C, as it’s a point between a high-level language and a language that a computer can understand. Low-level programming languages are designed to create hardware, as they work directly with the memory and specifications of the computer, meanwhile high-level programming languages are more “designed” to building software.

But languages are not compiled to binary directly. The process of compiling a program can be pretty complex. If we talk about compiled languages, a high-level programming language is compiled to assembly code or machine code). Assembly is a very low-level programming language, that is the most similar thing to machine code that we can write without problems.

There are numerous different versions of assembly. It’s not one language; it’s actually a collection of similar languages. In most cases, assembly is just “shorthand” for machine language. It usually has some symbols that are close to words (like JMP for “jump”) that are easier for humans to digest. The real machine code is just a bunch of numbers. While understandable for small programs, it’s unmanageable for large projects.

For example, C/C++/Rust compile directly to machine code, Java/C#/Python compile to an intermediate language that is then run on a system that interprets that output when the program runs. It used to be fairly slow, but it’s not anymore given modern hardware and operating systems. Python is kind of halfway in this camp, it’s actually interpreted at runtime but it’s the compiled code that’s interpreted. JavaScript is entirely interpreted at runtime. Not compiled at all.

It’s easy to convert assembly code to machine code and vice versa.

Now let’s get into code!

To code in assembly, we can use any plain text editor, for example Visual Studio Code, Sublimetext3… Programming in assembly is the same as working with any other programming language, but you have to directly move the RAM memory as you want for it to work.

I’ll use Vim, The first step is creating an assembly file, Assembly code is written in files with the .asm extension. I’ll call my file hello.asm .

Basic assembly x86 syntax

Today we are going to use x86 assembly, as I have said before assembly is not a single language, but x86 is the most common of all of them. We are going to see a bunch of assembly keywords and symbols, to then understand how the hello world works.

Comments in assembly start with a semi colon. For example:

As assembly instructions are pretty different to human language, it’s a good practice to comment every line of code and explain what it does. I can’t explain assembly to you guys, but if you have curiosity and want to learn more x86, you can learn this guide. Basically you have to keep in mind two important things, we have registers. From tutorials point:

Processor operations mostly involve processing data. This data can be stored in memory and accessed from thereon. However, reading data from and storing data into memory slows down the processor, as it involves complicated processes of sending the data request across the control bus and into the memory storage unit and getting the data through the same channel. To speed up the processor operations, the processor includes some internal memory storage locations, called registers. The registers store data elements for processing without having to access the memory. A limited number of registers are built into the processor chip.

More about registers here. The second think we are going to use today is the mov keyword, as an abbreviation of “move”, mov is used for moving memory inside the program, it can be also used for moving a register. For example:

Читать:
Как прикрепить файл в вордовский документ

The Wikipedia page has a clear explication about how does it work. Now that we know this, we can start coding in our file. The first step is opening the file in your text editor and creating two sections. We will call this sections .text and .data . In assembly a section is the smallest unit of an object that can be relocated in .elf files (elf is a file format for executable programs, libraries and more). We can use sections for executable text, read-only data, read-write data, read-write uninitialized data…

Sections are created with the section keyword, so in our program we will have to write:

As I have previously said it’s a good practice to comment the lines (you don’t have to comment all, but we will do it today as this is a “tutorial”)

It’s also a good practice to tabulate the code in columns, so that it’s not a mess. The next line we are going to type inside the .text section is

global is a directive (or an instruction) for Nasm (Netwide Assembler), wich is the assembler for the x86 CPU. It can be used for creating 16, 32 or 64 bits programs. Don’t worry you’ll have to use it with a linker later. And now we have to write the entry point for it:

Now we are going to declare the data that we are going to be using in the program. All this data goes into the data section. For creating a “Hello world!” program we’ll have to use two things that can be expressed as data.

  • The message we want to show in the console (in this case “hello world”)
  • The size of that message

Maybe you think “do we really need to now the size of the message for showing it in the console? Well my friend, yes we have. Maybe you don’t need the size of the message for creating a Hello world in Python, but in assembly you have the control over all. This means that you can control exactly the number of bits, bytes or whatever you want to use, to move, to show, to write etc etc… This is what we refer to when we say “working directly with the memory of the computer”.

So let’s start creating the message, for creating the message we are going to use db , witch is an abbreviation for “define byte”, so we are going to use 8 bits of memory (as maximum) for storing our message. You can use other variable sizes:

  • db: Define byte (8 bits of memory for the variable)
  • dw: Define Word. Generally 2 bytes on a typical x86 32-bit system
  • dd: Define double word. Generally 4 bytes on a typical x86 32-bit system

We will assign the message to msg , so now the code looks like:

0xa is the hexadecimal character for creating a new line

And now we are going to assign the lenght of the message to another expression called len . We can do this using a pointer “$” and the equ (from “equals) statement.

So now the code will look like:

Note: I’m not commenting the code because it is too wide for a device screen. At the end of the article you have the code completely commented
Now we can return to the _start piece of code. For creating a Hello world program in assembly, we have to do four things:

  1. “Invoke” the data to the .text section.
  2. Set the file descriptor for the program.
  3. Print the text
  4. Exit the program

So, let’s start with the first point, for doing so we have to first “invoke” the data from the .data section, we do this using the mov keyword and moving the memory:

The third step is also very simple, for setting the file descriptor of the program we just have to use the following line of code:

If you don’t know what the file descriptor is in Linux (fd) you can read about it here. So now our code should look like this (but with some comments)

The next step is to call the system for printing in the console. x86 for linux works with system calls, every system call has an ID. The system call for printing in x86 is eax, 4 . So we’ll have to add to the .start section:

And now we have to add another line for stopping this process. In Linux assembly is what we call “call the kernel”:

Int is the abbreviation for “interrupt” An interrupt transfers the program flow to whomever is handling that interrupt, which is interrupt 0x80 in this case. In Linux, 0x80 interrupt handler is the kernel, and is used to make system calls to the kernel by other programs. So the code will now look like:

The last step is to exit the program and again pass it to the Linux kernel. The exit system call is eax, 1 , so the code will look like:

And that’s it, this is a complete “Hello world” program in assembly x86. We can comment the code like:

Again, you don’t really have to comment all the lines as I have done, but this is a tutorial so you I have done it so that you can understand what I’m doing, however lines as global _start , the sections or int 0x80 don’t really need to be commented as everyone knows what they are.

I have updated all the code (commented) to a GitHub gits. Link under the image

Running the program without problems

For running the program we are going to use 2 things

  1. nasm Nasm is the assembler we are going to use. An assembler is a program that converts assembly language into machine code. It takes the basic commands and operations from assembly code and converts them into binary code that can be recognized by a specific type of processor. Assemblers are similar to compilers in that they produce executable code.

If you want to install nasm is really simple in most Linux distributions, for example in Debian (and similar ones) you just have to open a terminal and type:

If you are not using Debian, type in Google “How to install nasm in <name>”, and instead of <name> type your distribution. For example “how to install nasm in arch linux”.

Verify if you have installed nasm using:

2. ld: Ld is the linker we are going to use, a linker is a program that “joins” lot’s of pieces of code into the same executable file. If you don’t know if you have ld installed in your computer type

in the terminal. If it does not create any errors, you have ld installed. If you don’t have ld installed you can download it from the binutils project (GNU):
https://www.gnu.org/software/binutils/

Generating the executable

Now that you have nasm and ld installed, we are going to generate the executable. The first thing we are going to run is nasm, in a terminal type:

And this should not raise any error. Now you have to link the object file hello.o into an executable using ld, so type:

You can also type both of the commands in the same line using && :

And that’s it! Now you can run the Hello world as an executable using ./hello !

That’s the end of this tutorial. Remember to follow me on Twitter and GitHub @pablocorbalann!

Изучаем язык ассемблера на примере TSR программы под MS-DOS. Часть 1

Эта серия статей посвящена изучению и практике программирования на языке ассемблера.

Материал рассчитан на новичков в ассемблере, студентов, которым пришлось столкнуться с «динозавром» в виде MS-DOS, и может быть интересен тем, кто хочет немного узнать как функционировали операционные системы на заре своего существования.

Писать мы будем резидентную программу (TSR), которая при завершении возвращает управление оболочке операционной системы, но остается в памяти и продолжает своё существование. В современном мире близкий аналог этого понятия — демон/служба.

Программа будет выполнять следующие функции:

вывод текста вниз экрана по таймеру,

переключение режима отображения шрифта: italic/normal,

запрет на ввод прописных русских букв,

вывод бинарного представления символа.

Предисловие

Материал не претендует на полноту, здесь будут рассматриваться базовые концепции и приемы программирования на языке ассемблера, необходимые для написания программ.

Не буду лишний раз подчеркивать важность ассемблера. Скажу лишь только, что любой уважающий себя профессионал должен понимать как работает его система на всех уровнях, необязательно знать, но понимать нужно.

Немного оговорок. Далее под ассемблером будет пониматься язык ассемблера, а не программа компилятор. MS-DOS часто будет заменяться на dos/дос.

Об умениях, ожидается, что ты имеешь какие-то представления о командной строке, работал с языками высокого уровня (так ты будешь уже знать основные конструкции, используемые в программировании, и увидишь как они реализуются на уровне ниже). В целом, этого хватит.

Про MS-DOS. Всех, наверное, пугает это слово в современном мире. Операционная система, которая уже как 20 лет мертва, но не все так однобоко как кажется на первый взгляд. Минусы понятны: изучение технологии, которая уже сгнила и разложилась, не используемая модель памяти. Но что насчет положительных моментов:

Ассемблер он и в Африке ассемблер, основные концепции программирования на нем будут везде одинаковы, да где-то будут расширенные регисты, где-то другой интерфейс по работе с операционной системой.

MS-DOS очень простая операционная система, которая в начале своего существования умещалась в 50 тысяч строк кода, причем ассемблерных (Майкрософт выложила исходники 2-х версий на github). График ее изучения имеет дно, в отличие от современных операционных систем. Аналогией может служить C и C++, последний, наверное, не знает в полной мере со всеми тонкостями ни один человек в мире.

Операционка работает в реальном режиме процессора, то есть в 16-битном. Это означает, что нет виртуальной памяти, адреса сразу преобразуются в физические с использованием сегментной адресаци памяти. Нет защиты процессов друг от друга, можно обратиться по любому адресу, посмотреть, что там лежит, можно делать с осью все, что тебе вздумается, но могут быть последствия ;). Плюс этот режим до сих пор не вымер, при запуске системы процессор начинает работу именно в этом режиме. Так что это не просто знакомство с историей.

Из предыдущего пункта понятно, что систему легко сломать, например, переписать адрес аппаратного прерывания по работе с клавиатурой, но в режиме эмуляции dos очень быстро запускается, что очень удобно в таких случаях

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

в MS-DOS мало встроенной функциональности, она работает в режиме терминала (печатной машинки), и уже первые шаги в написании ассемблерных программ позволяют видеть пользу от них.

Ассемблер актуален в MS-DOS, и это радует, когда работаешь в ней, потому что иных средств разработки программ не так много там. Но в настоящее время ассемблер используется только в виде вставок в языке Си или в микроконтроллерах.

Простой формат бинарного файла, точнее его попросту нет. Текст программы компилируется напрямую в машинный код, и получается исполняемый файл .COM, готовый к запуску. Очень удобно начинать обучение с этого, не забивая себе голову всякими разными дерективами, секции, которые необходимы в современных форматах.

Немного про компилятор. Использоваться будет NASM, хотя логичнее было бы использовать досовские компиляторы TASM, MASM, но они не поддерживают мою рабочую операционную систему Линукс, а разрабатываться хочется все-таки в удобстве, поэтому взят nasm. Он популярный, современный, кроссплатформенный (запускается везде, компилируется подо все, включая дос), более умный — позволяет опускать какие-то вещи в синтаксисе, имеет фичи в виде локальных меток, контекстов, всяких других директив.

Настройка

Для начала нам потребуется эмулятор операционной системы DOS под названием DOSBox. Скачать можно здесь, версия 0.74-3. После установки и запуска вы увидите, что-то похожее на это:

Стартовый экран DOSBox

Стартовый экран DOSBox

Теперь смонтируем папку (сделаем доступной в досе), в которой будут лежать все наши файлы, утилиты. Для этого в хостовой операционной системе создадим папку в домашней директории пользователя или на рабочем столе. Назовем ее, например, dos. После этого в эмуляторе прописываем следующую команду:

Windows: Z:\> mount c: C:\Users\Username\Desktop\dos

Linux: Z:\> mount c: /home/username/dos

Получаем сообщение Drive C is mounted. Теперь все содержимое папочки dos будет отображаться в диске С: в эмуляторе. Перейти в диск C с диска Z можно командой Z:\>c: . Это действие придется делать каждый раз при запуске эмулятора, поэтому мы можем положить эту команду в файл конфигурации в секцию autoexec. На линуксе файл находится в /home/username/.dosbox . На виндовс C:\Users\Username\AppData\Local\DOSbox . Открываем файл dosbox-0.74-3.conf и в конец прописываем команду монтирования и перехода в диск C вот таким образом:

Hello world

Напишем первую программу на ассемблере, которая будет выводить на экран избитую фразу hello world:

Вот такая маленькая простая программа исполняет наши нужды. Скомпилировать ее можно с помощью насма следующим образом:

nasm hello_world.asm -o hello_world.com

Бинарный .com файл нужно положить в нашу папочку dos, перезапустить дос или запустить в работующем эмуляторе команду rescan, чтобы дос подхватил изменения. Запустить команду можно, начав вводить первые символы имени файла и нажав Tab. Вводить название файла целиком самостоятельно не стоит, потому что долго и потому что с файлами, у которых в имени больше 8 символов, начинаются проблемы. Регистр букв не важен. После запуска, на экране можно будет увидеть фразу Hello, world!.

Теперь о том, что делает каждая строчка, 1-я строка org 100h это указание компилятору на смещение начала инстукций, будет понятно, что это означает, когда мы рассмотрим устройство .com файла и механизм работы процессора в реальном режиме.

8-я строка содержит метку message: , метки это своего рода переменные, в них помещается адрес текущей инструкции, после компиляции, места, где были ссылки на метки будут заменяться реальными адресами. Двоеточие в метках опционально. Далее идет псевдо-инструкция db (define byte), она не является инструкцией процессора, служит для того, чтобы в текущее место исполняемого файла записать блок данных побайтово. db принимает сколько угодно операндов (аргументов), разделенных запятыми. В нашем случае это один операнд, являющийся строкой из 14 символов (байт), можно было бы записать строку и посимвольно. В конце строки ставится знак $, который дает понять внутренней функции доса, что наступил конец строки. В следующей части поговорим, о том почему у нас данные находятся в конце файла.

3-5 строки подготовка для вызова прерывания 21h и непосредственно сам вызов, прерывание мы обсудим в 3-ей части, в нашем случае это попросту вызов функции операционной системы. В строке 3 мы помещаем число 09h (h значит шестнадцатиричное) в регистр ah. 09h — это номер функции.

В строке 4 записываем в dx адрес начала строки, которую хотим вывести на экран. Теперь понятно зачем нужен $, начало строки дос знает, конец нет.

В строке 5 передаем управление операционной системе с помощью прерывания, по номеру функции дос понимает, что нужно сделать (вывести строку на экран).

В строке 6 используем прерывание 20h для завершения программы, этот способ не совсем корректный, но он простой и хорошо подходит для .com программ.

Не думаю, что стало сильно понятно. Поэтому в следующих частях мы рассмотрим теоретические аспекты: сегментную адресацию памяти, формат файла .com, дебаггер, интерфейс вызовов функций дос, прерывания и снова вернемся к примеру с hello world.

Похожие статьи