Как написать ассембли код x86 nasm для Linux?
Мне нужно написать ассембли код x86 nasm для Linux, чтобы решить эту проблему. Необходимо создать список из 55 учеников, каждый из которых имеет свою оценку. Программе необходимо распечатать имя ученика с наивысшей оценкой, а также поставить рядом с ним его оценку. Если есть несколько учеников с одинаковым наивысшим баллом, необходимо вывести имя студента, который стоит первым в списке.
Код который я написал, но еще не закончил доконца:
section .data ; Student records students: db "John ", 80 ; Student 1: Name "John", Mark 80 db "Alice ", 70 ; Student 2: Name "Alice", Mark 70 db "Bob ", 80 ; Student 3: Name "Bob", Mark 80 ; Add more students as needed new_line db 10, 0 ; Define newline character section .text global _start _start: ; Initialize registers mov eax, students ; Start of student records mov ecx, 55 ; Number of students mov edx, 0 ; Initialize maximum mark xor ebx, ebx ; Initialize index of max mark student xor edi, edi ; Initialize index of first max mark student traverse_loop: ; Load student name mov esi, eax call PrintName ; Load and print student mark movzx esi, byte [eax + 10h] ; Load the module mark call PrintMark ; Compare marks cmp esi, edx ; Compare with current maximum mark jle not_greater ; If not greater, skip mov edx, esi ; Update maximum mark mov edi, ebx ; Update index of first max mark student not_greater: add eax, 11 ; Move to the next student record inc ebx ; Increment index dec ecx ; Decrement counter jnz traverse_loop ; If not zero, continue traversal ; Return with the first student with the highest mark mov eax, students add eax, edi ; Calculate address of the first max mark student ; Print a new line mov eax, 4 ; sys_write system call mov ebx, 1 ; File descriptor for stdout mov ecx, new_line ; Address of newline mov edx, 1 ; Length of newline int 0x80 ; Call kernel ; Exit mov eax, 1 ; syscall number for exit xor ebx, ebx ; exit code 0 int 0x80 ; call kernel PrintName: ; Print student name mov eax, 4 ; sys_write system call mov ebx, 1 ; File descriptor for stdout mov ecx, esi ; Address of student name mov edx, 10 ; Length of student name int 0x80 ; Call kernel ret PrintMark: ; Print student mark mov eax, 4 ; sys_write system call mov ebx, 1 ; File descriptor for stdout mov ecx, eax ; Address of student record add ecx, 10h ; Offset to mark mov edx, 2 ; Length of student mark int 0x80 ; Call kernel ret |
section .data ; Student records students: db "John ", 80 ; Student 1: Name "John", Mark 80 db "Alice ", 70 ; Student 2: Name "Alice", Mark 70 db "Bob ", 80 ; Student 3: Name "Bob", Mark 80 ; Add more students as needed new_line db 10, 0 ; Define newline character section .text global _start _start: ; Initialize registers mov eax, students ; Start of student records mov ecx, 55 ; Number of students mov edx, 0 ; Initialize maximum mark xor ebx, ebx ; Initialize index of max mark student xor edi, edi ; Initialize index of first max mark student traverse_loop: ; Load student name mov esi, eax call PrintName ; Load and print student mark movzx esi, byte [eax + 10h] ; Load the module mark call PrintMark ; Compare marks cmp esi, edx ; Compare with current maximum mark jle not_greater ; If not greater, skip mov edx, esi ; Update maximum mark mov edi, ebx ; Update index of first max mark student not_greater: add eax, 11 ; Move to the next student record inc ebx ; Increment index dec ecx ; Decrement counter jnz traverse_loop ; If not zero, continue traversal ; Return with the first student with the highest mark mov eax, students add eax, edi ; Calculate address of the first max mark student ; Print a new line mov eax, 4 ; sys_write system call mov ebx, 1 ; File descriptor for stdout mov ecx, new_line ; Address of newline mov edx, 1 ; Length of newline int 0x80 ; Call kernel ; Exit mov eax, 1 ; syscall number for exit xor ebx, ebx ; exit code 0 int 0x80 ; call kernel PrintName: ; Print student name mov eax, 4 ; sys_write system call mov ebx, 1 ; File descriptor for stdout mov ecx, esi ; Address of student name mov edx, 10 ; Length of student name int 0x80 ; Call kernel ret PrintMark: ; Print student mark mov eax, 4 ; sys_write system call mov ebx, 1 ; File descriptor for stdout mov ecx, eax ; Address of student record add ecx, 10h ; Offset to mark mov edx, 2 ; Length of student mark int 0x80 ; Call kernel ret
После того как я раню код мне выдается слелующее:
John Segmentation fault
Как видно, John выходит верно, но вместо отметки рядом с ним я получаю Segmentation fault
Дополнительно:
Ответы:
Видимо ошибка ф функции PrintMark.
Перед вызовом ты грузишь значение отметки в si, но в вызове его не используешь.Зачем-то копируешь там из EAX, хотя до этого записал туда 4, зачем-то еще раз берешь offset,
Твой traverse_loop держит указатель на текущую запись в eax, но первый же вызов PrintName портит почти все регистры и не восстанавливает их, поэтому первый же movzx esi, byte [eax + 10h] после этого вызова обращается мимо памяти и вызывает segfault. Проще всего это исправить каким-нибудь pusha / popa вокруг тела PrintName. После этого ты доберёшься до вызова PrintMark, где увидишь, что эта функция ожидает в eax + 10h текстового представления оценки, а у тебя пока есть только двоичное.
int 0x80 ; Call kernel
доки то читал?
ps аж ностальгия..
но не в твою пользу..
section .data только грусть вызывает..
.. и да... если тебе не хватает регистров для данных..
section .data не только для списка других... кхм... пытающихся стать программистами ))
... желаю успеха, но придется включить свои мозги... без вариантов
- Ох... посмотрел и аж взвыл от ностальгии... 1992 год, IBM PC 80286, 1Мб ОЗУ, 20 Мб HDD, msdos 3.3... как молоды мы были, как верили в себя...
ТС: Скажи мне, как ты думаешь, что означает команда int 0x80?
- CityCat4, 1982 (ассемблер АСВТ М6000) 1988, dos 3.3, турбо все (паскаль, ассемблер, дебагер..) портирование биос на автограф 1840 (с секапы, другая архитектура)... порт успешен, взломы "вражеских" прог на конвейере... а потом... сняли эмбарго )))
- #, Эх... в 1988 у меня была OS RSX на CМ ЭВМ... Я еще не знал, что слова нашего препода по предмету со странным названием ЛИПО САПР (Лингвистическое И Программное Обеспечение САПР) "бывает что некоторые из вас становятся специалистами, значительно большими чем я" окажутся пророческими :) Я в терминалке не работал - я в ней жил :)
- CityCat4, у меня в профиле телега... если иногда понастальгировать... ну а может и че конструктивное ))
- CityCat4, Ну че вы угораете над человеком лучше бы ткнули его носом в доку с системными вызовами линуксов.
- Sergei Nazarenko, а гугл отсох?..
асм увлекательная штука. но порог вхождения, видимо повыше чем в python или js. строгость мышления.. внимания.. необходимы..
а поиск доков? цель ресурса обучить?
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос

