Создание устройства чтения ввода на сборке x86

Пытаюсь выучить системные вызовы в сборке от эта страница на tutorialspoint.

На этой странице есть ассемблерный код, который считывает вводимые пользователем данные и запрашивает их. Что меня сбивает с толку и, к сожалению, не работает:

section .data                           ;Data segment
   userMsg db 'Please enter a number: ' ;Ask the user to enter a number
   lenUserMsg equ $-userMsg             ;The length of the message
   dispMsg db 'You have entered: '
   lenDispMsg equ $-dispMsg                 

section .bss           ;Uninitialized data
   num resb 5

section .text          ;Code Segment
   global _start

_start:                ;User prompt
   mov eax, 4
   mov ebx, 1
   mov ecx, userMsg
   mov edx, lenUserMsg
   int 80h

   ;Read and store the user input
   mov eax, 3
   mov ebx, 2
   mov ecx, num  
   mov edx, 5          ;5 bytes (numeric, 1 for sign) of that information
   int 80h

   ;Output the message 'The entered number is: '
   mov eax, 4
   mov ebx, 1
   mov ecx, dispMsg
   mov edx, lenDispMsg
   int 80h  

   ;Output the number entered
   mov eax, 4
   mov ebx, 1
   mov ecx, num
   mov edx, 5
   int 80h  

   ; Exit code
   mov eax, 1
   mov ebx, 0
   int 80h

После выполнения кода программа никогда не запрашивает ввод - она ​​немедленно вызывает выход из системы.


Я нахожу некоторые части кода сбивающими с толку и предполагаю, что им, возможно, придется что-то делать с ошибкой:

   ;Read and store the user input
   mov eax, 3
   mov ebx, 2
   mov ecx, num  
   mov edx, 5          ;5 bytes (numeric, 1 for sign) of that information
   int 80h

В приведенном выше коде для eax (32-битный регистр накопителя) имеет смысл использовать 3, поскольку он выполняет системный вызов sys_read. edx, вероятно, определяет тип данных, и, учитывая, что мы сохраняем целое число, 5 имеет смысл.

Но 32-битный базовый регистр должен содержать индекс файлового дескриптора (где stdin=0, stdout=1, stderr=2). Но почему ebx=2 в приведенном выше коде?


Извините, если вопрос слишком простой, но почему код не работает? Что-то не так с неправильным выбором входов в регистры? то есть то, что я упоминал выше.

Если вы не перенаправили stderr, чтение с него, вероятно, будет работать так же, как чтение с stdin.

Michael 11.09.2018 21:39

stderr может использоваться как входной поток: stackoverflow.com/a/51308591/3512216

rkhb 11.09.2018 21:42

Программа работает но надо собрать и свяжите его как 32-битный исполняемый файл. Я думаю, вы можете прочитать первую часть учебника, но затем перейти к соглашению о вызовах 64-битных системных вызовов, получить список системных вызовов и использовать их, как в C. Раздел 2 руководства описывает оболочки вокруг syscalls, поиск в Google имени системного вызова также даст некоторую документацию. В худшем случае - исходники ядра.

Margaret Bloom 11.09.2018 21:42

@MargaretBloom: Мой Debian Jessie принимает и запускает эту программу как есть - как в 32-битном, так и в 64-битном режиме.

rkhb 11.09.2018 21:51

@rkhb Это не странно, это также происходит в моей CentOS, но это зависит от переключателей по умолчанию, с которыми ваш дистрибутив настроил GCC. См. этот отличный ответ. Я догадался, что это может быть проблема с OP.

Margaret Bloom 11.09.2018 21:54

@rkhb, как всегда в сборке, тот факт, что «программа работала, как ожидалось», мало что говорит о ее правильности (это, безусловно, ближе к правильному коду, чем программа, которая не дает правильного наблюдаемого поведения, но может быть еще далеким от правильного).

Ped7g 11.09.2018 21:57

@Margaret Bloom Что-то не так с прерыванием работы ядра? Я слышал, что 0x80 для ядра в каждом дистрибутиве Linux. Я выполнил этот код на нескольких онлайн-ассемблерах nasm, но все они дали одинаковые результаты. На указанной выше странице также есть ссылка для онлайн-сборки их кода (который должен иметь оптимальные настройки для этого определенного кода), но она все еще не работает.

ShellRox 11.09.2018 22:09

@Michael Но какой смысл использовать индекс stderr в качестве дескриптора ввода, когда есть stdin? Есть ли преимущество?

ShellRox 11.09.2018 22:11

@ShellRox int 0x80 - это старый 32-битный интерфейс системных вызовов. 64-битная версия использует syscall. Взгляните на связанный ответ, который я дал rkhb;)

Margaret Bloom 11.09.2018 22:34

@MargaretBloom Приношу извинения за путаницу, я попытался заменить int 0x80 на syscall в качестве эксперимента, но это не сработало, возникла недопустимая ошибка инструкции. Из последней ссылки я понял, что int 0x80 будет работать, если данные в указателях не превышают 32 бит.

ShellRox 11.09.2018 22:59

@ShellRox syscall - другое дело, лучше найти по нему учебник. Точно! int 0x80 будет работать, если все указатели уместятся в 32-битном формате :) Но вы должны убедиться, что это так.

Margaret Bloom 11.09.2018 23:42

@MargaretBloom: почему здесь кто-то говорит о портировании на x86-64? Это допустимая программа для i386 Linux, корректно использующая устаревший 32-разрядный ABI int 0x80. Это также могло бы работать, если бы оно было построено как 64-битный статический исполняемый файл, потому что модель кода по умолчанию помещает статические символы в младшие 32 бита адресного пространства. Он потерпит неудачу только в том случае, если он построен как 64-битный исполняемый файл PIE (который объясняет наблюдаемые симптомы) или на ядрах без CONFIG_IA32_EMULATION, и в этом случае он будет segfault или что-то в этом роде вместо чистого выхода.

Peter Cordes 12.09.2018 01:18

Конечно, это довольно дрянная программа. Он читает из stderr без всякой причины и выгружает весь 5-байтовый буфер вместо сохранения возвращаемого значения из read(2) для использования в качестве длины для write(2).

Peter Cordes 12.09.2018 01:19

@PeterCordes, потому что цель OP - научиться писать программу для Linux на ассемблере. Я предложил либо собрать / связать его как 32-битный, либо перейти на 64-битный, поскольку руководство, которому они следуют, устарело и не учитывает эти проблемы.

Margaret Bloom 12.09.2018 08:05

Я бы предпочел перейти к другому руководству, поскольку код устарел и немного странный. Спасибо вам за помощь!

ShellRox 12.09.2018 09:22

@ShellRox о int 0x80, работающем повсюду ... например, встроенный Linux внутри Windows 10 имеет только 64-битное ядро, поэтому 64-битный двоичный код с использованием int 0x80 там не сработает, даже если он работает с обычной 64-битной установкой Ubuntu (и этот Linux внутри win10 основан на Ubuntu , поэтому можно ожидать, что он будет работать аналогичным образом, но это не так). Конечно, обычный 32-битный двоичный файл не будет работать вообще в такой 64-битной системе, но сообщение об ошибке, вероятно, будет более конкретным, чем общий segfault.

Ped7g 12.09.2018 14:25
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
16
64
0

Другие вопросы по теме