A good example of a widely used, yet simple, array would be a forward substitution table and/or a reverse substitution table used with the AES algorithm:
aes_sbox:
db 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5
db 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76
db 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0
db 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0
db 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc
db 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15
db 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a
db 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75
db 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0
db 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84
db 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b
db 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf
db 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85
db 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8
db 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5
db 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2
db 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17
db 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73
db 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88
db 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb
db 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c
db 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79
db 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9
db 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08
db 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6
db 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a
db 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e
db 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e
db 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94
db 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf
db 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68
db 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
As we may clearly see, all values have a size of 1 byte and are stored sequentially one after the other. Accessing such arrays is very simple and may even be performed with the XLAT instruction. For example, imagine that we are in the middle of an AES-128 calculation and we have a value in which we need to substitute each byte with a byte from the preceding table. Let the following be the value:
needs_substitution db 0, 1, 2, 3, 4, 5, 6, 7\
8, 9, 10, 11, 12, 13, 14, 15
The following code would do the substitution:
lea ebx, [aes_sbox]
lea esi, [needs_substitution] ; Set the source pointer (ESI) and
mov edi, esi ; destination pointer (EDI) as we
; will be storing substituted
; byte back
mov ecx, 0x10 ; Set the counter
@@:
lodsb ; Load byte from the value
xlatb ; Substitute byte from the s-box
stosb ; Store new byte to the value
loop @b ; Loop while ECX != 1
The first thing we do is load the base address of the table (of the s-box) into the EBX register, as the XLAT instruction uses exactly this register for addressing the substitution/lookup table. Then, we load the address of the array of values requiring
substitution into the ESI register in order to not bother with index computations, as the ESI register is automatically incremented by the lodsb instruction. Duplicate the address into the EDI register, as we will be storing data back.
We then sequentially read each byte of the value, substitute it with a byte form the s-box with the XLAT instruction, and store the result back. As an alternative to the XLAT instruction (which is limited to 256 byte tables and may only operate on byte values depending on the AL register), we can write the following:
mov al, [aes_sbox + eax] ; aes_sbox is the base and EAX is the index
However, we would have needed to set the whole EAX register to 0 prior to entering the loop, while XLAT allows the upper 24 bits of the EAX register to remain unchanged throughout the whole operation.