I'm doing a project that attaches a subroutine that I wrote to a main file included by the teacher. He gave us the instructions for making our subroutine global but apparently I'm an idiot. The two asm files are in the same folder, I'm using nasm -f elf -g prt_dec.asm and ld prt_dec and then doing the same for main.asm. Here's the relevant code in the main.asm:
SECTION .text ; Code section.
global _start ; let loader see entry point
extern prt_dec
_start:
mov ebx, 17
mov edx, 214123
mov edi, 2223187809
mov ebp, 1555544444
mov eax, dword 0x0
call prt_dec
call prt_lf
The line call prt_dec throws "undefined reference to prt_dec" when i use ld main.o
Here's the a code segment from my prt_dec.asm:
Section .text
global prt_dec
global _start
start:
prt_dec:
(pushing some stuff)
L1_top:
(code continues)
You want to call a routine in another asm file or object file?
if you are Assembling prt_dec.asm and are linking multiple asm files to use in your main program, here is a sample, 2 asm files Assembled and linked together... * NOTE * hello.asm *DOES NOT * have a start label!
Main asm file: hellothere.asm
sys_exit equ 1
extern Hello
global _start
section .text
_start:
call Hello
mov eax, sys_exit
xor ebx, ebx
int 80H
Second asm file: hello.asm
sys_write equ 4
stdout equ 1
global Hello
section .data
szHello db "Hello", 10
Hello_Len equ ($ - szHello)
section .text
Hello:
mov edx, Hello_Len
mov ecx, szHello
mov eax, sys_write
mov ebx, stdout
int 80H
ret
makefile:
APP = hellothere
$(APP): $(APP).o hello.o
ld -o $(APP) $(APP).o hello.o
$(APP).o: $(APP).asm
nasm -f elf $(APP).asm
hello.o: hello.asm
nasm -f elf hello.asm
Now, if you just want to separate your code into multiple asm files, you can include them into your main source: with %include "asmfile.asm" at the beginning of your main source file and just assemble and link your main file.
Related
I coding assembly with Nasm, i want debug the program using gdb, but it not works when i put a breakpoint and run the program.
The program compile fine and link too, the problem is gdb.
Here is the commands to compile:
nasm -f elf64 -F dwarf -g types.asm
nasm -f elf64 -F dwarf -g functions.asm
nasm -f elf64 -F dwarf -g Hello.asm
ld -g -o Hello Hello.o functions.o types.o
This is the file i want debug Hello.asm:
%include "functions.asm"
section .bss
res: resb 1
fout: resb 1
section .text
global _start: ;must be declared for linker (ld)
section .data
msg db 'Hello, world!', 0xa ;string to be printed
len equ $ - msg ;length of the string
filename db 'hello.txt'
_start: ;tells linker entry point
mov ecx,5
mov edx,4
call sum
mov [res],eax
mov edx,1 ;message length
mov ecx,res ;message to write
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
write_string msg,len
create_file filename
mov [fout],eax
close_file [fout]
call print_msg
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
sum:
mov eax,ecx
add eax,edx
add eax,'0'
ret
Next i open gdb:
gdb Hello
(gdb) break _start
Function «_start» not defined
¿Compilación de breakpoint pendiente hasta futura cargada de biblioteca compartida? (y or [n]) y
Punto de interrupción 1 (_start) pendiente.
(gdb) run
Starting program: /asm/Hello
9Hello, world!
Hello, world!from another file
[Inferior 1 (process 5811) exited with code 01]
(gdb)
I solved it, i only change position section .data to section .text and the debugger works.I don't know why, but now the gdb take the .start.
I have the following assembly, which I assemble with NASM and then link with gcc:
section .text
extern printf
global main
main:
sub rsp, 8 ;align stack pointer
mov rax, 0 ;no vector arguments
mov rdi, intro_message ;First argument
call printf
mov rax, 60 ;exit
syscall
section .data
intro_message:
db 'Hello world',0
When I run ./a.out, nothing is printed, and the instruction pointer seems to have moved to an invalid location. What have I done wrong?
I'm trying to write some assembly programs using nasm on linux. Everything is good, but I make heavy use of local symbols (.loop, .else, etc.), which is a pain when debugging, because these symbols are emitted to the symbol table, e.g.:
[BITS 32]
global main
section .text
main:
do stuff
.else:
do other stuff
will produce a disassembly that looks like:
<main>:
00000000 do stuff
<main.else>:
00000000 do other stuff
which is a bit annoying just because gdb will think these are all separate functions, so when I 'disas' it will only disassemble a couple of instructions before it runs into another label and stops.
Is there a way to suppress emitting these symbols to the ELF symbol table using nasm under linux?
I haven't found a way to do it directly with nasm, however if you link your object with ld, then you have at your disposal a very handy switch.
Quoting from ld's man page:
-x --discard-all
Delete all local symbols.
-X --discard-locals
Delete all temporary local symbols. (These symbols start with
system-specific local label prefixes, typically .L for ELF
systems or L for traditional a.out systems.)
so if you have, for example, this:
section .data
hello: db 'Hello world!',10
helen: equ $-hello
hi: db 'Hi!',10
hilen: equ $-hi
section .text
global _start
_start:
mov eax,4
mov ebx,1
mov ecx,hello
mov edx,helen
int 80h
.there:
mov eax,4
mov ebx,1
mov ecx,hi
mov edx,hilen
int 80h
.end:
mov eax,1
mov ebx,0
int 80h
and then build, link (and run) it like this:
$ nasm -g -f elf32 prog.asm && ld -x prog.o -o prog && ./prog
Hello world!
Hi!
then, when you load it in gdb, you get this:
$ gdb prog
.....
Reading symbols from prog...done.
(gdb) disas _start
Dump of assembler code for function _start:
0x08048080 <+0>: mov $0x4,%eax
0x08048085 <+5>: mov $0x1,%ebx
0x0804808a <+10>: mov $0x80490b8,%ecx
0x0804808f <+15>: mov $0xd,%edx
0x08048094 <+20>: int $0x80
0x08048096 <+22>: mov $0x4,%eax
0x0804809b <+27>: mov $0x1,%ebx
0x080480a0 <+32>: mov $0x80490c5,%ecx
0x080480a5 <+37>: mov $0x4,%edx
0x080480aa <+42>: int $0x80
0x080480ac <+44>: mov $0x1,%eax
0x080480b1 <+49>: mov $0x0,%ebx
0x080480b6 <+54>: int $0x80
End of assembler dump.
(gdb)
where the disassembly is not hindered by the local symbols any more.
Test platform is 32 bit Linux.
Basically, I did a modification to the asm code gcc generated to change the entry point from main to start as below:
asm code:
.file "test.c"
.intel_syntax noprefix
.section .rodata
.LC0:
.string "%d\n"
.text
.globl start
.type start, #function
start:
push ebp
mov ebp, esp
call main
mov eax, 0
leave
ret
.size start, .-start
.globl main
.type main, #function
main:
push ebp
mov ebp, esp
and esp, -16
sub esp, 32
mov DWORD PTR [esp+28], 1
mov eax, OFFSET FLAT:.LC0
mov edx, DWORD PTR [esp+28]
mov DWORD PTR [esp+4], edx
mov DWORD PTR [esp], eax
call printf
mov eax, 0
Then I use these to compile and link:
as test.s -g -o test.o
ld -o test test.o -lc -dynamic-linker /lib/ld-linux.so.2 -e start
When debug using gdb, it can successfully work until the end of start function,
then from the debug info it seems that $EIP don't know where to jump next, and
segment fault occurs...
Could anyone give me some help on this issue..?
Thank you a lot!
you should call exit instead of set eax to 0 and return, because you don't use C main function(C-runtime), so nowhere to return.
I'm starting to learn Assembler and I'm working in Unix. I want to open a file and write 'Hello world' on it.
section .data
textoutput db 'Hello world!', 10
lentext equ $ - textoutput
filetoopen db 'hi.txt'
section .text
global _start
_start:
mov eax, 5 ;open
mov ebx, filetoopen
mov ecx, 2 ;read and write mode
int 80h
mov eax, 4
mov ebx, filetoopen ;I'm not sure what do i have to put here, what is the "file descriptor"?
mov ecx, textoutput
mov edx, lentext
mov eax, 1
mov ebx, 0
int 80h ; finish without errors
But when I compile it, it doesn't do anything. What am I doing wrong?
When I open a file where does the file descriptor value return to?
This is x86 Linux (x86 is not the only assembly language, and Linux is not the only Unix!)...
section .data
textoutput db 'Hello world!', 10
lentext equ $ - textoutput
filetoopen db 'hi.txt'
The filename string requires a 0-byte terminator: filetoopen db 'hi.txt', 0
section .text
global _start
_start:
mov eax, 5 ;open
mov ebx, filetoopen
mov ecx, 2 ;read and write mode
2 is the O_RDWR flag for the open syscall. If you want the file to be created if it doesn't already exist, you will need the O_CREAT flag as well; and if you specify O_CREAT, you need a third argument which is the permissions mode for the file. If you poke around in the C headers, you'll find that O_CREAT is defined as 0100 - beware of the leading zero: this is an octal constant! You can write octal constants in nasm using the o suffix.
So you need something like mov ecx, 0102o to get the right flags and mov edx, 0666o to set the permssions.
int 80h
The return code from a syscall is passed in eax. Here, this will be the file descriptor (if the open succeeded) or a small negative number, which is a negative errno code (e.g. -1 for EPERM). Note that the convention for returning error codes from a raw syscall is not quite the same as the C syscall wrappers (which generally return -1 and set errno in the case of an error)...
mov eax, 4
mov ebx, filetoopen ;I'm not sure what do i have to put here, what is the "file descriptor"?
...so here you need to mov ebx, eax first (to save the open result before eax is overwritten) then mov eax, 4. (You might want to think about checking that the result was positive first, and handling the failure to open in some way if it isn't.)
mov ecx, textoutput
mov edx, lentext
Missing int 80h here.
mov eax, 1
mov ebx, 0
int 80h ; finish without errors
Did you read the Linux Assembly HOWTO? It covers your question.
You can also compile some C code with gcc -S -fverbose-asm -O1 and look at the generated assembly. For example, with foo.c, run gcc -S -Wall -fverbose-asm -O1 foo.c (as a command in some terminal) then look (using some editor -perhaps GNU emacs) into the generated foo.s assembler file.
At last, I don't think it is worth bothering a lot about assembler. In 2020, a recent GCC compiler will surely generate better code than what you could write (if you invoke it with optimizations, at least -O2). See this draft report for more.
This is a x64 Linux sample
; Program to open and write to file
; Compile with:
; nasm -f elf64 -o writeToFile64.o writeToFile64.asm
; Link with:
; ld -m elf_x86_64 -o writeToFile64 writeToFile64.o
; Run with:
; ./writeToFile64
;==============================================================================
; Author : Rommel Samanez
;==============================================================================
global _start
%include 'basicFunctions.asm'
section .data
fileName: db "testFile.txt",0
fileFlags: dq 0102o ; create file + read and write mode
fileMode: dq 00600o ; user has read write permission
fileDescriptor: dq 0
section .rodata ; read only data section
msg1: db "Write this message to the test File.",0ah,0
msglen equ $ - msg1
msg2: db "File Descriptor=",0
section .text
_start:
mov rax,2 ; sys_open
mov rdi,fileName ; const char *filename
mov rsi,[fileFlags] ; int flags
mov rdx,[fileMode] ; int mode
syscall
mov [fileDescriptor],rax
mov rsi,msg2
call print
mov rax,[fileDescriptor]
call printnumber
call printnewline
; write a message to the created file
mov rax,1 ; sys_write
mov rdi,[fileDescriptor]
mov rsi,msg1
mov rdx,msglen
syscall
; close file Descriptor
mov rax,3 ; sys_close
mov rdi,[fileDescriptor]
syscall
call exit
It depends what assembler you are using and if you expect to be using the C runtime or not. In this case which appears to be the Hello World text example from rosettacode they are using nasm. Given you have a _start field you are not needing the C runtime so you assemble this to an elf object file and link it into a program:
nasm -felf hello.asm
ld hello.o -o hello
Now you can run the hello program.
A slightly more portable example that uses the C runtime to do the work rather than linux syscalls might look like the sample below. If you link this as described it can use printf to do the printing.
;;; helloworld.asm -
;;;
;;; NASM code for Windows using the C runtime library
;;;
;;; For windows - change printf to _printf and then:
;;; nasm -fwin32 helloworld.asm
;;; link -subsystem:console -out:helloworld.exe -nodefaultlib -entry:main
;;; helloworld.obj msvcrt.lib
;;; For gcc (linux, unix etc):
;;; nasm -felf helloworld.asm
;;; gcc -o helloworld helloworld.o
extern printf
section .data
message:
db 'Hello, World', 10, 0
section .text
global main
main:
push dword message ; push function parameters
call printf ; call C library function
add esp, 4 ; clean up the stack
mov eax, 0 ; exit code 0
ret
For information about file descriptors - read the open(2) manual page or look at wikipedia. It is how posix refers to an open i/o stream. In your case, stdout.