Using NASM, I need to change a character in a string at a given index and print the string in its new form. Here is a simplified version of my code:
;test_code.asm
global main
extern printf
output_str: db "----------"
index: dq 7
main:
push rbp
mov rdi, output_str
mov rax, index
mov byte[rdi + rax], 'x'
xor rax, rax
call printf
pop rbp
ret
I then compile using:
nasm -felf64 test_code.asm && gcc test_code.o -lm
and get a seg fault. Would someone please point out the flaw here? I can't seem to find it myself.
your string is in the .text section of the executable, which is read only by default. Either you allocate a buffer on the stack, copy the string and you modify it there, or you put the string in the .data section (which is read/write) using the section directive. In this last case, notice that the character replacement will be persistent, i.e. even later in the program the string will remain modified;
if you want to print that string with printf it has to be NUL-terminated. Add a ,0 to the end of the db line;
that mov rax, index is wrong - index is the address of the qword you wrote above, while you actually want to copy in rax the datum wrote there; you probably want mov rax, [index].
So, something like
;test_code.asm
global main
extern printf
section .data
output_str:
db "----------",0
section .text
index:
dq 7
main:
push rbp
mov rdi, output_str
mov rax, [index]
mov byte[rdi + rax], 'x'
xor rax, rax
call printf
pop rbp
ret
Related
I am trying to use the strstr C function in a NASM assembly program but cannot seem to get it to print out correctly. I have tried multiple variations of this, but I think I may be misinterpreting how NASM returns the pointer value from C as I either get a blank line returned in the printf or a '(null)'. Could some help fill me in as why I cannot get the correct return value to be printed?
section .data
str1 db "Here is some text with a word",0x0A,0x00
str2 db "text",0x0A, 0x00
strFmt db "%s",0x0A,0x00
global _start
extern printf
extern strstr
section .text
_start:
push ebp
mov ebp, esi
push str2
push str1
call strstr
add esp, 8
mov dword [myString], eax
push dword [myString]
push strFmt
call printf
add esp, 8
_exit:
mov ebx, 0
mov eax, 1
int 0x80
The main issue is the 0x0A in the search string. It's a part of the string, as everything before the terminating null is a part of it. It must be listed separately because C-style escape sequences inside strings won't be resolved by the assembler. A "test\n" won't be found by strstr. Remove the 0x0A and strstr will found the search string.
As Cody Gray mentioned, the block with mov ebp, esi is strange—you probably meant the idiomatic mov ebp, esp. Moreover, it's not needed in this example. Also superfluous is the indirection with myString—just push eax directly.
printf writes the output first to a buffer. You exit the program with a int 80h system call. This call will destroy everything of the process including the printf-buffer. So the buffer won't be outputted. There are two ways to solve the problem:
1) Use the C function exit instead of the system call:
section .data
str1 db "Here is some text with a word",0x0A,0x00
str2 db "text",0x00
strFmt db "%s",0x0A,0x00
global _start
extern printf, strstr, exit
section .text
_start:
push str2
push str1
call strstr
add esp, 8
push eax
push strFmt
call printf
add esp, 8
_exit:
push 0
call exit
2) Add a call to the C function fflush:
section .data
str1 db "Here is some text with a word",0x0A,0x00
str2 db "text",0x00
strFmt db "%s",0x0A,0x00
global _start
extern printf, strstr, fflush
section .text
_start:
push str2
push str1
call strstr
add esp, 8
push eax
push strFmt
call printf
add esp, 8
push 0
call fflush
_exit:
mov ebx, 0
mov eax, 1
int 0x80
I'm trying to input values into an array in x86-64 Intel assembly, but I can't quite figure it out.
I'm creating an array in segement .bss. Then I try to pass the address of the array along to another module by using r15. Inside that module I prompt the user for a number that I then insert into the array. But it doesn't work.
I'm trying to do the following
segment .bss
dataArray resq 15 ; Array that will be manipulated
segment .text
mov rdi, dataArray ; Store memory address of array so the next module can use it.
call inputqarray ; Calling inputqarray module
Inside of inputqarary I have:
mov r15, rdi ; Move the memory address of the array into r15 for safe keeping
push qword 0 ; Make space on the stack for the value we are reading
mov rsi, rsp ; Set the second argument to point to the new locaiton on the stack
mov rax, 0 ; No SSE input
mov rdi, oneFloat ; "%f", 0
call scanf ; Call C Standard Library scanf function
call getchar ; Clean the input stream
pop qword [r15]
I then try to output the value entered by the use by doing
push qword 0
mov rax, 1
mov rdi, oneFloat
movsd xmm0, [dataArray]
call printf
pop rax
Unfortunately, all I get for output is 0.00000
Output is 0 because you are using the wrong format specifier. It should be "%lf"
Next, no need to push and pop in your procedure. Since your going to pass the address of the data array to scanf, and that will be in rsi, just pass it in rsi; one less move.
You declared your array as 15 QWORDS, is that correct - 120 bytes? or did you mean resb 15?
This works and should get you on your way:
extern printf, scanf, exit
global main
section .rodata
fmtFloatIn db "%lf", 0
fmtFloatOut db `%lf\n`, 0
section .bss
dataArray resb 15
section .text
main:
sub rsp, 8 ; stack pointer 16 byte aligned
mov rsi, dataArray
call inputqarray
movsd xmm0, [dataArray]
mov rdi, fmtFloatOut
mov rax, 1
call printf
call exit
inputqarray:
sub rsp, 8 ; stack pointer 16 byte aligned
; pointer to buffer is in rsi
mov rdi, fmtFloatIn
mov rax, 0
call scanf
add rsp, 8
ret
Since you are passing params in rdi to the C functions, this is not on Windows.
My question: Why is it printing twice when I'm making one call to printf?
Note that yes, I'm aware I'm allocating space in heap for a variable stored on the stack. I'm only doing this to get used to malloc, pointers, and 'arrays' in NASM.
Compiling in x64 bit machine with:
nasm -f elf32 -o TEMP.o file.asm
and:
gcc -m32 -o exec TEMP.o
extern exit, printf, malloc, free
global main
section .data
format db "%s", 10
msg: db "Hello!!",10
BUF equ $-msg + 1
section .text
main:
push BUF ; How many bytes do we want to allocate
call malloc ; ptr stored in EAX
add esp, 4 ; clear the last thing on the stack (BUF)
mov esi, eax ; new source index at malloc pointer
xor ecx, ecx ; clear ECX (counter for us)
loop:
mov dl, [msg+ecx] ; mov letter into dl
mov BYTE [esi+ecx], dl ; cat dl onto array
inc ecx ; add 1 to our ounter
cmp ecx, BUF-1d
jl loop
xor edx, edx
mov BYTE [esi+ecx], dl
add esp, 4
mov esi, eax
push esi ;
push format
call printf
add esp, 4*2
push esi
call free
push 0
call exit
add esp, 4
You only need to end your strings with 0
format db "%s", 10, 0
msg: db "Hello!!",10 ,0
Okay i'v read the comments just now and see you said you had code that is meant to insert the 0s, i'd check that, because i copied/pasted your code and only added the 0s on the ends of the strings to make it output one string, i didn't even notice the insertion code let alone touch it, but i can only assume that is where your problem is.
I made a simple program which will just push a number and display it on the screen but
don't know what is going wrong
section .data
value db 10
section .text
global main
extern printf
main:
push 10 //can we push value directly on stack?
call printf
add esp,4
ret
Getting Segmentation fault for above.
section .data
value db 10
section .text
global main
extern printf
main:
push [value]
call printf
add esp,4
ret
In second version will be pushing value pointed to by value variable on to stack
But getting "operation size not specified"
Yes, you can push any DWORD value (in 32-bit assembler) onto the stack.
The problem in the first code fragment is that printf expects the first argument to be a format string (in C, you'd write printf("%d\n", 10);). So something like
section .data
fmt db "%d", 10, 0
...
push 10
push fmt
call printf
add esp, 8
will work.
In the second code fragment, instead of push [value] you should write push dword [value], but that's not correct if your value variable is a single byte. Either declare it as a DWORD (dd), or perform
movsx eax, byte [value] ; if it's a signed integer; movzx for unsigned
push eax
And one more thing. When calling printf (or any of the C library functions), beware of stack alignment. Some platforms require that stack is 16-byte aligned at the time of a function call (this is necessary for correct execution of optimized CPU instructions like SSE). So, to make the stack aligned:
push ebp
mov ebp, esp
sub esp, 8 ; reserve 8 bytes for parameters
and esp, -16 ; align the stack (the reserved space can increase)
mov dword [esp], fmt ; put parameters into stack
mov dword [esp+4], 10
call printf
mov esp, ebp ; restore stack
pop ebp
I have some assembly code that uses scanf and printf and I'm running into some problems. When both of these functions are used in the same code, the values in the registers seem to be lost. The program basically loads a number and prints it out. We run it using
nasm -f elf64 file.asm && gcc -o file file.o && ./file
on linux
Here's our code:
extern printf
extern scanf
section .data
a db "set: ", 0
b db "not set: ", 0
reading db "Please enter a number: ", 0
message db "\n", 0
printsent db "%s", 10, 0
printint db "%d", 10, 0
printchar db "%c", 10, 0
readInt db "%d", 0
input db "%d", 0
section .text
global main
main:
hatta:
push rbp,
mov rbp, rsp,
push rbx,
xor rax, rax,
mov rdi, printsent,
mov rsi, reading
call printf,
pop rbx,
xor rax, rax,
mov rdi, readInt,
call scanf,
mov rbx, rdi
push rbx,
xor rax, rax,
mov rdi, printint,
mov rsi, rbx,
call printf,
pop rbx,
pop rbp,
ret
The odd thing is that if the line mov rdi, printint, is removed, we obtain the correct values. However, if we do the same thing with printsentence, we get a segmentation fault. Could anyone tell us the reason for this?
Thanks!
There are two errors in your scanf usage, possibly based on one false assumption: You seem to mean that scanf returns the loaded number in rdi and that no further argument is needed with format "%d". In truth the number (if scanned successfully) is returned in the memory pointed to by the second argument. Thus, the following changes make the code work.
pop rbx, | ;delete
=
xor rax, rax, = xor rax, rax,
mov rdi, readInt, = mov rdi, readInt,
> mov rsi, rsp
call scanf, = call scanf,
mov rbx, rdi | pop rbx,
Concerning if the line mov rdi, printint, is removed, we obtain the correct values - I doubt that.
I don't understand why you have the C flag here, there is no C code involved, but to your question:
As far as I remember the calling convention in Linux glibc x64 for printf(format, argument) is format in rdi, argument in rsi.
If you remove mov rdi, printsent, then you are calling printf(undefined,"Please enter a number: "). You did not provide a format argument in rdi, but printf
doesn't know that and uses whatever is in rdi at that moment. Most likely an invalid memory address which thus invokes a SIGSEGV.
By default function calls in x86 are supposed to be non-destructive on the arguments, though this is not a requirement. Standard library functions generally are. They achieve this by pushing the arguments on to the stack and reload them when done.
As such when you call scanf(readInt, ...) it will restore the pointer to readInt which has the same contents as printint in rdi when it returns. As such removing the line mov rdi, printint, has no effect because rdi contains a valid pointer to the format you need.