Skip to main content
Tweeted twitter.com/StackCodeReview/status/1603766929319149569
update wording, add tag
Source Link

I am a beginner in assembly and would like to know ways I could improve my code. I am talking more about assembly specific thingthings and less the logic (ege. Thatg. what I could've written better loops"), like loops

I am a beginner in assembly and would like to know ways I could improve my code. I am talking more about assembly specific thing and less the logic (eg. That I could've written better loops")

I am a beginner in assembly and would like to know ways I could improve my code. I am talking more about assembly specific things and less the logic e.g. what I could've written better, like loops

edited tags; final newline after code fence
Source Link
Toby Speight
  • 88.5k
  • 14
  • 104
  • 327
SECTION .data           ; Section containing initialised data
    Base64Table: db "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    OutBuf: db "xxxx"
    OutBufLen: equ $ - OutBuf

SECTION .bss            ; Section containing uninitialized data
    InBufLen: equ 3
    InBuf:    resb InBufLen

SECTION .text           ; Section containing code

global _start           ; Linker needs this to find the entry point!

_start:

read:
    ; read chunk from stdin to InBuf
    mov rax, 0                      ; sys_read
    mov rdi, 0                      ; file descriptor: stdin
    mov rsi, InBuf                  ; destination buffer
    mov rdx, InBufLen               ; maximum # of bytes to read
    syscall

    ; check number of bytes read
    cmp rax, 0                      ; did we receive any bytes?
    je exit; if not: exit the program

    xor r10, r10                    ; clear r10
    mov r10, rax                    ; save # of bytes read

    cmp rax, 2                      ; If only two bytes were read call specific subroutine
    je twobyte

    cmp rax, 1
    je onebyte

    ; clear r10, r11 and rax for future usage
    xor r11, r11
    xor rax, rax

process:
    mov eax, [InBuf]

    ; convert little endian to big endian and shifting right by 8 to remove 0x00
    ; which we only got because we saved a 24 bit value into a 32 bit register
    bswap eax                       ; example: 0x004e5089 -> 0x89504e00
    shr eax, 8                      ; example: 0x89504e00 -> 0x0089504e

    ; clean rdx and rbx to store values there and then copy eax into edx to use edx to shift the values around
    xor rdx, rdx
    xor rbx, rbx
    mov edx, eax

    ; Get second char in 3 byte chunk
    shr edx, 6                      ; move first char out of the way
    and edx, 0x3F                   ; mask 3 and 4 char
    mov bl, [Base64Table + rdx]     ; Lookup and add to ebx on the 4 place xxxx -> xxxV
    xor rdx, rdx                    ; clear rdx
    mov edx, eax                    ; fill edx with eax

    and edx, 0x3F                   ; get first char by masking all others
    mov bh, [Base64Table + rdx]     ; lookup and add to ebx on the 3 place xxxV -> xxiV
    xor rdx, rdx                    ; clear rdx
    mov edx, eax                    ; fill edx with eax

    shl ebx, 16                     ; move 3 and 4th place of ebx to first and second xxiV -> iVxx

    shr edx, 18                     ; move away 1st, 2nd and 3d char out of edx
    mov bl, [Base64Table + rdx]     ; look up remaining 4th char and add to ebx iVxx -> iVxB
    xor rdx, rdx                    ; clear rdx
    mov edx, eax                    ; fill edx with eax

    shr edx, 12                     ; move 1st and 2nd char out of edx
    and edx, 0x3F                   ; mask 4 char
    mov bh, [Base64Table + rdx]     ; look up remaining 3th char and add to 3th place in ebx iVxB -> iVOB

    mov [OutBuf + r11], ebx         ; move content of ebx to the output at the correct place (r11)
    push r11                        ; save r11
    push r10                        ; save r10
    call write                      ; write output
    pop r10                         ; get r10 back
    pop r11                         ; get r11 back

    add r11, 4                      ; add 4 to output index
    cmp r11, r10                    ; check if all data read in was processed yet by comparing the numbers of read in bytes to the index in the output
    jl process                      ; if r11 is lower, go to process

    jmp read                        ; else read new data

onebyte:
    ; Clear registers
    xor rdx, rdx
    xor rbx, rbx
    xor rax, rax

    ;Add two = and move them up 16 to make room for the last two chars
    mov bh, 0x3D
    mov bl, 0x3D
    shl ebx, 16

    mov eax, [InBuf]

    and eax, 0xFF                   ; Mask all other bytes except last one

    shl eax, 4                      ; Add 4 zeroes at the end

    mov edx, eax

    shr edx, 6                      ; move first char out of edx
    and edx, 0x3F                   ; mask everything except the remaining (second) 6 bites
    mov bl, [Base64Table + rdx]     ; Look up and write to bh
    xor rdx, rdx
    mov edx, eax

    and edx, 0x3F                   ; Mask second char away
    mov bh, [Base64Table + rdx]     ; Lookup first char and add to output

    ; Write and exit the programm
    mov [OutBuf], ebx
    call write
    jmp exit

twobyte: ;TODO Document
    ; Clear registers
    xor rdx, rdx
    xor rbx, rbx
    xor rax, rax


    mov eax, [InBuf]

    and eax, 0xFFFF                 ; Mask all other bytes except the two last ones

    bswap eax
    shr eax, 16                     ; bswap ax doesn't work so we have to do this manually

    shl eax, 2                      ; Add 2 zeroes at the end

    ; Add one =
    mov bh, 0x3D
    mov edx, eax

    and edx, 0x3F
    mov bl, [Base64Table + rdx]
    xor rdx, rdx
    mov edx, eax

    shl ebx, 16

    shr edx, 6
    and edx, 0x3F
    mov bh, [Base64Table + rdx]
    xor rdx, rdx
    mov edx, eax

    shr edx, 12
    and edx, 0x3F
    mov bl, [Base64Table + rdx]

    ; Write and exit the programm
    mov [OutBuf], ebx
    call write
    jmp exit

write: ;TODO Document
   mov rax, 1
   mov rdi, 1
   mov rsi, OutBuf
   mov rdx, OutBufLen
   syscall
   ret

exit: ;TODO Document
    mov rdi, 0
    mov rax, 60
    syscall
```
SECTION .data           ; Section containing initialised data
    Base64Table: db "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    OutBuf: db "xxxx"
    OutBufLen: equ $ - OutBuf

SECTION .bss            ; Section containing uninitialized data
    InBufLen: equ 3
    InBuf:    resb InBufLen

SECTION .text           ; Section containing code

global _start           ; Linker needs this to find the entry point!

_start:

read:
    ; read chunk from stdin to InBuf
    mov rax, 0                      ; sys_read
    mov rdi, 0                      ; file descriptor: stdin
    mov rsi, InBuf                  ; destination buffer
    mov rdx, InBufLen               ; maximum # of bytes to read
    syscall

    ; check number of bytes read
    cmp rax, 0                      ; did we receive any bytes?
    je exit; if not: exit the program

    xor r10, r10                    ; clear r10
    mov r10, rax                    ; save # of bytes read

    cmp rax, 2                      ; If only two bytes were read call specific subroutine
    je twobyte

    cmp rax, 1
    je onebyte

    ; clear r10, r11 and rax for future usage
    xor r11, r11
    xor rax, rax

process:
    mov eax, [InBuf]

    ; convert little endian to big endian and shifting right by 8 to remove 0x00
    ; which we only got because we saved a 24 bit value into a 32 bit register
    bswap eax                       ; example: 0x004e5089 -> 0x89504e00
    shr eax, 8                      ; example: 0x89504e00 -> 0x0089504e

    ; clean rdx and rbx to store values there and then copy eax into edx to use edx to shift the values around
    xor rdx, rdx
    xor rbx, rbx
    mov edx, eax

    ; Get second char in 3 byte chunk
    shr edx, 6                      ; move first char out of the way
    and edx, 0x3F                   ; mask 3 and 4 char
    mov bl, [Base64Table + rdx]     ; Lookup and add to ebx on the 4 place xxxx -> xxxV
    xor rdx, rdx                    ; clear rdx
    mov edx, eax                    ; fill edx with eax

    and edx, 0x3F                   ; get first char by masking all others
    mov bh, [Base64Table + rdx]     ; lookup and add to ebx on the 3 place xxxV -> xxiV
    xor rdx, rdx                    ; clear rdx
    mov edx, eax                    ; fill edx with eax

    shl ebx, 16                     ; move 3 and 4th place of ebx to first and second xxiV -> iVxx

    shr edx, 18                     ; move away 1st, 2nd and 3d char out of edx
    mov bl, [Base64Table + rdx]     ; look up remaining 4th char and add to ebx iVxx -> iVxB
    xor rdx, rdx                    ; clear rdx
    mov edx, eax                    ; fill edx with eax

    shr edx, 12                     ; move 1st and 2nd char out of edx
    and edx, 0x3F                   ; mask 4 char
    mov bh, [Base64Table + rdx]     ; look up remaining 3th char and add to 3th place in ebx iVxB -> iVOB

    mov [OutBuf + r11], ebx         ; move content of ebx to the output at the correct place (r11)
    push r11                        ; save r11
    push r10                        ; save r10
    call write                      ; write output
    pop r10                         ; get r10 back
    pop r11                         ; get r11 back

    add r11, 4                      ; add 4 to output index
    cmp r11, r10                    ; check if all data read in was processed yet by comparing the numbers of read in bytes to the index in the output
    jl process                      ; if r11 is lower, go to process

    jmp read                        ; else read new data

onebyte:
    ; Clear registers
    xor rdx, rdx
    xor rbx, rbx
    xor rax, rax

    ;Add two = and move them up 16 to make room for the last two chars
    mov bh, 0x3D
    mov bl, 0x3D
    shl ebx, 16

    mov eax, [InBuf]

    and eax, 0xFF                   ; Mask all other bytes except last one

    shl eax, 4                      ; Add 4 zeroes at the end

    mov edx, eax

    shr edx, 6                      ; move first char out of edx
    and edx, 0x3F                   ; mask everything except the remaining (second) 6 bites
    mov bl, [Base64Table + rdx]     ; Look up and write to bh
    xor rdx, rdx
    mov edx, eax

    and edx, 0x3F                   ; Mask second char away
    mov bh, [Base64Table + rdx]     ; Lookup first char and add to output

    ; Write and exit the programm
    mov [OutBuf], ebx
    call write
    jmp exit

twobyte: ;TODO Document
    ; Clear registers
    xor rdx, rdx
    xor rbx, rbx
    xor rax, rax


    mov eax, [InBuf]

    and eax, 0xFFFF                 ; Mask all other bytes except the two last ones

    bswap eax
    shr eax, 16                     ; bswap ax doesn't work so we have to do this manually

    shl eax, 2                      ; Add 2 zeroes at the end

    ; Add one =
    mov bh, 0x3D
    mov edx, eax

    and edx, 0x3F
    mov bl, [Base64Table + rdx]
    xor rdx, rdx
    mov edx, eax

    shl ebx, 16

    shr edx, 6
    and edx, 0x3F
    mov bh, [Base64Table + rdx]
    xor rdx, rdx
    mov edx, eax

    shr edx, 12
    and edx, 0x3F
    mov bl, [Base64Table + rdx]

    ; Write and exit the programm
    mov [OutBuf], ebx
    call write
    jmp exit

write: ;TODO Document
   mov rax, 1
   mov rdi, 1
   mov rsi, OutBuf
   mov rdx, OutBufLen
   syscall
   ret

exit: ;TODO Document
    mov rdi, 0
    mov rax, 60
    syscall
```
SECTION .data           ; Section containing initialised data
    Base64Table: db "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    OutBuf: db "xxxx"
    OutBufLen: equ $ - OutBuf

SECTION .bss            ; Section containing uninitialized data
    InBufLen: equ 3
    InBuf:    resb InBufLen

SECTION .text           ; Section containing code

global _start           ; Linker needs this to find the entry point!

_start:

read:
    ; read chunk from stdin to InBuf
    mov rax, 0                      ; sys_read
    mov rdi, 0                      ; file descriptor: stdin
    mov rsi, InBuf                  ; destination buffer
    mov rdx, InBufLen               ; maximum # of bytes to read
    syscall

    ; check number of bytes read
    cmp rax, 0                      ; did we receive any bytes?
    je exit; if not: exit the program

    xor r10, r10                    ; clear r10
    mov r10, rax                    ; save # of bytes read

    cmp rax, 2                      ; If only two bytes were read call specific subroutine
    je twobyte

    cmp rax, 1
    je onebyte

    ; clear r10, r11 and rax for future usage
    xor r11, r11
    xor rax, rax

process:
    mov eax, [InBuf]

    ; convert little endian to big endian and shifting right by 8 to remove 0x00
    ; which we only got because we saved a 24 bit value into a 32 bit register
    bswap eax                       ; example: 0x004e5089 -> 0x89504e00
    shr eax, 8                      ; example: 0x89504e00 -> 0x0089504e

    ; clean rdx and rbx to store values there and then copy eax into edx to use edx to shift the values around
    xor rdx, rdx
    xor rbx, rbx
    mov edx, eax

    ; Get second char in 3 byte chunk
    shr edx, 6                      ; move first char out of the way
    and edx, 0x3F                   ; mask 3 and 4 char
    mov bl, [Base64Table + rdx]     ; Lookup and add to ebx on the 4 place xxxx -> xxxV
    xor rdx, rdx                    ; clear rdx
    mov edx, eax                    ; fill edx with eax

    and edx, 0x3F                   ; get first char by masking all others
    mov bh, [Base64Table + rdx]     ; lookup and add to ebx on the 3 place xxxV -> xxiV
    xor rdx, rdx                    ; clear rdx
    mov edx, eax                    ; fill edx with eax

    shl ebx, 16                     ; move 3 and 4th place of ebx to first and second xxiV -> iVxx

    shr edx, 18                     ; move away 1st, 2nd and 3d char out of edx
    mov bl, [Base64Table + rdx]     ; look up remaining 4th char and add to ebx iVxx -> iVxB
    xor rdx, rdx                    ; clear rdx
    mov edx, eax                    ; fill edx with eax

    shr edx, 12                     ; move 1st and 2nd char out of edx
    and edx, 0x3F                   ; mask 4 char
    mov bh, [Base64Table + rdx]     ; look up remaining 3th char and add to 3th place in ebx iVxB -> iVOB

    mov [OutBuf + r11], ebx         ; move content of ebx to the output at the correct place (r11)
    push r11                        ; save r11
    push r10                        ; save r10
    call write                      ; write output
    pop r10                         ; get r10 back
    pop r11                         ; get r11 back

    add r11, 4                      ; add 4 to output index
    cmp r11, r10                    ; check if all data read in was processed yet by comparing the numbers of read in bytes to the index in the output
    jl process                      ; if r11 is lower, go to process

    jmp read                        ; else read new data

onebyte:
    ; Clear registers
    xor rdx, rdx
    xor rbx, rbx
    xor rax, rax

    ;Add two = and move them up 16 to make room for the last two chars
    mov bh, 0x3D
    mov bl, 0x3D
    shl ebx, 16

    mov eax, [InBuf]

    and eax, 0xFF                   ; Mask all other bytes except last one

    shl eax, 4                      ; Add 4 zeroes at the end

    mov edx, eax

    shr edx, 6                      ; move first char out of edx
    and edx, 0x3F                   ; mask everything except the remaining (second) 6 bites
    mov bl, [Base64Table + rdx]     ; Look up and write to bh
    xor rdx, rdx
    mov edx, eax

    and edx, 0x3F                   ; Mask second char away
    mov bh, [Base64Table + rdx]     ; Lookup first char and add to output

    ; Write and exit the programm
    mov [OutBuf], ebx
    call write
    jmp exit

twobyte: ;TODO Document
    ; Clear registers
    xor rdx, rdx
    xor rbx, rbx
    xor rax, rax


    mov eax, [InBuf]

    and eax, 0xFFFF                 ; Mask all other bytes except the two last ones

    bswap eax
    shr eax, 16                     ; bswap ax doesn't work so we have to do this manually

    shl eax, 2                      ; Add 2 zeroes at the end

    ; Add one =
    mov bh, 0x3D
    mov edx, eax

    and edx, 0x3F
    mov bl, [Base64Table + rdx]
    xor rdx, rdx
    mov edx, eax

    shl ebx, 16

    shr edx, 6
    and edx, 0x3F
    mov bh, [Base64Table + rdx]
    xor rdx, rdx
    mov edx, eax

    shr edx, 12
    and edx, 0x3F
    mov bl, [Base64Table + rdx]

    ; Write and exit the programm
    mov [OutBuf], ebx
    call write
    jmp exit

write: ;TODO Document
   mov rax, 1
   mov rdi, 1
   mov rsi, OutBuf
   mov rdx, OutBufLen
   syscall
   ret

exit: ;TODO Document
    mov rdi, 0
    mov rax, 60
    syscall
Source Link
Jocomol
  • 153
  • 4

Base64 Encoder in Assembly X86-64

I am a beginner in assembly and would like to know ways I could improve my code. I am talking more about assembly specific thing and less the logic (eg. That I could've written better loops")

SECTION .data           ; Section containing initialised data
    Base64Table: db "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    OutBuf: db "xxxx"
    OutBufLen: equ $ - OutBuf

SECTION .bss            ; Section containing uninitialized data
    InBufLen: equ 3
    InBuf:    resb InBufLen

SECTION .text           ; Section containing code

global _start           ; Linker needs this to find the entry point!

_start:

read:
    ; read chunk from stdin to InBuf
    mov rax, 0                      ; sys_read
    mov rdi, 0                      ; file descriptor: stdin
    mov rsi, InBuf                  ; destination buffer
    mov rdx, InBufLen               ; maximum # of bytes to read
    syscall

    ; check number of bytes read
    cmp rax, 0                      ; did we receive any bytes?
    je exit; if not: exit the program

    xor r10, r10                    ; clear r10
    mov r10, rax                    ; save # of bytes read

    cmp rax, 2                      ; If only two bytes were read call specific subroutine
    je twobyte

    cmp rax, 1
    je onebyte

    ; clear r10, r11 and rax for future usage
    xor r11, r11
    xor rax, rax

process:
    mov eax, [InBuf]

    ; convert little endian to big endian and shifting right by 8 to remove 0x00
    ; which we only got because we saved a 24 bit value into a 32 bit register
    bswap eax                       ; example: 0x004e5089 -> 0x89504e00
    shr eax, 8                      ; example: 0x89504e00 -> 0x0089504e

    ; clean rdx and rbx to store values there and then copy eax into edx to use edx to shift the values around
    xor rdx, rdx
    xor rbx, rbx
    mov edx, eax

    ; Get second char in 3 byte chunk
    shr edx, 6                      ; move first char out of the way
    and edx, 0x3F                   ; mask 3 and 4 char
    mov bl, [Base64Table + rdx]     ; Lookup and add to ebx on the 4 place xxxx -> xxxV
    xor rdx, rdx                    ; clear rdx
    mov edx, eax                    ; fill edx with eax

    and edx, 0x3F                   ; get first char by masking all others
    mov bh, [Base64Table + rdx]     ; lookup and add to ebx on the 3 place xxxV -> xxiV
    xor rdx, rdx                    ; clear rdx
    mov edx, eax                    ; fill edx with eax

    shl ebx, 16                     ; move 3 and 4th place of ebx to first and second xxiV -> iVxx

    shr edx, 18                     ; move away 1st, 2nd and 3d char out of edx
    mov bl, [Base64Table + rdx]     ; look up remaining 4th char and add to ebx iVxx -> iVxB
    xor rdx, rdx                    ; clear rdx
    mov edx, eax                    ; fill edx with eax

    shr edx, 12                     ; move 1st and 2nd char out of edx
    and edx, 0x3F                   ; mask 4 char
    mov bh, [Base64Table + rdx]     ; look up remaining 3th char and add to 3th place in ebx iVxB -> iVOB

    mov [OutBuf + r11], ebx         ; move content of ebx to the output at the correct place (r11)
    push r11                        ; save r11
    push r10                        ; save r10
    call write                      ; write output
    pop r10                         ; get r10 back
    pop r11                         ; get r11 back

    add r11, 4                      ; add 4 to output index
    cmp r11, r10                    ; check if all data read in was processed yet by comparing the numbers of read in bytes to the index in the output
    jl process                      ; if r11 is lower, go to process

    jmp read                        ; else read new data

onebyte:
    ; Clear registers
    xor rdx, rdx
    xor rbx, rbx
    xor rax, rax

    ;Add two = and move them up 16 to make room for the last two chars
    mov bh, 0x3D
    mov bl, 0x3D
    shl ebx, 16

    mov eax, [InBuf]

    and eax, 0xFF                   ; Mask all other bytes except last one

    shl eax, 4                      ; Add 4 zeroes at the end

    mov edx, eax

    shr edx, 6                      ; move first char out of edx
    and edx, 0x3F                   ; mask everything except the remaining (second) 6 bites
    mov bl, [Base64Table + rdx]     ; Look up and write to bh
    xor rdx, rdx
    mov edx, eax

    and edx, 0x3F                   ; Mask second char away
    mov bh, [Base64Table + rdx]     ; Lookup first char and add to output

    ; Write and exit the programm
    mov [OutBuf], ebx
    call write
    jmp exit

twobyte: ;TODO Document
    ; Clear registers
    xor rdx, rdx
    xor rbx, rbx
    xor rax, rax


    mov eax, [InBuf]

    and eax, 0xFFFF                 ; Mask all other bytes except the two last ones

    bswap eax
    shr eax, 16                     ; bswap ax doesn't work so we have to do this manually

    shl eax, 2                      ; Add 2 zeroes at the end

    ; Add one =
    mov bh, 0x3D
    mov edx, eax

    and edx, 0x3F
    mov bl, [Base64Table + rdx]
    xor rdx, rdx
    mov edx, eax

    shl ebx, 16

    shr edx, 6
    and edx, 0x3F
    mov bh, [Base64Table + rdx]
    xor rdx, rdx
    mov edx, eax

    shr edx, 12
    and edx, 0x3F
    mov bl, [Base64Table + rdx]

    ; Write and exit the programm
    mov [OutBuf], ebx
    call write
    jmp exit

write: ;TODO Document
   mov rax, 1
   mov rdi, 1
   mov rsi, OutBuf
   mov rdx, OutBufLen
   syscall
   ret

exit: ;TODO Document
    mov rdi, 0
    mov rax, 60
    syscall
```