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.
Related
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?
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.
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.
So I'm confused. I'm going through the book "Programming from the Ground Up" and am working with using libraries.
printf is working just fine so long as I include a "\n" in the string, but without it it will print absolutely nothing.
Any idea why this happens?
Code:
.section .data
my_str:
.ascii "Jimmy Joe is %d years old!\n\0"
my_num:
.long 76
.section .text
.globl _start
_start:
pushl my_num
pushl $my_str
call printf
movl $1, %eax
movl $0, %ebx
int $0x80
Also, when I use -m elf_i386 for 32-bit mode and -dynamic-linker /lib/ld-linux.so.2 -lc to link, I get the warning
ld: skipping incompatible /usr/lib64/libc.so when searching for -lc
If that makes any difference, or if anybody has any suggestions as to how to have it load the 32-bit library directly.
Thanks!
The problem is that printf by default just prints stuff into the stdout buffer. Things won't actually be printed until the buffer is flushed. The depends on the buffering mode of stdout, but, by default, it is line-buffered, which means it gets flushed every time you print a newline character.
To flush explicitly in C, you call fflush; you can do that in asm code with
pushl stdout
call fflush
addl $4, %esp
Alternately, you can call the stdlib exit function (which flushes all I/O buffers before actually exiting), instead of using the _exit system call, which does not.
It seems you try to link your 32-bit program against the (system default) 64Bit c library.
Check if you have libs32 packages installed.
To find out which libraries a program or other dynamically loads froum the LD_LIBRARY_PATH use ldd <name_of_your_binary>
As to why the newline is required I can only speculate that it flushes the output buffer.
See also Why does printf not flush after the call unless a newline is in the format string?
The following x86 assembly code assembles fine, and it used to run flawlessly on my school's linux server, but when applying the same code to my linux virtual machine (ubuntu 14.04, all of a sudden it causes a segmentation fault.
Did stack conventions change, is this a GNU assembler problem? What memo did I miss?
I am running on a 64-bit machine, and this is a warm-up to building the backbone of an OS, so I need to be able to use the 16-bit real, 32-bit protected, and the 64-bit mode all in the same program. So I suppose what I really need is the little details about making all modes valid in the same program. I know to use .code16/32/64 when changing modes, but I guess what I'm missing (and can't seem to find in any OS tutorial, is how to do this on 64-bit architecture.
.code32
.text
.global _start
_start:
pushl $str1
pushl $len1
call print
addl $8, %esp <-cleans up the stack pointer
exit:
movl $1, %eax
movl $0, %ebx
int $0x80
print:
pushl %ebp
movl %esp, %ebp
movl $4, %eax
movl $1, %ebx
movl 12(%ebp), %ecx <- This is where the Seg Fault occurs according to GDB
movl 8(%ebp), %edx
int $0x80
popl %ebp
ret
.data
str1 : .ascii "String1\n"
len1 = . - str1
I'm guessing that you have a 64-bit machine, while your program is obviously 32-bit.
I have a 64-bit machine, if I compile it with this command, it fails, same line as you:
$ gcc -nostdlib test.s
However, if I compile a 32-bit executable:
$ gcc -nostdlib -m32 test.s
And all is fine.
Note that you may need some packages to be able to compile a 32-bit program in a 64-bit machine (g++-multilib or whatever they call it these days).