I am new to Assembly.
And I have this code
section .data ; we define (global) initialized variables in .data section
an: dd 0 ; an is a local variable of size double-word, we use it to count the string characters
section .text ; we write code in .text section
global do_Str ; 'global' directive causes the function do_Str(...) to appear in global scope
section .text ; we write code in .text section
global do_Str ; 'global' directive causes the function do_Str(...) to appear in global scope
do_Str: ; do_Str function definition - functions are defined as labels
push ebp ; save Base Pointer (bp) original value
mov ebp, esp ; use Base Pointer to access stack contents (do_Str(...) activation frame)
pushad ; push all signficant registers onto stack (backup registers values)
mov ecx, dword [ebp+8] ; get function argument on stack
; now ecx register points to the input string
yourCode: ; use label to build a loop for treating the input string characters
cmp byte [ecx], ' '
JE updateAndCount
inc ecx ; increment ecx value; now ecx points to the next character of the string
cmp byte [ecx], 0 ; check if the next character (character = byte) is zero (i.e. null string termination)
jnz yourCode ; if not, keep looping until meet null termination character
updateAndCount:
mov byte [ecx], '_'
inc dword[an]
ret
popad ; restore all previously used registers
mov eax,[an] ; return an (returned values are in eax)
mov esp, ebp ; free function activation frame
pop ebp ; restore Base Pointer previous value (to returnt to the activation frame of main(...))
ret ; returns from do_Str(...) function
but when running it(I have c code calling it), I get this error:
Segmentation fault (core dumped)
I know it has something to do with the return from updateAndCount, but I'm not sure how to fix it.
Expanding from my comments with an example.
The snippet starting with the updateAndCount
label mustn't end with ret
, it should jump (or fall through) to where you want your loop to continue. That is not the only control flow error you did however. After the jnz yourCode
you probably want an unconditional jump to the function epilogue (which starts with popad
). Or move the epilogue around to follow directly behind the jnz yourCode
and then let it fall through if the jnz
does not jump.
Moreover you did not initialise the an
variable in the function so it will act like a static variable in C, that is if your function is called repeatedly an
will keep incrementing and not be reset when your function is called subsequently. This may be intentional but you did not specify which behaviour is intended. Besides, yourCode
is an exceptionally undescriptive label. I'd recommend replacing it by .loop
-- the leading dot makes it alocal label for NASM . The name is to describe the intention of that jump target.
Here's an example correcting the control flow, initialising the an
variable, and changing the labels to descriptive and local labels. I will not optimise the program beyond that, nor make it threadsafe (which it isn't due to the global variable).
section .data ; we define (global) initialized variables in .data section
an: dd 0 ; an is a local variable of size double-word, we use it to count the string characters
section .text ; we write code in .text section
global do_Str ; 'global' directive causes the function do_Str(...) to appear in global scope
do_Str: ; do_Str function definition - functions are defined as labels
push ebp ; save Base Pointer (bp) original value
mov ebp, esp ; use Base Pointer to access stack contents (do_Str(...) activation frame)
pushad ; push all signficant registers onto stack (backup registers values)
mov dword [an], 0
;;; continues in the next code block
;;; all the code blocks in this answer combine to one function with one loop
This zero-initialises the variable to zero. (I'd use and
with zero personally, which is slightly shorter than mov
with a zero immediate number. But for clarity we'll use mov
.)
mov ecx, dword [ebp+8] ; get function argument on stack
; now ecx register points to the input string
jmp .first
This unconditional jump fixes another logic error. If the very first byte in the string is a NUL byte we should most likely honour it, not continue to process whatever follows after it.
.loop: ; use label to build a loop for treating the input string characters
cmp byte [ecx], ' '
jne .do_not_updateAndCount
I inverted the condition code of the jump. Now it jumps if we don't want to run the .updateAndCount
part.
.updateAndCount:
mov byte [ecx], '_'
inc dword [an]
I kept your label (now local with the leading dot) even though it is not referenced anywhere. It can serve as a comment for what this block is supposed to do, however.
Crucially, the control flow falls through after the end of the .updateAndCount
block here. Equivalently, you could add an unconditional jmp .next
at the end to jump (back) into the loop. If you moved around the .updateAndCount
block (eg to behind the epilogue's ret
) then this jmp .next
would be required.
.do_not_updateAndCount:
.next:
inc ecx ; increment ecx value; now ecx points to the next character of the string
.first:
cmp byte [ecx], 0 ; check if the next character (character = byte) is zero (i.e. null string termination)
jnz .loop ; if not, keep looping until meet null termination character
popad ; restore all previously used registers
mov eax, [an] ; return an (returned values are in eax)
mov esp, ebp ; free function activation frame
pop ebp ; restore Base Pointer previous value (to returnt to the activation frame of main(...))
ret ; returns from do_Str(...) function
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.