I am new to assembly and I have an AMD processor, so I've been learning x64 assembly from books and tutorials. After inspecting the code in GDB and LDD I see that GLibC is included in the linked libraries, as is ld-linux.so; but I'm not sure if I'm missing something. That or I'm not calling the functions properly with arguments. I was also wondering if I should have added any '[]' around any variables. But the weird thing is that the code is saying that something is missing. But what?
prime.asm
%include "asm_io.inc"
%macro prologue 0
push rbp
mov rbp,rsp
push rbx
push r12
push r13
push r14
push r15
pushfq
%endmacro ; end of prologue
%macro epilogue 0
popfq
pop r15
pop r14
pop r13
pop r12
pop rbx
leave
ret
%endmacro ; end of epilogue
section .rodata
prompt1 db "Find primes upto: "
section .bss
guess resd 1 ; uninitialized integer
limit resd 1 ; uninitialized integer
section .text
global main
main:
prologue
; enter a value in the variable limit
mov rdi, prompt1
call print_string
mov rdi, dword limit
call read_int
; print the first 2 prime numbers
mov rdi, 0x2
call print_int
call print_nl
mov rdi, 0x3
call print_int
call print_nl
mov [guess],dword 0x5
while_limit:
mov eax, [guess] ; since we are dealing with integers, we use the 32-bit register to move data
mov edx, [limit] ; since we are dealing with integers
cmp eax, edx
jnbe end_of_while_limit ; jump if not below or equal
mov rcx, 3 ; RCX holds the variable factor
while_factor:
mov rax, rcx
mul rax ; calculate factor*factor. we could use EAX here,
; but using RAX will reduce chances of an overflow
jo end_of_while_factor ; we still check for overflow though with jump if overflow
cmp eax,[guess] ; we compare with EAX, otherwise if we use RAX here,
; 8 bytes will be read from the address of the variable guess
jge end_of_while_factor ; jump if greater than or equal
mov eax,[guess] ; moving 4 bytes only
cqo
div rcx ; guess / factor
cmp rdx,0 ; guess % factor is in RDX
je end_of_while_factor ; jump if equal
add rcx,2 ; factor+=2
jmp while_factor ; loop
end_of_while_factor:
mov eax,[guess]
cqo
div rcx
cmp rdx,0 ; guess%factor is in RDX
je end_of_if ; jump if equal
mov edi, [guess] ; move the value in guess into EDI for printing
call print_int
call print_nl
end_of_if:
mov eax, [guess]
add rax, 2 ; guess+=2
mov [guess],eax
jmp while_limit ; loop
end_of_while_limit:
epilogue
asm_io.inc
extern print_string2, print_nl2, print_int, read_int, print_string, print_nl
asm_io.asm
%macro prologue 0
push rbp
mov rbp,rsp
push rbx
push r12
push r13
push r14
push r15
%endmacro
%macro epilogue 0
pop r15
pop r14
pop r13
pop r12
pop rbx
leave
ret
%endmacro
section .rodata
int_format db "%i",0
string_format db "%s",0
section .text
global print_string2, print_nl2, print_int, read_int
global print_string, print_nl
extern printf, scanf, putchar
print_string2:
prologue
; argument is already in rdi
mov rcx,dword -1
xor al,al
cld
repnz scasb
mov rdx,dword -2
sub rdx,rcx
mov rsi,rdi
push 0x1
pop rax
mov rdi,rax
syscall
epilogue
print_nl2:
prologue
; print 0xa is only one byte
push 0xA
mov rsi,rsp
push 0x1
pop rdx
mov rdi,rdx
mov rax,rdx
syscall
pop rcx
epilogue
print_string:
prologue
mov rsi,rdi
mov rdi,dword string_format
xor rax,rax
call printf
epilogue
print_nl:
prologue
mov rdi,0xA
xor rax,rax
call putchar
epilogue
print_int:
prologue
;arg is in rdi
mov rsi, rdi
mov rdi, dword int_format
xor rax,rax
call printf
epilogue
read_int:
prologue
;rdi is assumed to have the address of the int to be read in
mov rsi, rdi
mov rdi, dword int_format
xor rax,rax
call scanf
epilogue
Build Script
I noticed the linker error for the non supplied section, but it doesn't seem required for the build to run.
└─$ make prime
yasm -f elf64 prime.asm
yasm -f elf64 asm_io.asm
ld -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 \
/usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o \
asm_io.o prime.o /usr/lib/x86_64-linux-gnu/crtn.o -lc -o prime.out
ld: warning: prime.o: missing .note.GNU-stack section implies executable stack
ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker
Debug Inspection
I noticed that there was a missing file. Is it possible that GLibc is not linked correctly?
$ gdb prime.out
GNU gdb (Debian 13.2-1) 13.2
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from prime.out...
(No debugging symbols found in prime.out)
(gdb) b main
Breakpoint 1 at 0x4011b4
(gdb) run
Starting program: /home/kali/Desktop/assembly/prime.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, 0x00000000004011b4 in main ()
(gdb) l
1 ./elf/sofini.c: No such file or directory.
(gdb) s
Single stepping until exit from function main,
which has no line number information.
zRx
rogram received signal SIGSEGV, Segmentation fault.
0x00007ffff7e27f82 in __vfscanf_internal (s=0x7ffff7f9eaa0 <_IO_2_1_stdin_>, format=0x402004 "%i",
argptr=argptr@entry=0x7fffffffdc58, mode_flags=mode_flags@entry=0) at ./stdio-common/vfscanf-internal.c:339
339 ./stdio-common/vfscanf-internal.c: No such file or directory.
(gdb) q
A debugging session is active.
Inferior 1 [process 70321] will be killed.
ldd output
└─$ ldd prime.out
linux-vdso.so.1 (0x00007fffebb91000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f88a63ee000)
/lib64/ld-linux-x86-64.so.2 (0x00007f88a65e8000)
So my guess is that there are possibly three errors with this tutorial code.
- GLibC might not be included properly with LD
- Using 32-bit registers improperly with 64-bit registers
- Variables not getting set properly.
Either way, I need help and to get out of this Segmentation fault. Please help.
Update
Compiling now with:
prime_gcc:
yasm -f elf64 prime.asm
yasm -f elf64 asm_io.asm
gcc -Wall -m64 -no-pie prime.o asm_io.o -o prime_gcc.out
GDB Logs
┌──(kali㉿kali)-[~/Desktop/assembly]
└─$ gdb prime_gcc.out
GNU gdb (Debian 13.2-1) 13.2
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from prime_gcc.out...
(No debugging symbols found in prime_gcc.out)
(gdb) b main
Breakpoint 1 at 0x401154
(gdb) run
Starting program: /home/kali/Desktop/assembly/prime_gcc.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, 0x0000000000401154 in main ()
(gdb) si
0x0000000000401155 in main ()
(gdb) si
0x0000000000401157 in main ()
(gdb) l
1 ./elf/sofini.c: No such file or directory.
(gdb) si
0x0000000000401159 in main ()
(gdb) l
1 in ./elf/sofini.c
(gdb) si
0x000000000040115b in main ()
(gdb) l
1 in ./elf/sofini.c
(gdb) si
0x000000000040115d in main ()
(gdb) l
1 in ./elf/sofini.c
(gdb) si
0x000000000040115e in main ()
(gdb) l
1 in ./elf/sofini.c
(gdb) si
0x0000000000401165 in main ()
(gdb) si
0x0000000000401230 in print_string2 ()
(gdb) l
1 in ./elf/sofini.c
(gdb) si
0x0000000000401231 in print_string2 ()
(gdb) l
1 in ./elf/sofini.c
(gdb) si
0x0000000000401234 in print_string2 ()
(gdb) l
1 in ./elf/sofini.c
(gdb) si
0x0000000000401235 in print_string2 ()
(gdb) l
1 in ./elf/sofini.c
(gdb) si
0x0000000000401237 in print_string2 ()
(gdb) x/i $pc
=> 0x401237 <print_string2+7>: push %r13
(gdb) si
0x0000000000401239 in print_string2 ()
(gdb) x/i $pc
=> 0x401239 <print_string2+9>: push %r14
(gdb) si
0x000000000040123b in print_string2 ()
(gdb) x/i $pc
=> 0x40123b <print_string2+11>: push %r15
(gdb) si
0x000000000040123d in print_string2 ()
(gdb) x/i $pc
=> 0x40123d <print_string2+13>: mov $0xffffffffffffffff,%rcx
(gdb) si
0x0000000000401244 in print_string2 ()
(gdb) x/i $pc
=> 0x401244 <print_string2+20>: xor %al,%al
(gdb) si
0x0000000000401246 in print_string2 ()
(gdb) x/i $pc
=> 0x401246 <print_string2+22>: cld
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) x/i $pc
=> 0x401247 <print_string2+23>: repnz scas %es:(%rdi),%al
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) x/i $pc
=> 0x401247 <print_string2+23>: repnz scas %es:(%rdi),%al
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) x/i $pc
=> 0x401247 <print_string2+23>: repnz scas %es:(%rdi),%al
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) x/i $pc
=> 0x401247 <print_string2+23>: repnz scas %es:(%rdi),%al
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) x/i $pc
=> 0x401247 <print_string2+23>: repnz scas %es:(%rdi),%al
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) x/i $pc
=> 0x401247 <print_string2+23>: repnz scas %es:(%rdi),%al
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) x/i $pc
=> 0x401247 <print_string2+23>: repnz scas %es:(%rdi),%al
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) x/i $pc
=> 0x401247 <print_string2+23>: repnz scas %es:(%rdi),%al
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) x/i $pc
=> 0x401247 <print_string2+23>: repnz scas %es:(%rdi),%al
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) x/i $pc
=> 0x401247 <print_string2+23>: repnz scas %es:(%rdi),%al
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) x/i $pc
=> 0x401247 <print_string2+23>: repnz scas %es:(%rdi),%al
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) x/i $pc
=> 0x401247 <print_string2+23>: repnz scas %es:(%rdi),%al
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) x/i $pc
=> 0x401247 <print_string2+23>: repnz scas %es:(%rdi),%al
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) x/i $pc
=> 0x401247 <print_string2+23>: repnz scas %es:(%rdi),%al
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb)
0x0000000000401247 in print_string2 ()
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) si
0x0000000000401247 in print_string2 ()
(gdb) si
0x0000000000401249 in print_string2 ()
(gdb) si
0x0000000000401250 in print_string2 ()
(gdb) x/i $pc
=> 0x401250 <print_string2+32>: sub %rcx,%rdx
(gdb) si
0x0000000000401253 in print_string2 ()
(gdb) si
0x0000000000401256 in print_string2 ()
(gdb) x/i $pc
=> 0x401256 <print_string2+38>: push $0x1
(gdb) si
0x0000000000401258 in print_string2 ()
(gdb) x/i $pc
=> 0x401258 <print_string2+40>: pop %rax
(gdb) si
0x0000000000401259 in print_string2 ()
(gdb) x/i $pc
=> 0x401259 <print_string2+41>: mov %rax,%rdi
(gdb) si
0x000000000040125c in print_string2 ()
(gdb) x/i $pc
=> 0x40125c <print_string2+44>: syscall
(gdb) si
%i%s$0x000000000040125e in print_string2 ()
(gdb) x/i $pc
=> 0x40125e <print_string2+46>: pop %r15
(gdb) si
0x0000000000401260 in print_string2 ()
(gdb) x/i $pc
=> 0x401260 <print_string2+48>: pop %r14
(gdb) si
0x0000000000401262 in print_string2 ()
(gdb) x/i $pc
=> 0x401262 <print_string2+50>: pop %r13
(gdb) si
0x0000000000401264 in print_string2 ()
(gdb) x/i $pc
=> 0x401264 <print_string2+52>: pop %r12
(gdb) si
0x0000000000401266 in print_string2 ()
(gdb) x/i $pc
=> 0x401266 <print_string2+54>: pop %rbx
(gdb) si
0x0000000000401267 in print_string2 ()
(gdb) x/i $pc
=> 0x401267 <print_string2+55>: leave
(gdb) si
0x0000000000401268 in print_string2 ()
(gdb) x/i $pc
=> 0x401268 <print_string2+56>: ret
(gdb) si
0x000000000040116a in main ()
(gdb) x/i $pc
=> 0x40116a <main+26>: mov $0x404030,%rdi
(gdb) si
0x0000000000401171 in main ()
(gdb) x/i $pc
=> 0x401171 <main+33>: call 0x40130d <read_int>
(gdb) si
0x000000000040130d in read_int ()
(gdb) x/i $pc
=> 0x40130d <read_int>: push %rbp
(gdb) si
0x000000000040130e in read_int ()
(gdb) x/i $pc
=> 0x40130e <read_int+1>: mov %rsp,%rbp
(gdb) si
0x0000000000401311 in read_int ()
(gdb) x/i $pc
=> 0x401311 <read_int+4>: push %rbx
(gdb) si
0x0000000000401312 in read_int ()
(gdb) x/i $pc
=> 0x401312 <read_int+5>: push %r12
(gdb) si
0x0000000000401314 in read_int ()
(gdb) x/i $pc
=> 0x401314 <read_int+7>: push %r13
(gdb) si
0x0000000000401316 in read_int ()
(gdb) x/i $pc
=> 0x401316 <read_int+9>: push %r14
(gdb) si
0x0000000000401318 in read_int ()
(gdb) x/i $pc
=> 0x401318 <read_int+11>: push %r15
(gdb) si
0x000000000040131a in read_int ()
(gdb) x/i $pc
=> 0x40131a <read_int+13>: mov %rdi,%rsi
(gdb) si
0x000000000040131d in read_int ()
(gdb) x/i $pc
=> 0x40131d <read_int+16>: mov $0x402018,%rdi
(gdb) si
0x0000000000401324 in read_int ()
(gdb) x/i $pc
=> 0x401324 <read_int+23>: xor %rax,%rax
(gdb) si
0x0000000000401327 in read_int ()
(gdb) x/i $pc
=> 0x401327 <read_int+26>: call 0x401050 <scanf@plt>
(gdb) si
0x0000000000401050 in scanf@plt ()
(gdb) x/i $pc
=> 0x401050 <scanf@plt>: jmp *0x2fba(%rip) # 0x404010 <[email protected]>
(gdb) si
0x0000000000401056 in scanf@plt ()
(gdb) x/i $pc
=> 0x401056 <scanf@plt+6>: push $0x2
(gdb) si
0x000000000040105b in scanf@plt ()
(gdb) x/i $pc
=> 0x40105b <scanf@plt+11>: jmp 0x401020
(gdb) si
0x0000000000401020 in ?? ()
(gdb) x/i $pc
=> 0x401020: push 0x2fca(%rip) # 0x403ff0
(gdb)