X86 NASM程序集将低级字符串转换为大写字母和大写字母

时间:2014-02-27 03:02:49

标签: assembly x86 nasm

由于我对汇编很新,所以如果用户在汇编中输入大写字母或反之亦然,我有一些关于如何从小写转换为大写的问题。这是我到目前为止所做的:

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包含输入的字符串。现在出现了从低级到高级,从大写到小写的困境。因为我对此非常陌生,所以根本不知道该怎么做。任何帮助将不胜感激:))

5 个答案:

答案 0 :(得分:5)

如果您只支持ASCII,则可以使用OR 0x20

强制使用小写
  or   eax, 0x20

同样,您可以通过清除该位将字母转换为大写:

  and  eax, 0xBF   ; or use ~0x20

正如nneonneo所提到的,可以使用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语法。您可能还需要确保jljg也正确...

如果你需要转换任何国际字符,那么除非你可以调用接受Unicode字符的libc tolower()或toupper()函数,否则这样做会复杂得多。


作为一个公平的问题:它为什么会起作用? (kuhaku问道)

ASCII字符(也是ISO-8859-1)在0x41和0x5A之间定义了基本的大写字符,在0x61和0x7A之间定义了小写字符。

要强制4进6和5进7,强制设置第5位(0x20)。

要转到大写,你做相反的事情,你删除第5位使它变为零。

答案 1 :(得分:3)

好的,但是你的字符串不在edx中,而是在[ecx](或[In_Buffer])中(并且它只是一个有用的字符)。获得一个角色......

mov al, [ecx]

在HLL中,您执行“如果有某些条件,请执行此代码”。您可能想知道CPU是如何知道是否执行代码。我们真正做的事情(HLL为你做这个)是“如果没有条件,跳过这个代码”(到标签)。试验一下,你会弄明白的。

干净利落地退出代码所需的任何路径。你没有表现出来,但我认为你这样做了。

我刚刚在sys_read here上发布了一些信息。

这是一个完全不同的程序(添加两个数字 - “十六进制”数字),但关于sys_read的部分可能会让您感兴趣...

答案 2 :(得分:0)

可爱的技巧:如果他们只输入 字母,你可以用0x20对他们的输入字母进行异或交换。

然后,如果他们可以输入多个字母,你只需要检查每个字母,看它是否是字母顺序,然后再进行异或。例如,您可以通过测试来查看它是否位于“a”到“z”或“A”到“Z”的范围内。

或者,您可以通过256个元素的表格映射每个字母,该表格按照您希望的方式映射字符(例如,这通常是toupper等函数的实现方式。)

答案 3 :(得分:0)

这是我一起攻击的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

答案 4 :(得分:0)

杰夫·丹特曼(Jeff Duntemann)写了一本名为汇编语言的汇编语言逐步编程的书......在第275-277页中很好地介绍了这个主题。

他使用代码sub byte [ebp+ecx], 20h显示 然后您可以将小写更改为大写,请注意缓冲区使用1024个字节,这是一个更快更好的方法,然后上一个示例位于第268-269页,其中缓冲区只有8位时间。