X86 NASM Assembly преобразует нижние и верхние и нижние символы
Как я довольно новичок в сборке, у меня есть несколько вопросов относительно того, как я должен преобразовывать из строчной буквы в верхний регистр, если пользователь вводит прописную букву или наоборот в сборке. вот что я до сих пор:
section .data
Enter db "Enter: "
Enter_Len equ $-Enter
Output db "Output: "
Output_Len equ $-Output
Thanks db "Thanks!"
Thanks_Len equ $-Thanks
Loop_Iter dd 0 ; Loop counter
section .bss
In_Buffer resb 2
In_Buffer_Len equ $-In_Buffer
section .text
global _start
_start:
; Print Enter message
mov eax, 4 ; sys_write
mov ebx, 1
mov ecx, Enter
mov edx, Enter_Len
int 80h
; Read input
mov eax, 3 ; sys_read
mov ebx, 0
mov ecx, In_Buffer
mov edx, In_Buffer_Len
int 80h
Итак, в принципе, если я прав, мой edx содержит введенную строку. Теперь возникает дилемма преобразования от нижнего к верхнему и верхнему к нижнему. Поскольку я совершенно новичок в этом, буквально не знаю, что делать. Любая помощь будет высоко оценена:)
Ответы
Ответ 1
Если вы поддерживаете только ASCII, вы можете принудительно ввести строчный код с помощью OR 0x20
or eax, 0x20
Аналогично, вы можете преобразовать букву в верхний регистр, очистив этот бит:
and eax, 0xBF ; or use ~0x20
И как упоминалось выше, случай символа может быть заменен с помощью команды XOR
:
xor eax, 0x20
Это работает только в том случае, если eax
находится между 'a' и 'z' или 'A' и 'Z', поэтому вам придется сравнивать и убедиться, что вы находитесь в диапазоне:
cmp eax, 'a'
jl .not-lower
cmp eax, 'z'
jg .not-lower
or eax, 0x20
.not-lower:
Я использовал синтаксис nasm. Возможно, вы захотите убедиться, что значения jl
и jg
тоже верны...
Если вам нужно преобразовать любой международный символ, то это намного сложнее, если вы не можете вызвать функцию libc tolower() или toupper(), которая принимает символы Unicode.
Как справедливый вопрос: зачем это работает? (спросил кухаку)
Символы ASCII (также ISO-8859-1) имеют основные символы верхнего регистра, определенные между 0x41 и 0x5A и строчными буквами между 0x61 и 0x7A.
Чтобы заставить 4 в 6 и 5 в 7, вы устанавливаете бит 5 (0x20).
Чтобы перейти в верхний регистр, вы делаете обратное, вы удаляете бит 5, чтобы он становился равным нулю.
Ответ 2
Хорошо, но ваша строка не находится в edx
, она находится в [ecx]
(или [In_Buffer]
) (и это только один полезный символ). Чтобы получить один символ...
mov al, [ecx]
В HLL вы делаете "если какое-то условие, выполните этот код". Вы можете задаться вопросом, как CPU знает, следует ли выполнять код или нет. То, что мы действительно делаем (HLLs делают это для вас), это "если НЕ условие, пропустите этот код" (на ярлык). Поэкспериментируйте с этим, вы поймете это.
Выйти чисто, независимо от того, какой путь ваш код. Вы не показываете это, но я предполагаю, что вы это делаете.
Я только что разместил информацию о sys_read
здесь.
Это для совершенно другой программы (добавление двух чисел - "шестнадцатеричных" чисел), но часть о sys_read
может вас заинтересовать...
Ответ 3
Симпатичный трюк: если они печатают только буквы, вы можете XOR их входные буквы с 0x20, чтобы обменять их.
Затем, если они могут печатать больше, чем буквы, вам просто нужно проверить каждую букву, чтобы увидеть, является ли она алфавитной, прежде чем XORing. Вы можете сделать это с помощью теста, чтобы определить, находится ли он в диапазонах от 'a' до 'z' или 'A' до 'Z', например.
В качестве альтернативы вы можете просто сопоставить каждую букву с таблицей из 256 элементов, которая отображает символы так, как вы их хотите (обычно такие функции, как toupper
, реализованы).
Ответ 4
Вот программа NASM, которую я взломал вместе, которая переворачивает случай строки, вам в основном нужно перебирать строку и проверять каждый символ для границ в ascii, а затем добавлять или вычитать 0x20
, чтобы изменить случай (то есть расстояние между верхним и нижним в ascii). Вы можете использовать команду Linux ascii
, чтобы увидеть таблицу значений ascii.
Файл: flipcase.asm
section .text
global _start ; Entry point for linker (ld)
; Linker entry point
_start:
mov rcx,len ; Place length of message into rcx
mov rbp,msg ; Place address of our msg into rbp
dec rbp ; Adjust count to offset
; Go through the buffer and convert lowercase to uppercase characters:
upperScan:
cmp byte [rbp+rcx],0x41 ; Test input char against uppercase 'A'
jb lowerScan ; Not uppercase Ascii < 0x41 ('A') - jump below
cmp byte [rbp+rcx],0x5A ; Test input char against uppercase 'Z'
ja lowerScan ; Not uppercase Ascii > 0x5A ('Z') - jump above
; At this point, we have a uppercase character
add byte [rbp+rcx],0x20 ; Add 0x20 to get the lowercase Ascii value
jmp Next ; Done, jump to next
lowerScan:
cmp byte [rbp+rcx],0x61 ; Test input char against lowercase
jb Next ; Not lowercase Ascii < 0x61 ('a') - jump below
cmp byte [rbp+rcx],0x7A ; Test input char against lowercase 'z'
ja Next ; Not lowercase Ascii > 0x7A ('z') - jump below
; At this point, we have a lowercase char
sub byte [rbp+rcx],0x20 ; Subtract 0x20 to get the uppercase Ascii value
; Fall through to next
Next:
dec rcx ; Decrement counter
jnz upperScan ; If characters remain, loop back
; Write the buffer full of processed text to stdout:
Write:
mov rbx,1 ; File descriptor 1 (stdout)
mov rax,4 ; System call number (sys_write)
mov rcx,msg ; Message to write
mov rdx,len ; Length of message to write
int 0x80 ; Call kernel interrupt
mov rax,1 ; System call number (sys_exit)
int 0x80 ; Call kernel
section .data
msg db 'hELLO, wwwoRLD!',0xa ; Our dear string
len equ $ - msg ; Length of our dear string
Затем вы можете скомпилировать и запустить его с помощью:
$> nasm -felf64 flipcase.asm && ld -melf_x86_64 -o flipcase flipcase.o && ./flipcase
Ответ 5
Jeff Duntemann написал книгу под названием "Язык поэтапного программирования ассемблера" с linux.., который очень хорошо освещает эту тему на стр. 275 - 277.
там он показывает, используя код sub byte [ebp+ecx], 20h
вы можете изменить нижний регистр на верхний регистр, обратите внимание, что буфер использует 1024 байта, что является более быстрым и лучшим способом сделать это, чем предыдущий пример, расположенный на стр. 268-269, где буфер имеет только 8 бит на время.