I am new with assembly. And I have problem with code. I am trying to create simple program using scanf.
This is code:
global main
extern printf
extern scanf
section .text
section .data
message: db "The result is = %d", 10, 0
request: db "Enter the number: ", 0
integer1: times 4 db 0 ; 32-bits integer = 4 bytes
formatin: db "%d", 0
main:
; Ask for an integer
push request
call printf
add esp, 4 ; remove the parameter
push integer1 ; address of integer1, where the input is going to be stored
push formatin ; arguments are right to left (first parameter)
call scanf
add esp, 8 ; remove the parameters
; Move the value under the address integer1 to EAX
mov eax, [integer1]
; Print out the content of eax register
push rax
push message
call printf
add esp, 8
; Linux terminate the app
MOV AL, 1
MOV EBX, 0
INT 80h
i compile it with:
nasm -f elf64 -o program.o program.asm
and:
ld -o program program.o
but when i try ld i get error:
program.o: In function `main':
program.asm:(.data+0x34): undefined reference to `printf'
program.asm:(.data+0x46): undefined reference to `scanf'
program.asm:(.data+0x5b): undefined reference to `printf'
I am working on 64-bit linux.
Thanks for help.
You're not linking with any libraries with your ld command. scanf and printf are defined in the C library, so you can link with that:
ld -o program program.o -lc
or you can use some other library that defines those functions, if you have it available.
Related
I'm trying to print a format string in NASN 64 (linux-fedora) but I'm getting an error that says "cannot find -lc" and "ld returned 1 exit status".
; ----------------------------------------------------------------------------------------
; Testing extern printf to print a format string.
; Linux-Fedora/.
; To assemble and run:
;
; nasm -felf64 printf.asm
; gcc -static -o printf printf.o
; ----------------------------------------------------------------------------------------
;--------------------------------Varibles declaradas--------------------------------------
section .data
string db "The number is: %d", 10, 0
;-----------------------------------------------------------------------------------------
;-----------------------------------------------------------------------------------------
section .text
extern printf
global main
main:
mov rdi, string ;the format string
mov rsi, 10 ;the argument (number 10)
xor eax, eax ;no vector in use
call printf
;exit(0)
mov rax, 60
mov rdi, 0
syscall
To get to print the string.
I have this:
$ make build
read.o: In function `_start':
read.asm:(.text+0x0): multiple definition of `_start'
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o:(.text+0x0): first defined here
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
Makefile:3: recipe for target 'build' failed
make: *** [build] Error 1
From this asm:
global main
section .text
main: mov rax, 1 ; system call for write
mov rdi, 1 ; file handle 1 is stdout
mov rsi, message ; address of string to output
mov rdx, 13 ; number of bytes
syscall ; invoke operating system to do the write
mov rax, 60 ; system call for exit
xor rdi, rdi ; exit code 0
syscall ; invoke operating system to exit
section .data
message: db "Hello, World", 10 ; note the newline at the end
I am running it with this:
$ nasm -felf64 read.asm -o read.o && gcc read.o -o store && ./store
How do I change the word main to something other than main or _start, such as begin or myentrypoint? I would like to customize it. Can it even be customized?
Note that main is not the entrypoint. The entrypoint is _start provided by crt0.o which eventually calls main. You cannot change that. However, you can provide your own startup code that calls some other function than main.
Note that the entrypoint itself can be set to whatever symbol you like with the -e option to ld. Refer to the manual for details. Note however that if you change this, the C runtime code will no longer work correctly. Use only with your own runtime code.
One option to change main to something else is setting main to be an alias for some other symbol, e.g. with
.set main, mymain
in some assembly file. Alternatively, simply provide a dummy main function that jumps to your actual main function:
global main
main: jmp mymain
When writing some x64 assembly, I stumbled upon something weird. A function call works fine when executed on a main thread, but causes a segmentation fault when executed as a pthread. At first I thought I was invalidating the stack, as it only segfaults on the second call, but this does not match with the fact that it works properly on the main thread yet crashes on a newly-spawned thread.
From gdb:
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Value: 1337
Value: 1337
[New Thread 0x7ffff77f6700 (LWP 8717)]
Return value: 0
Value: 1337
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff77f6700 (LWP 8717)]
__printf (format=0x600570 <fmt> "Value: %d\n") at printf.c:28
28 printf.c: No such file or directory.
Does anyone have an idea about what could be going on here?
extern printf
extern pthread_create
extern pthread_join
extern pthread_exit
section .data
align 4
fmt db "Value: %d", 0x0A, 0
fmt_rval db "Return value: %d", 0x0A, 0
tID dw 0
section .text
global _start
_start:
mov rdi, 1337
call show_value
call show_value ; <- this call works fine
; CREATE THREAD
mov ecx, 0 ; function argument
mov edx, thread_1 ; function pointer
mov esi, 0 ; attributes
mov rdi, tID ; pointer to threadID
call pthread_create
mov rdi, rax
call show_rval
mov rsi, 0 ; return value
mov rdi, [tID] ; id to wait on
call pthread_join
mov rdi, rax
call show_rval
call exit
thread_1:
mov rdi, 1337
call show_value
call show_value ; <- this additional call causes a segfault
ret
show_value:
push rdi
mov rsi, rdi
mov rdi, fmt
call printf
pop rdi
ret
show_rval:
push rdi
mov rsi, rdi
mov rdi, fmt_rval
call printf
pop rdi
ret
exit:
mov rax, 60
mov rdi, 0
syscall
The binary was generated on Ubuntu 14.04 (64-bit of course), with:
nasm -felf64 -g -o $1.o $1.asm
ld -I/lib64/ld-linux-x86-64.so.2 -o $1.out $1.o -lc -lpthread
Functions that take a variable number of parameters like printf require the RAX register to be set properly. You need to set it to the number of vector registers used, which in your case is 0. From Section 3.2.3 Parameter Passing in the System V 64-bit ABI:
RAX
temporary register;
with variable arguments passes information about the number of vector registers used;
1st return register
Section 3.5.7 contains more detailed information about the parameter passing mechanism of functions taking a variable number of arguments. That section says:
When a function taking variable-arguments is called, %rax must be set to the total number of floating point parameters passed to the function in vector registers.
Modify your code to set RAX to zero in your call to printf:
show_value:
push rdi
xor rax, rax ; rax = 0
mov rsi, rdi
mov rdi, fmt
call printf
pop rdi
ret
You have a similar issue with show_rval
One other observation is that you could simplify linking your executable by using GCC instead of LD
I would recommend renaming _start to main and simply use GCC to link the final executable. GCC's C runtime code will provide a _start label that does proper initialization of the C runtime, which could potentially be required in some scenarios. When the C runtime code is finished initialization it transfers (via a CALL) to the label main. You could then produce your executable with:
nasm -felf64 -g -o $1.o $1.asm
gcc -o $1.out $1.o -lpthread
I don't think this is related to your problem, but was meant more as an FYI.
By not properly setting RAX for the printf call, unwanted behavior may occur in some cases. In this case, the value of RAX not being set properly for the printf call in an environment with threads causes a segmentation fault. The code without threads happened to work because you were lucky.
I need to make a program that outputs a text file with an extension of .dna, I don't know if I can really do that, and if the text file will even be compatible with what I need to compare it afterwards. Anyway, I'm not really sure how to do this. I tried to look for some examples for NASM, but I didn't find much. I have an idea of what I'd need to do, but I just don't know what to call to generate a file.
Afterwards I'd need to write stuff into it, I'm not really sure on how to go on about that. Could anyone point me to some examples or something? I just need to see what is required to write my own thing.
Here's an example using system calls. Basically, you just open the file, write some data to it, then close and exit:
; nasm -f elf file.asm
; ld -m elf_i386 file.o
BITS 32
section .data
; don't forget the 0 terminator if it akes a C string!
filename: db 'test.txt', 0
; an error message to be printed with write(). The function doesn't
; use a C string so no need for a 0 here, but we do need length.
error_message: db 'Something went wrong.', 10 ; 10 == \n
; this next line means current location minus the error_message location
; which works out the message length.
; many of the system calls use pointer+length pairs instead of
; 0 terminated strings.
error_message_length: equ $ - error_message
; a message we'll write to our file, same as the error message
hello: db 'Hello, file!', 10 ; the 10 is a newline at the end
hello_length: equ $ - hello
fd: dd 0 ; this is like a global int variable in C
; global variables are generally a bad idea and there's other
; ways to do it, but for simplicity I'm using one here as the
; other ways are a bit more work in asm
section .text
global _start
_start:
; first, open or create the file. in C it would be:
; // $ man 2 creat
; int fd = creat("file.txt", 0644); // the second argument is permission
; we get the syscall numbers from /usr/include/asm/unistd_32.h
mov eax, 8 ; creat
mov ebx, filename ; first argument
mov ecx, 644O ; the suffix O means Octal in nasm, like the leading 0 in C. see: http://www.nasm.us/doc/nasmdoc3.html
int 80h ; calls the kernel
cmp eax, -1 ; creat returns -1 on error
je error
mov [fd], eax ; the return value is in eax - the file descriptor
; now, we'll write something to the file
; // man 2 write
; write(fd, hello_pointer, hello_length)
mov eax, 4 ; write
mov ebx, [fd],
mov ecx, hello
mov edx, hello_length
int 80h
cmp eax, -1
; it should also close the file in a normal program upon write error
; since it is open, but meh, since we just terminate the kernel
; will clean up after us
je error
; and now we close the file
; // man 2 close
; close(fd);
mov eax, 6 ; close
mov ebx, [fd]
int 80h
; and now close the program by calling exit(0);
mov eax, 1 ; exit
mov ebx, 0 ; return value
int 80h
error:
mov eax, 4 ; write
mov ebx, 1 ; write to stdout - file #1
mov ecx, error_message ; pointer to the string
mov edx, error_message_length ; length of the string
int 80h ; print it
mov eax, 1 ; exit
mov ebx, 1 ; return value
int 80h
The file will be called a.out if you copied my link command above. The -o option to ld changes that.
We can also call C functions, which helps if you need to write out things like numbers.
; nasm -f elf file.asm
; gcc -m32 file.o -nostdlib -lc # notice that we're using gcc to link, makes things a bit easier
; # the options are: -m32, 32 bit, -nostdlib, don't try to use the C lib cuz it will look for main()
; # and finally, -lc to add back some of the C standard library we want
BITS 32
; docs here: http://www.nasm.us/doc/nasmdoc6.html
; we declare the C functions as external symbols. the leading underscore is a C thing.
extern fopen
extern fprintf
extern fclose
section .data
; don't forget the 0 terminator if it akes a C string!
filename: db 'test.txt', 0
filemode: db 'wt', 0 ; the mode for fopen in C
format_string: db 'Hello with a number! %d is it.', 10, 0 ; new line and 0 terminator
; an error message to be printed with write(). The function doesn't
; use a C string so no need for a 0 here, but we do need length.
error_message: db 'Something went wrong.', 10 ; 10 == \n
; this next line means current location minus the error_message location
; which works out the message length.
; many of the system calls use pointer+length pairs instead of
; 0 terminated strings.
error_message_length: equ $ - error_message
fp: dd 0 ; this is like a global int variable in C
; global variables are generally a bad idea and there's other
; ways to do it, but for simplicity I'm using one here as the
; other ways are a bit more work in asm
section .text
global _start
_start:
; first, open or create the file. in C it would be:
; FILE* fp = fopen("text.txt", "wt");
; arguments for C functions are pushed on to the stack, right from left.
push filemode ; "wt"
push filename ; "text.txt"
call fopen
add esp, 8 ; we need to clean up our own stack. Since we pushed two four-byte items, we need to pop the 8 bytes back off. Alternatively, we could have called pop twice, but a single add instruction keeps our registers cleaner.
; the return value is in eax, store it in our fp variable after checking for errors
; in C: if(fp == NULL) goto error;
cmp eax, 0 ; check for null
je error
mov [fp], eax;
; call fprintf(fp, "format string with %d", 55);
; the 55 is just a random number to print
mov eax, 55
push eax ; all arguments are pushed, right to left. We want a 4 byte int equal to 55, so eax is it
push format_string
mov eax, [fp] ; again using eax as an intermediate to store our 4 bytes as we push to the stack
push eax
call fprintf
add esp, 12 ; 3 words this time to clean up
; fclose(fp);
mov eax, [fp] ; again using eax as an intermediate to store our 4 bytes as we push to the stack
push eax
call fclose
; the rest is unchanged from the above example
; and now close the program by calling exit(0);
mov eax, 1 ; exit
mov ebx, 0 ; return value
int 80h
error:
mov eax, 4 ; write
mov ebx, 1 ; write to stdout - file #1
mov ecx, error_message ; pointer to the string
mov edx, error_message_length ; length of the string
int 80h ; print it
mov eax, 1 ; exit
mov ebx, 1 ; return value
int 80h
There's a lot more that can be done here, like a few techniques to eliminate those global variables, or better error checking, or even writing a C style main() in assembly. But this should get you started in writing out a text file. Tip: Files are the same as writing to the screen, you just need to open/create them first!
BTW don't mix the system calls and the C library functions at the same time. The C library (fprintf etc) buffers data, the system calls don't. If you mix them, the data might end up written to the file in a surprising order.
The code is similar, but slightly different in 64 bit.
Finally, this same pattern can be used to translate almost any C code to asm - the C calling convention is the same with different functions, and the linux system call convention with the argument placement etc. follows a consistent pattern too.
Further reading:
http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl on the C calling convention
http://docs.cs.up.ac.za/programming/asm/derick_tut/syscalls.html on linux system calls
What is the purpose of EBP in the following code? is another SO answer I wrote up a while ago about local variables in asm - this will have hints as to one way to get rid of that global and describes how the C compile does it. (the other way to get rid of that global is to either keep the fd/fp in a register and push and pop it onto the stack when you need to free up the register for something else)
And the man pages referenced in the code for each function. From your linux prompt, do things like man 2 write or man 3 fprintf to see more. (System calls are in manual section 2 and C functions are in manual section 3).
[section .data]
strHello db "Hello World"
STRLEN equ $-strHello
MessageLength equ 9
Message db "hi!!!! "
[section .text]
global main
main:
mov edx,STRLEN;
mov ecx,strHello;
mov ebx,1
mov eax,4
int 0x80
call DispStr
mov ebx,0
mov eax,1
int 0x80
DispStr:
mov ax,MessageLength
mov dh,0
mul dh
add ax,Message
mov bp,ax
mov ax,ds
mov es,ax
mov cx,MessageLength
mov ax,01301h
mov bx,0007h
mov dl,0
int 10h
ret
Compile and run:
$ nasm -f elf64 helloworld.asm -o helloworld.o
$ gcc -s -o helloworld helloworld.o
helloworld.o: In function `DispStr':
helloworld.asm:(.text+0x31): relocation truncated to fit: R_X86_64_16 against `.data'
collect2: ld return 1
This exact error happens because at:
add ax,Message
ax is only 16-bit wide, but Message is a 64-bit wide address, so it won't fit during relocation.
I have explained this error in detail at: https://stackoverflow.com/a/32639540/895245
The solution in this case is to use a linker script as mentioned at: Using .org directive with data in .data section: In connection with ld
This repository contains working examples of boot sectors and BIOS: https://github.com/cirosantilli/x86-bare-metal-examples/tree/d217b180be4220a0b4a453f31275d38e697a99e0
Since you're in 64-bit mode, you won't be able to use BIOS functions (i.e. the int 10h instruction). Even if you could, BIOS uses a different addressing mechanism, so attempting to use the address of Message wouldn't work anyway.
Also, wouldn't the first 3 lines of the DispStr function zero out ax? (since you're multiplying by dh, which was just set to zero)