Для написания ассемблерного кода x86 на языке NASM для Linux вам потребуется установить компилятор NASM, который позволит вам создавать исполняемые файлы из исходного кода на ассемблере.
Ниже приведен пример простой программы на ассемблере x86 для Linux, которая выводит строку "Hello, World!" на экран:
```php
section .data
hello db 'Hello, World!', 0
section .text
global _start
_start:
; выводим строку на экран
mov eax, 4 ; номер системного вызова для вывода
mov ebx, 1 ; файловый дескриптор (stdout)
mov ecx, hello ; указатель на строку
mov edx, 13 ; длина строки
int 0x80 ; вызов ядра
; завершаем программу
mov eax, 1 ; номер системного вызова для завершения
xor ebx, ebx ; код возврата 0
int 0x80 ; вызов ядра
```
Чтобы скомпилировать эту программу, сохраните ее в файл с расширением .asm, например, hello.asm, и выполните следующие команды в терминале:
```bash
nasm -f elf32 hello.asm -o hello.o
ld -m elf_i386 hello.o -o hello
```
После этого у вас будет исполняемый файл hello, который можно запустить, чтобы увидеть вывод "Hello, World!".
Не забывайте, что ассемблерный код x86 для Linux может немного отличаться в зависимости от архитектуры процессора и операционной системы, поэтому убедитесь, что используете соответствующие инструкции и вызовы системы для вашей конкретной среды.