x86 GNU Assembler Strange Change Seg Fault - linux

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).

Related

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.

Compiling Linux assembler on Windows

.string "Hello\n"
.globl main
main:
pushl %ebp
movl %esp, %ebp
pushl $hello
call puts
movl $0, %eax
movl %ebp, %esp
popl %ebp
ret
This code works on 32bit Linux. How can I run this on Windows?
gcc hello.s
You need to find a Windows version of an x86 assembler. The GNU Assembler is available on Windows through the MinGW project. This is the same assembler you are using on Linux.

Problems with accessing command line arguments in linux from x86 asm

I have a basic asm program that checks if a string is a digit. I was adding in code to read from command line arguements, put it keeps seg faulting.
if what I have read is right, this should get the amount of arguments passed to the program, which should be stored in 0(%ebp). What am i doing wrong?
The entirity of the code can be found here: http://pastebin.com/kGV2Mxx4
The problem is the first 3-5 lines of _start.
upon Looking at lscpu's output, I have an i868 cpu. Although, it says it can operate in 32-bit and 64-bit. I am running 32 bit linux (Arch linux x86)
I fixed the issue. I did 2 pop's, one to bypass the programs name, the next to get the first argument. the updated code can be found here: http://pastebin.com/xewyeHYf
Can someone please tell me why I could not just do the following:
pushl 8(%ebp)
or
movl 8(%ebp), %eax
Here is a little tutorial I wrote on the subject:
NASM - Linux Getting command line parameters
You could write this:
_start:
b1: movl 0(%ebp), %eax
cmpl $1, %eax
je load_msg
b2: pushl 8(%ebp)
b4: call check
To understand why your previous attempts didn't work, draw stack diagrams.
Compile a small C program that does something like what you want to do, and compile it to assembly language to find out exactly how to access arguments. The x86_32 code doesn't look at all like any of the above, BTW:
int main(int argc, char *argv[])
{
return argv[1][0];
}
gives (yes, some is superfluous stack bookkeeping, but anyway):
.file "tst.c"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
movl 12(%ebp), %eax
addl $4, %eax
movl (%eax), %eax
movzbl (%eax), %eax
movsbl %al, %eax
popl %ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.7.2 20121109 (Red Hat 4.7.2-8)"
.section .note.GNU-stack,"",#progbits

Invalid instruction suffix for push when assembling with gas

When assembling a file with GNU assembler I get the following error:
hello.s:6: Error: invalid instruction suffix for `push'
Here's the file that I'm trying to assemble:
.text
LC0:
.ascii "Hello, world!\12\0"
.globl _main
_main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
call __alloca
call ___main
movl $LC0, (%esp)
call _printf
movl $0, %eax
leave
ret
What is wrong here and how do I fix it?
The problem is somewhat related to this question although errors and instructions in questions are different.
Prepend .code32 as your first line.
--32 option will change the target to 32 bit platform.
64bit instructions
By default most operations remain 32-bit and the 64-bit counterparts are invoked by the fourth bit in the REX prefix. This means that each 32-bit instruction has it's natural 64-bit extension and that extended registers are for free in 64-bit instructions
movl $1, %eax # 32-bit instruction
movq $1, %rax # 64-bit instruction
pushl %eax # Illegal instruction
pushq %rax # 1 byte instruction encoded as pushl %eax in 32 bits
pushq %r10 # 2 byte instruction encoded as pushl preceeded by REX
Are you assembling with a 64-bit assembler? Your code looks like it's 32-bit. I get this error with your code when using a 64-bit assembler:
example.s:6:suffix or operands invalid for `push'
But it works fine with a 32-bit assembler.
You have to use a "64 bit syntax", or you can use the " --32 " option: by this way the assembler chages its target to the i386 platform.

Resources