I’m trying to learn assembly (Intel x86 with NASM on Linux) and unsurprisingly I’m having some trouble.
The following is meant to take a buffer of text, remove all spaces and put the result in another buffer. It’s part of a larger project I’m doing as a way to learn, and I’m developing each part individually first. In the actual project the message is going to come from a file, here I’m just using a hardcoded string (Msg) for testing purposes.
But it’s not working. I’ve been fiddling with it for a while now, but I’m sure I’ve missed some fundamental concept somewhere or something.
[SECTION .data]
Msg db ' %d Whitespace, thanks ', 10, 0
[SECTION .bss]
BUFFSIZE equ 80
BufferA resb BUFFSIZE
BufferB resb BUFFSIZE
[SECTION .text]
extern printf
global main
; PROCEDURE stripwhite
; INPUT None
; OUTPUT None
; NOTES Strips all leading and trailing whitespace from BufferA
; Result is stored in BufferB
stripwhite:
pushad ; Save caller's registers
mov eax, BufferA ; Source string
mov ebx, BufferB ; Output string
.loop:
mov cl, byte [eax] ; Get a single character from the source
cmp cl, 0
je .end ; End if character is null
cmp cl, 32
jne .save ; Save it if it's not a space
add eax, 1 ; Otherwhise skip to next character
jmp .loop
.save:
mov byte [ebx], cl ; Save character in output buffer
add eax, 1 ; Move on to next character
add ebx, 1
jmp .loop
.end:
mov byte [ebx], 0 ; Add a null at the end
popad ; Restore caller's registers
ret
main:
push ebp ; Set up stack frame for debugger
mov ebp, esp
push ebx ; Must preserve ebp, ebx, esi and edi
push esi
push edi
; start
mov dword [BufferA], Msg
call stripwhite
push 0
push BufferB ; Push message string
call printf ; Print line count
add esp, 8 ; Clean up the stack
; end
pop edi ; Restore saved registers
pop esi
pop ebx
mov esp, ebp ; Destroy stack frame
pop ebp
ret
I’m kinda wondering why it seems I have to use dword in the line before call stripwhite above when both Msg and the two buffers use bytes, but the linker (called by GCC in this case) throws an error when I use anything else:
stripwhite.o:stripwhite.asm:82: relocation truncated to fit: R_386_8 against `.data'
collect2: ld returned 1 exit status
Maybe that has something to do with it, but I can’t figure out what.
The following seems to work just fine, and it’s basically identical except the code is not inside a procedure.
[SECTION .data]
Msg db ' %d Whitespace, thanks ', 10, 0
[SECTION .bss]
BUFFSIZE equ 80
BufferA resb BUFFSIZE
BufferB resb BUFFSIZE
[SECTION .text]
extern printf
global main
main:
push ebp ; Set up stack frame for debugger
mov ebp, esp
push ebx ; Must preserve ebp, ebx, esi and edi
push esi
push edi
; start
mov eax, Msg
mov ebx, BufferB
.loop:
mov cl, byte [eax]
cmp cl, 0
je .end
cmp cl, 32
jne .save
add eax, 1
jmp .loop
.save:
mov byte [ebx], cl
add eax, 1
add ebx, 1
jmp .loop
.end:
mov byte [ebx], 0
push 0
push BufferB ; Push message string
call printf ; Print line count
add esp, 8 ; Clean up the stack
; end
pop edi ; Restore saved registers
pop esi
pop ebx
mov esp, ebp ; Destroy stack frame
pop ebp
ret
BufferAis an array.This is putting the address of
Msgin the first 4 bytes ofBufferA, probably not what you want. You could callmemcpyinstead.