I'm interesting in compile a 32bit assembly code using a 64bit machine.
This is the 32 bit code:
.global factorial
factorial:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
pushl %esi
pushl %ebx
movl $1,-4(%ebp)
movl $2,%esi
for:
cmpl 8(%ebp), %esi
jg endfor
movl -4(%ebp), %ebx
imull %esi, %ebx
movl %ebx, -4(%ebp)
incl %esi
jmp for
endfor:
movl -4(%ebp), %eax
popl %ebx
popl %esi
movl %ebp, %esp
popl %ebp
ret
I'm building:
> gcc test32.s -m32 -o test32
But I'm obtaining:
/usr/lib/gcc/x86_64-linux-gnu/4.6.1/../../../../lib32/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
collect2: ld returned 1 exit status
know someone who's going? Thanks in advance!
You are trying to compile and link to an executable. For that to work, you need a main function that contains the programs start function.
All you have is a single mathematical function, without any way to define inputs and outputs.
Related
Full disclosure the following code is for a homework, but I wrote the code I just need help figuring out why I'm getting several errors when trying to compile it (My professor never talked about GCC errors).
I wrote a function that returns the sum of the two largest members of an array of size 10. I've marked the lines 70 and 74:
function1:
pushl %ebp
pushl %ebx
movl $2, %ebx #ebx will be counter
movl %esp, %ebp #first will be %edx and second will be %eax
movl 8(%ebp), %edx #first = arr[0]
movl (%edx,1,4), %eax #second = arr[1] **LINE 70**
cmpl %eax, %edx #if(arr[0] > arr[1]) don't jump
jle .L6
.L7:
movl (8(%ebp),%ebx,4), %ecx #%ecx = next value to compare **LINE 74**
cmpl %ecx, %edx #if first > next don't jump
jle .L8
cmpl %ecx, %eax #if second > next don't jump
jle .L9
cmpl $9, %ebx #check if counter = 9
je .L10
addl $1, %ebx #counter++
jmp .L7
.L6:
movl %edx, %ecx #move arr[0] into %ecx
movl %eax, %edx #first = arr[1]
movl %ecx, %eax #second = arr[0]
jmp .L7
.L8:
movl %edx, %eax #move previous first into second
movl %ecx, %edx #move new first into first
addl $1, %ebx #counter++
jmp .L7
.L9:
movl %ecx, %eax #move new second into second
addl $1, %ebx #counter++
jmp .L7
.L10:
addl %edx, %eax
popl %ebx
popl %ebp
ret
I am getting the following error messages:
assign3.s:70: Error: expecting `)' after scale factor in `(%edx,1,4)'
assign3.s:74: Error: missing ')'
assign3.s:74: Error: missing ')'
assign3.s:74: Error: junk `(%ebp),%ebx,4))' after expression
I appreciate the help and let me know how I can improve my questions in the future
I had to rework my code completely but thanks to #fuz I was able to find the proper solution. My problem was both in syntax and in understanding of registers and pointers. Here's the correct code:
function1:
#FIRST %edx
#SECOND %eax
#THIRD %ebx
#LOCATION OF ARRAY %esi
#COUNTER %edi
pushl %ebp
pushl %ebx
pushl %esi
pushl %edi
movl %esp, %ebp
movl $1, %edi
movl %eax, %esi
movl (%esi), %edx
movl (%esi, %edi, 4), %eax
addl $1, %edi
cmpl %eax, %edx
jle .L6
.L7:
movl (%esi, %edi, 4), %ebx
cmpl %ebx, %edx
jle .L8
cmpl %ebx, %eax
jle .L9
.L11:
addl $1, %edi
cmpl $10, %edi
jne .L7
jmp .L10
.L6: #Switch FIRST and SECOND
movl %edx, %ebx
movl %eax, %edx
movl %ebx, %eax
.L8: #THIRD is bigger than FIRST
movl %edx, %eax
movl %ebx, %edx
jmp .L11
.L9: #THIRD is bigger than SECOND
movl %ebx, %eax
jmp .L11
.L10: #Add and return
addl %edx, %eax
popl %edi
popl %esi
popl %ebx
popl %ebp
ret
In this application, I am trying to print a character passed through command line arguments (Intel Mac OS X). EX:
./thisapp q
Desired output:
q
However, it prints out a bunch of symbols and nonsense, but what is interesting is that different characters produce different gibberish. This leads me to believe that I am close. Does this need to be "formatted" for it to produce the correct letter?
.section __DATA,__data
.section __TEXT,__text
.globl _start
_start:
push %rbp
mov %rsp,%rbp
lea -32(%rsp), %r10 #<--- should be argv
add $8, %r10 #<--- should be argv[1]
movl $0x2000004, %eax
mov $1, %edi
mov %r10, %rsi
mov $16, %edx
syscall
xor %rax, %rax
mov $0x2000001, %eax
mov $0, %edi
syscall
Thanks to everyone's help I was able to get this working. Here is the code in the event someone else is looking to do this:
.section __DATA,__data
.section __TEXT,__text
.globl _start
_start:
push %rbp
mov %rsp,%rbp
lea 24(%rbp), %r10
movl $0x2000004, %eax
mov $1, %edi
mov (%r10), %rsi
mov $1, %edx
syscall
xor %rax, %rax
mov $0x2000001, %eax
mov $0, %edi
syscall
I would like to point out that this will only print 1 element (letter/number). I still need to figure out how to get the length(size?) of whatever was passed.
I'm tring to compile the following assembly code into shared library (dll)
.extern _GetProcAddress
.global _main
_main:
CALL _GetProcAddress
using the following commend:
i686-w64-mingw32-gcc -shared -o file.dll file.S
but I'm getting the following link error:
`_GetProcAddress' referenced in section `.text' of /tmp/ccamwU4N.o: defined in discarded section `.text' of /usr/lib/gcc/i686-w64-mingw32/4.6/../../../../i686-w64-mingw32/lib/../lib/libkernel32.a(dxprbs00553.o)
how can I fix this error and call winapi functions?
This code:
// file: winapi0.s
.extern ___main
.extern _GetStdHandle#4
.extern _WriteConsoleA#20
.data
_text:
.ascii "Hello World!\12\0"
.section .text.startup,"x"
.p2align 2,,3
.globl _main
_main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $52, %esp
call ___main
movl $-11, (%esp)
call _GetStdHandle#4
pushl %edx
movl $0, 16(%esp)
leal -12(%ebp), %edx
movl %edx, 12(%esp)
movl $14, 8(%esp)
movl $_text, 4(%esp)
movl %eax, (%esp)
call _WriteConsoleA#20
subl $20, %esp
xorl %eax, %eax
movl -4(%ebp), %ecx
leave
leal -4(%ecx), %esp
ret
Compiles for me just fine with:
gcc -Wall -O2 winapi0.s -o winapi0.exe
And it works by printing this:
Hello World!
It's a slightly cleaned up version of this C code translated by gcc into assembly with the -S switch:
// file: winapi.c
#include <windows.h>
#include <tchar.h>
TCHAR text[] = _T("Hello World!\n");
int main(void)
{
DWORD err;
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),
text,
sizeof(text) / sizeof(text[0]),
&err,
NULL);
return 0;
}
I got originally this:
.file "winapi.c"
.def ___main; .scl 2; .type 32; .endef
.section .text.startup,"x"
.p2align 2,,3
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB14:
.cfi_startproc
leal 4(%esp), %ecx
.cfi_def_cfa 1, 0
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
.cfi_escape 0x10,0x5,0x2,0x75,0
pushl %ecx
.cfi_escape 0xf,0x3,0x75,0x7c,0x6
subl $52, %esp
call ___main
movl $-11, (%esp)
call _GetStdHandle#4
pushl %edx
movl $0, 16(%esp)
leal -12(%ebp), %edx
movl %edx, 12(%esp)
movl $14, 8(%esp)
movl $_text, 4(%esp)
movl %eax, (%esp)
call _WriteConsoleA#20
subl $20, %esp
xorl %eax, %eax
movl -4(%ebp), %ecx
.cfi_def_cfa 1, 0
leave
leal -4(%ecx), %esp
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE14:
.globl _text
.data
_text:
.ascii "Hello World!\12\0"
.def _GetStdHandle#4; .scl 2; .type 32; .endef
.def _WriteConsoleA#20; .scl 2; .type 32; .endef
Can't you do the same for the 64-bit case?
Link with the import library for the Windows DLL that contains the function you want to call.
I believe that symbol is contained in kernel32.dll. You'll need to make an import library and then link with it.
I have to create a program in assembly that takes a user's input as a maximum array size then let's the user create an array of that size.
I'm supposed to buffer that value to a maximum of 1000 array items (all ints)
Then I have to run a selection sort on the array and output.
I've found the following selection sort on the IBM website.
.section .data
array:
.byte 89, 10, 67, 1, 4, 27, 12, 34, 86, 3
array_end:
.equ ARRAY_SIZE, array_end - array
array_fmt:
.asciz " %d"
usort_str:
.asciz "unsorted array:"
sort_str:
.asciz "sorted array:"
newline:
.asciz "\n"
.section .text
.globl main
main:
pushl $usort_str
call puts
addl $4, %esp
pushl $ARRAY_SIZE
pushl $array
pushl $array_fmt
call print_array10
addl $12, %esp
pushl $ARRAY_SIZE
pushl $array
call sort_routine20
# Adjust the stack pointer
addl $8, %esp
pushl $sort_str
call puts
addl $4, %esp
pushl $ARRAY_SIZE
pushl $array
pushl $array_fmt
call print_array10
addl $12, %esp
jmp _exit
print_array10:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %edx
movl 12(%ebp), %ebx
movl 16(%ebp), %ecx
movl $0, %esi
push_loop:
movl %ecx, -4(%ebp)
movl 8(%ebp), %edx
xorl %eax, %eax
movb (%ebx, %esi, 1), %al
pushl %eax
pushl %edx
call printf
addl $8, %esp
movl -4(%ebp), %ecx
incl %esi
loop push_loop
pushl $newline
call printf
addl $4, %esp
movl %ebp, %esp
popl %ebp
ret
sort_routine20:
pushl %ebp
movl %esp, %ebp
# Allocate a word of space in stack
subl $4, %esp
# Get the address of the array
movl 8(%ebp), %ebx
# Store array size
movl 12(%ebp), %ecx
decl %ecx
# Prepare for outer loop here
xorl %esi, %esi
outer_loop:
# This stores the min index
movl %esi, -4(%ebp)
movl %esi, %edi
incl %edi
inner_loop:
cmpl $ARRAY_SIZE, %edi
jge swap_vars
xorb %al, %al
movl -4(%ebp), %edx
movb (%ebx, %edx, 1), %al
cmpb %al, (%ebx, %edi, 1)
jge check_next
movl %edi, -4(%ebp)
check_next:
incl %edi
jmp inner_loop
swap_vars:
movl -4(%ebp), %edi
movb (%ebx, %edi, 1), %dl
movb (%ebx, %esi, 1), %al
movb %dl, (%ebx, %esi, 1)
movb %al, (%ebx, %edi, 1)
incl %esi
loop outer_loop
movl %ebp, %esp
popl %ebp
ret
exit:
movl $1, %eax
movl 0, %ebx
int $0x80
I've gone through it and I can make sense of 90% of what's going on so I'm happy with that.
What I have no idea where to even begin is how do I take the user input and create an array with it? And how do I use the buffer to set a limit to the array size?
Any help is very much appreciated!
This program is not interactive. The "input" is given in the line array
array:
.byte 89, 10, 67, 1, 4, 27, 12, 34, 86, 3
and can only be changes during compile time. If you need to take a user input, you would need to make calls to the appropriate kernel functions or standard library functions.
http://linux.die.net/man/2/read with the stdin file descriptor (very low level, but you are writeing assembler) or http://www.manpagez.com/man/3/scanf/ (the C function).
You also get an overview with "man scanf" in the command line.
You put the arguments you want to give to the functions in reverse order on the stack, call the function, and readjust the stack. How the arguments are given to the functions is depending on the architecture and the operating system. It is defined in the application binary interface ("ABI"). See http://www.scribd.com/doc/48244725/abi386-4 under "function calling sequence", assuming you are on a i386.
You can reserve 1000 bytes in the .bss section with
.section .bss
buffer: .space 1000
Or you can use "malloc".
I wrote the following code in AT&T Assembler Syntax for gcc
.global main
.section .data
to_gen_inner: #x f, implicit n
pushl %ebp
movl %esp, %ebp
movl $0xFF00FF00, %eax
call printregs
lret
.set to_gen_inner_len, . - to_gen_inner
.section .text
main:
pushl %ebp
movl %esp, %ebp
#allocate memory
pushl $to_gen_inner_len
call malloc
popl %ecx
pushl $to_gen_inner_len
pushl to_gen_inner
pushl %eax
call copy_bytes
popl %eax
popl %ecx
popl %ecx
lcall *(%eax)
movl %ebp, %esp
popl %ebp
ret
printfregs:
.ascii "eax: %8X\nebx: %8X\necx: %8X\nedx: %8X\n\0"
printregs:
pushl %edx
pushl %ecx
pushl %ebx
pushl %eax
pushl $printfregs
call printf
popl %ecx
popl %eax
popl %ebx
popl %ecx
popl %edx
lret
copy_bytes: #dest source length
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl 8(%ebp), %ecx # dest
movl %eax, -4(%ebp)
movl 12(%ebp), %ebx # source
movl %eax, -8(%ebp)
movl 16(%ebp), %eax # length
movl %eax, -12(%ebp)
addl %eax, %ecx # last dest-byte
movl %ecx, -16(%ebp)
addl %eax, %edx # last source-byte
movl %ecx, -20(%ebp)
movl -4(%ebp), %eax
movl -8(%ebp), %ebx
movl -16(%ebp), %ecx
copy_bytes_2:
movb (%ebx), %dl
movb %dl, (%eax)
incl %eax
incl %ebx
cmp %eax, %ecx
jne copy_bytes_2
movl %ebp, %esp
popl %ebp
ret
Actually, what i want to do is copying the function code of to_gen_inner into the memory I am allocating with malloc, and then jump into it. This code produces a segmentation fault. gdb sais:
Program received signal SIGSEGV, Segmentation fault.
main () at speicher3.S:32
32 lcall *(%eax)
Current language: auto; currently asm
(gdb) disas $pc-5 $pc+5
Dump of assembler code from 0x80483eb to 0x80483f5:
0x080483eb <main+23>: add %al,(%eax)
0x080483ed <main+25>: pop %eax
0x080483ee <main+26>: pop %ecx
0x080483ef <main+27>: pop %ecx
0x080483f0 <main+28>: lcall *(%eax)
0x080483f2 <main+30>: mov %ebp,%esp
0x080483f4 <main+32>: pop %ebp
End of assembler dump.
(gdb) disas $pc-6 $pc+5
Dump of assembler code from 0x80483ea to 0x80483f5:
0x080483ea <main+22>: add %al,(%eax)
0x080483ec <main+24>: add %bl,0x59(%eax)
0x080483ef <main+27>: pop %ecx
0x080483f0 <main+28>: lcall *(%eax)
0x080483f2 <main+30>: mov %ebp,%esp
0x080483f4 <main+32>: pop %ebp
End of assembler dump.
(gdb)
I actually dont know why. I am already using lcall and lret, which I read is thought for absolute calls, with call and ret, it didnt work either, same error.
I dont know what I could be doing wrong. Can anybody please help me?
You have the following problems:
when setting up the stack for your call to copy_bytes, you want pushl $to_gen_inner not pushl to_gen_inner (the latter pushes the contents of memory to_gen_inner points to)
when copying values to the local stackframe inside copy_bytes, you need to write the register you just read the parameter into, instead of always writing EAX
lcall *(%eax) expects to read an address from the memory pointed to by EAX, and jump there. Moreover, it expects to read 48 bytes, with the first 16 being the segment. I've replaced your lcall with call *%eax; also replaced the lrets with rets accordingly.
the call to printregs is assembled as a relative call, which blows up since the instruction you're executing is no longer at the same relative offset to the target as it was when it was assembled. I've replaced it with
movl $printregs, %ecx
call *%ecx
(which trashes %ecx)
finally, to_gen_inner sets up the stackframe on entry, but fails to destroy it on exit
With all those fixed, the code looks like this:
.global main
.section .data
to_gen_inner: #x f, implicit n
pushl %ebp
movl %esp, %ebp
movl $0xFF00FF00, %eax
movl $printregs, %ecx
call *%ecx
movl %ebp, %esp
popl %ebp
ret
.set to_gen_inner_len, . - to_gen_inner
.section .text
main:
pushl %ebp
movl %esp, %ebp
#allocate memory
pushl $to_gen_inner_len
call malloc
popl %ecx
pushl $to_gen_inner_len
pushl $to_gen_inner
pushl %eax
call copy_bytes
popl %eax
popl %ecx
popl %ecx
call *%eax
movl %ebp, %esp
popl %ebp
ret
printfregs:
.ascii "eax: %8X\nebx: %8X\necx: %8X\nedx: %8X\n\0"
printregs:
pushl %edx
pushl %ecx
pushl %ebx
pushl %eax
pushl $printfregs
call printf
popl %ecx
popl %eax
popl %ebx
popl %ecx
popl %edx
ret
copy_bytes: #dest source length
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl 8(%ebp), %ecx # dest
movl %ecx, -4(%ebp)
movl 12(%ebp), %ebx # source
movl %ebx, -8(%ebp)
movl 16(%ebp), %eax # length
movl %eax, -12(%ebp)
addl %eax, %ecx # last dest-byte
movl %ecx, -16(%ebp)
addl %eax, %edx # last source-byte
movl %ecx, -20(%ebp)
movl -4(%ebp), %eax
movl -8(%ebp), %ebx
movl -16(%ebp), %ecx
copy_bytes_2:
movb (%ebx), %dl
movb %dl, (%eax)
incl %eax
incl %ebx
cmp %eax, %ecx
jne copy_bytes_2
movl %ebp, %esp
popl %ebp
ret
...which builds and runs here for me. Hope that helps.