xlat指令用于从内存的转换表读入一个字节更新al寄存器的内容。在指令执行前,要求al寄存器保存转换表的索引值,ebx寄存器保存转换表的起始地址。
《Assembly Language step by step programming with linux》第9章有一个使用这个指令的示例程序,此程序仍然用于把小写字母转换成大写字母:
SECTION .data ; Section containing initialised data
StatMsg: db "Processing...",10
StatLen: equ $-StatMsg
DoneMsg: db "...done!",10
DoneLen: equ $-DoneMsg
; The following translation table translates all lowercase characters to
; uppercase. It also translates all non-printable characters to spaces,
; except for LF and HT.
UpCase:
db 20h,20h,20h,20h,20h,20h,20h,20h,20h,09h,0Ah,20h,20h,20h,20h,20h
db 20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h
db 20h,21h,22h,23h,24h,25h,26h,27h,28h,29h,2Ah,2Bh,2Ch,2Dh,2Eh,2Fh
db 30h,31h,32h,33h,34h,35h,36h,37h,38h,39h,3Ah,3Bh,3Ch,3Dh,3Eh,3Fh
db 40h,41h,42h,43h,44h,45h,46h,47h,48h,49h,4Ah,4Bh,4Ch,4Dh,4Eh,4Fh
db 50h,51h,52h,53h,54h,55h,56h,57h,58h,59h,5Ah,5Bh,5Ch,5Dh,5Eh,5Fh
db 60h,41h,42h,43h,44h,45h,46h,47h,48h,49h,4Ah,4Bh,4Ch,4Dh,4Eh,4Fh
db 50h,51h,52h,53h,54h,55h,56h,57h,58h,59h,5Ah,7Bh,7Ch,7Dh,7Eh,20h
db 20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h
db 20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h
db 20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h
db 20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h
db 20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h
db 20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h
db 20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h
db 20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h,20h
SECTION .bss ; Section containing uninitialized data
READLEN equ 1024 ; Length of buffer
ReadBuffer: resb READLEN ; Text buffer itself
SECTION .text ; Section containing code
global _start ; Linker needs this to find the entry point!
_start:
nop ; This no-op keeps gdb happy...
; Display the "Processing..." message via stderr:
mov eax,4 ; Specify sys_write call
mov ebx,2 ; Specify File Descriptor 2: Standard error
mov ecx,StatMsg ; Pass offset of the message
mov edx,StatLen ; Pass the length of the message
int 80h ; Make kernel call
; Read a buffer full of text from stdin:
read:
mov eax,3 ; Specify sys_read call
mov ebx,0 ; Specify File Descriptor 0: Standard Input
mov ecx,ReadBuffer ; Pass offset of the buffer to read to
mov edx,READLEN ; Pass number of bytes to read at one pass
int 80h
mov ebp,eax ; Copy sys_read return value for safekeeping
cmp eax,0 ; If eax=0, sys_read reached EOF
jle done ; Jump If equal or below (to 0, from compare)
; Set up the registers for the translate step:
mov ebx,UpCase ; Place the offset of the table into ebx
mov edx,ReadBuffer ; Place the offset of the buffer into edx
mov ecx,ebp ; Place the number of bytes in the buffer into ecx
; Use the xlat instruction to translate the data in the buffer:
translate:
mov al,byte [edx+ecx-1] ; Load character into AL for translation
xlat ; Translate character in AL via table
mov byte [edx+ecx-1],al ; Put the translated character back in the buffer
dec ecx ; Decrement character count
jnz translate ; If there are more chars in the buffer, repeat
; Write the buffer full of translated text to stdout:
write:
mov eax,4 ; Specify sys_write call
mov ebx,1 ; Specify File Descriptor 1: Standard output
mov ecx,ReadBuffer ; Pass offset of the buffer
mov edx,ebp ; Pass the # of bytes of data in the buffer
int 80h ; Make kernel call
jmp read ; Loop back and load another buffer full
; Display the "...done!" message via stderr:
done:
mov eax,4 ; Specify sys_write call
mov ebx,2 ; Specify File Descriptor 2: Standard error
mov ecx,DoneMsg ; Pass offset of the message
mov edx,DoneLen ; Pass the length of the message
int 80h ; Make kernel call
; All done! Let's end this party:
mov eax,1 ; Code for Exit Syscall
mov ebx,0 ; Return a code of zero
int 80H ; Make kernel call
程序分析:
UpCase是一个字节数组,此数组用于把小写字母转换成大写字母。
mov ebx, UpCase //ebx=UpCase,ebx保存转换表的起始地址
mov edx, ReadBuffer //edx=ReadBuffer,edx保存读入缓存的起始地址
mov ecx, ebp //ecx=读入缓存的字节数,ecx用于循环计数
translate:
mov al, byte [edx+ecx-1] //al=edx[ecx-1],al保存的是输入字符的ASCII值,从最后一个输入字符开始转换。
xlat //指令执行结果,是al= UpCase[al]
mov byte [edx+ecx-1], al //放回转换的这个字节到edx[ecx-1]
dec ecx //ecx减1
jnz translate //如果ecx不等于0,跳转到translate继续循环。
makefile文件如下:
xlat1: xlat1.o
ld-o xlat1 xlat1.o
xlat1.o: xlat1.asm
nasm-f elf -g -F stabs xlat1.asm
测试:
[root@bogon xlat1]# make
nasm -f elf -g -F stabs xlat1.asm
ld -o xlat1 xlat1.o
[root@bogon xlat1]# ./xlat1
Processing...
a
A
abc
ABC
...done!