Missing reference to system calls - linux

I was looking at this short introduction to assembly on Linux:
http://asm.sourceforge.net/articles/linasm.html#Compiling
I tried to compile the hello world program therein:
.data
hw:
.string "hello world\n"
.text
.globl _start
_start:
movl $SYS_write,%eax
movl $1,%ebx
movl $hw,%ecx
movl $12,%edx
int $0x80
movl $SYS_exit,%eax
xorl %ebx,%ebx
int $0x80
$ gcc -c hello.s
$ ld -s -o hello hello.o
ld: hello.o: in function `_start':
(.text+0x1): undefined reference to `SYS_write'
ld: (.text+0x17): undefined reference to `SYS_exit'
So, I suppose that I need to tell the linker about where to find those symbols. (I also know that I can lookup the constants somewhere in /usr/include and then include them as literals).
I suppose with the right invocation, this program would compile, what am I missing? Or is it just the case that this author is writing in a "meta language" where these $SYS_* items have to be replaced with a kernel specific constant, and I'm just too noob to assembly to recognize that?

Related

segfault for simple close program in assembly

I just started to learn assembly by following "Programming From The Ground Up" and already hit my first issue with the first ever program. I got a segfault for the following code which is supposed to be an exit program:
.section .data
.section .text
.global _start
_start:
movl $1, %eax
movl $0, %edi
int $0x80
I've looked into it and one thing suggested was to not use int $0x80 anymore since its a legacy way to invoke system call so I tried to use syscall instead but it didn't fix it.
the commands I used are as follow:
as test.s -o test.o
ld test.o -o test
./test
I am using the Windows Subsystem for Linux.
I tried to look at it in a debugger and what I found was that after my code, there would be an endless stream of add %al, (%rax) with each memory address from 0x40100c and onwards having this line.
I have absolutely no idea what is happening and would appreciate any help.

ld can not find symbol _start error after assemble and link .asm file to 64 bit executables

I have a shellcode file.
Then use ndisasm to build the assembly code.
ndisasm -b 64 shellcode > shellcode.asm
cat shellcode.asm | cut -c29->key.asm
I add 2 lines to the key.asm file
global_start:
_start:
$vi key.asm
global_start:
_start:
xor eax,eax
push rax
push qword 0x79237771
push qword 0x76772427
push qword 0x25747320
. . .
. . .
. . .
push qword 0x20757577
push rsp
pop rsi
mov edi,esi
mov edx,edi
cld
mov ecx,0x80
mov ebx,0x41
xor eax,eax
push rax
lodsb
xor eax,ebx
An then I assemble and link it to 64 bit executables
$nasm -f elf64 -g -F stabs key.asm
$ld -o key key.o
It gives me a warning
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400080
I tested it out with gcc
gcc -o key key.o
I still get an error almost the same as the first one
/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
And when I run ./key with gdb after I use $ld NOT $gcc
$gdb -q ./key
$run
I get a seg fault
Starting program: /mnt/c/Users/owner/Documents/U
M/Computer_Security/ExtraCredit/key
Program received signal SIGSEGV, Segmentation fault.
0x000000000040013a in global_start ()
If I debug after run with gcc then the file will not be found because of exit status
Can you explain why does it happen? And how can I fix this problem? Thanks
It gives me a warning
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400080
This isn't actually a problem, as long as you're fine with the entry point being the start of the text segment (i.e. the first instruction in your shellcode).
You got the error because you left out the space between the global keyword and the _start symbol name. i.e. use global _start, or don't bother. What you did defined a label called global_start, as you can see from your later error message.
You segfault on lodsb because you truncated a stack address with mov edi,esi instead of mov rdi, rsi. And if you fix that then you fall off the end of your code into garbage instructions because you don't make an exit system call. You're already running this inside gdb, use it!
I tested it out with gcc: gcc -o key key.o
I still get an error almost the same as the first one
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o:
In function `_start':
(.text+0x20): undefined reference to `main'
No, that's a totally different error. If you had exported _start correctly, you would have gotten an error for conflicting definitions of _start (between your code and the CRT start files).
This error is that the _start definition in crt1.o (provided by gcc) has a reference to main, but your code doesn't provide a main. This is what happens when you try to compile a C or C++ program that doesn't define main.
To link with gcc, use -nostdlib to omit the CRT start files and all other libraries. (i.e. link pretty much exactly like you were doing manually with ld.)
gcc -nostdlib -static key.o -o key # static executable: just your code
Or dynamically linked without the CRT start files, using your _start.
gcc -nostdinc -no-pie key.o -o key
You can call libc functions from code linked that way, but only on Linux or other platforms where dynamic linking takes care of running libc initialization functions.
If you statically link libc, you can only call functions like printf if you first call all the libc init functions that the normal CRT startup code does. (Not going into detail here because this code doesn't use libc)
Your code is wrong. Between global and _start must have a space. That is one of your problems.
section .text
global _start
_start:
xor eax,eax
push rax
...
In addition, to get why the segmentation fault is happening, you have to debug it. You could look the assembly instruction that does the segfault.
x/5i $eip

Why is GDB breakpoint set at the wrong address for an x86 assembly function?

I am experiencing an issue where gdb is mapping a line number to the wrong memory address when adding a breakpoint.
The following x86 Linux assembly program prints "hello".
/* hello.s */
.section .data
str:
.ascii "hello\n"
strlen = . - str
.section .text
print:
pushl %ebp
movl %esp, %ebp
pushl %ebx
movl $4, %eax
movl $1, %ebx
movl $str, %ecx
movl $strlen, %edx
int $0x80
popl %ebx
movl %ebp, %esp
popl %ebp
ret
.globl _start
_start:
call print
movl $1, %eax
movl $0, %ebx
int $0x80
I compile it with debugging information, and then link.
$ as -g --32 -o hello.o hello.s
$ ld -m elf_i386 -o hello hello.o
Next, in gdb, I try to set a breakpoint on line 11, the first line of the print function (pushl %ebp).
$ gdb ./hello
(gdb) break hello.s:11
Breakpoint 3 at 0x8048078: file hello.s, line 11.
As shown in the output, the breakpoint is set at address 0x8048078. However, that is the wrong address. When I run my program in gdb, it breaks at line 14. The address of line 11 is 0x8048074, confirmed using gdb's info command.
(gdb) info line hello.s:11
Line 11 of "hello.s" starts at address 0x8048074 and ends at 0x8048075 .
Setting a breakpoint on the print instruction directly works (the break point is set for the address of line 11, 0x8048074).
How come when I add a breakpoint for line 11, gdb does not use the same address as output by using the info command above? This is the memory address I am trying to break on.
I am experiencing the same behavior on both gdb 7.11.1 and 8.0.1. I have tried adding a .type print,#function annotation, but that did not solve my issue.
How come
By default, GDB tries to skip past function prolog, when you set a breakpoint on a function, or a line on which the function starts.
This tends to be what C developers want, since they usually aren't interested in parameter setup.
If you want something else, use b *address or b &print to prevent GDB from doing its usual thing.

Excecute program on Windows Bash?

I have write a little .s program witch have to print a little string on the monitor.
Then I opened the linux bash on windows 10 and done:
as -o file.o file.s
ld -o file file.o
./file
but it doesn't print anything
Why? I tried the same code on a linux virtual machine and it works
The file it is a simple "hello world" for learn Assembly at school
.section .data
hello:
.ascii "Hello, World!\n"
hello_len:
.long . - hello
.section .text
.global _start
_start:
movl $4, %eax
movl $1, %ebx
leal hello, %ecx
movl hello_len, %edx
int $0x80
movl $1, %eax
xor %ebx, %ebx
int $0x80
As WSL is currently in beta, some features are not functionnal yet. Running 32 bits ELF binaries is part of the missing features (the issue is logged on WSL github and uservoice).
Currently, to do what you want, your can either wait until the devs publish this feature or redo your program using the x86_64 instruction set that can be found here.

Cannot build 32-bit assembly after installing 32-bit support

I am trying to build an x86 executable on an x86_64 platform from assembly. I know that I need to install x86 support, so I've installed the libraries:
glibc-devel.i386
libstdc++-devel.i386
This allows me to successfully build and execute C programs in 32-bit mode via GCC:
gcc test.c -o test -m32
./test
Hello world!
However, I'm not able to assemble an x86 program from assembly:
$gcc -m32 template.s -o test
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
collect2: error: ld returned 1 exit status
Or alternately:
$as --32 template.s -o temp
$ld -melf_i386 temp -lc
ld: skipping incompatible /usr/lib64/libc.so when searching for -lc
ld: warning: cannot find entry symbol _start; defaulting to 00000000080481b0
$./a.out
-bash: ./a.out: /usr/lib/libc.so.1: bad ELF interpreter: No such file or directory
Any help would be greatly appreciated. I know I was able to get this running before, but it's been a long time and was on a different computer. The program template.s is below:
procedure:
movl 4(%esp), %eax
ret
main:
pushl %ebp
movl %esp, %ebp
pushl a
call procedure
pushl %eax
pushl $string
call printf
leave
ret
.section .rodata
string:
.string "result is %d\n"
.section .data
a:
.long -25

Resources