From what I understand, when a parameter is passed in a function call in C, the callee can find the first parameter at [ebp+8].
Returning a value through eax works for me, reading the right parameter value from the stack doesn't.
Right now I'm just trying to write an assembly function, that can be called from C and returns the same value, that it is being passed.
When I run the following program, it prints number: 1 to the console, no matter what value is passed into myFunc. What am I doing wrong?
assembly.s
section .text
global _myFunc
_myFunc:
mov eax, [ebp+8]
ret
main.c
#include <stdio.h>
extern unsigned int myFunc(unsigned int somedata);
int main() {
unsigned int i = myFunc(6);
printf("number: %i\n",i);
return 0;
}
I'm using a Mac, nasm to assemble the code and gcc for C compilation.
Makefile
macho32:
nasm -f macho32 assembly.s
gcc -m32 -o macho32 assembly.o main.c
You need to setup to access the the parameters first by saving esp. This is explained in:
http://www.nasm.us/doc/nasmdoc9.html
in section "9.1.2 Function Definitions and Function Calls"
The following works for me
assembly.s
section .text
global myFunc:function
myFunc:
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov esp, ebp
pop ebp
ret
main.c
#include <stdio.h>
extern unsigned int myFunc(unsigned int somedata);
int main() {
unsigned int i = myFunc(6);
printf("number: %i\n",i);
return 0;
}
Assembly & Compilation
ericu#eric-phenom-linux:~$ nasm -f elf32 assembly.s
ericu#eric-phenom-linux:~$ gcc -m32 assembly.o main.c
ericu#eric-phenom-linux:~$ ./a.out
number: 6
I am on a linux machine so I use elf32. The use of macho32 is correct on your Mac.
you refer to argument on stack, by reading from [EBP+offset] - has EBP been set up to actually point at stack? If no, you may have to do that first, conventionally done by:
push ebp
mov ebp,esp
Only then points EBP to its stacked previous contents, below stacked return address, and below passed arguments.
Your function should look like this,
_myFunc:
push ebp ; setup ebp as frame pointer
mov ebp, esp
mov eax, [ebp + 8]
leave ; mov esp,ebp / pop ebp
ret
The convention is to use ebp to access the parameters, to do so you need to save ebp on the stack and make it to point to the new top of the stack. At function exit you should restore ebp and esp, as the leave instruction does.
In nasm there is a macro package, c32.mak, that can help in supporting the C calling convention, these macros are arg, proc and endproc.
Using these macros your code should look like,
proc _myfunc
%$i arg
mov eax, [ebp + %$i]
endproc
Related
I have been trying to compile this C program to assembly but it hasn't been working fine.
I am reading
Dennis Yurichev Reverse Engineering for Beginner but I am not getting the same output. Its a simple hello world statement. I am trying to get the 32 bit output
#include <stdio.h>
int main()
{
printf("hello, world\n");
return 0;
}
Here is what the book says the output should be
main proc near
var_10 = dword ptr -10h
push ebp
mov ebp, esp
and esp, 0FFFFFFF0h
sub esp, 10h
mov eax, offset aHelloWorld ; "hello, world\n"
mov [esp+10h+var_10], eax
call _printf
mov eax, 0
leave
retn
main endp
Here are the steps;
Compile the print statement as a 32bit (I am currently running a 64bit pc)
gcc -m32 hello_world.c -o hello_world
Use gdb to disassemble
gdb file
set disassembly-flavor intel
set architecture i386:intel
disassemble main
And i get;
lea ecx,[esp+0x4]
and esp,0xfffffff0
push DWORD PTR [ecx-0x4]
push ebp
mov ebp,esp
push ebx
push ecx
call 0x565561d5 <__x86.get_pc_thunk.ax>
add eax,0x2e53
sub esp,0xc
lea edx,[eax-0x1ff8]
push edx
mov ebx,eax
call 0x56556030 <puts#plt>
add esp,0x10
mov eax,0x0
lea esp,[ebp-0x8]
pop ecx
pop ebx
pop ebp
lea esp,[ecx-0x4]
ret
I have also used
objdump -D -M i386,intel hello_world> hello_world.txt
ndisasm -b32 hello_world > hello_world.txt
But none of those are working either. I just cant figure out what's wrong. I need some help. Looking at you Peter Cordes ^^
The output from the book looks like MSVC, not GCC. GCC will definitely not ever emit main proc because that's MASM syntax, not valid GAS syntax. And it won't do stuff like var_10 = dword ptr -10h.
(And even if it did, you wouldn't see assemble-time constant definitions in disassembly, only in the compiler's asm output which is what the book suggested you look at. gcc -S -masm=intel output. How to remove "noise" from GCC/clang assembly output?)
So there are lots of differences because you're using a different compiler. Even modern versions of MSVC (on the Godbolt compiler explorer) make somewhat different asm, for example not bothering to align ESP by 16, perhaps because more modern Windows versions, or CRT startup code, already does that?
Also, your GCC is making PIE executables by default, so use -fno-pie -no-pie. 32-bit PIE sucks for efficiency and for ease of understanding. See How do i get rid of call __x86.get_pc_thunk.ax. (Also 32-bit absolute addresses no longer allowed in x86-64 Linux? for more about PIE executables, mostly focused on 64-bit code)
The extra clunky stack-alignment in main's prologue is something that GCC8 optimized for functions that don't also need alloca. But it seems even current GCC10 emits the full un-optimized version when you don't enable optimization :(.
Why is gcc generating an extra return address? and Trying to understand gcc's complicated stack-alignment at the top of main that copies the return address
Optimizing printf to puts: see How to get the gcc compiler to not optimize a standard library function call like printf? and -O2 optimizes printf("%s\n", str) to puts(str). gcc -fno-builtin-printf would be one way to make that not happen, or just get used to it. GCC does a few optimizations even at -O0 that other compilers only do at higher optimization levels.
MSVC 19.10 compiles your function like this (on the Godbolt compiler explorer) with optimization disabled (the default, no compiler options).
_main PROC
push ebp
mov ebp, esp
push OFFSET $SG4501
call _printf
add esp, 4
xor eax, eax
pop ebp
ret 0
_main ENDP
_DATA SEGMENT
$SG4501 DB 'hello, world', 0aH, 00H
GCC10.2 still uses an over-complicated stack alignment dance in the prologue.
.LC0:
.string "hello, world"
main:
lea ecx, [esp+4]
and esp, -16
push DWORD PTR [ecx-4]
push ebp
mov ebp, esp
push ecx
sub esp, 4
# end of function prologue, I think.
sub esp, 12 # make sure arg will be 16-byte aligned
push OFFSET FLAT:.LC0 # push a pointer
call puts
add esp, 16 # pop the arg-passing space
mov eax, 0 # return 0
mov ecx, DWORD PTR [ebp-4] # undo stack alignment.
leave
lea esp, [ecx-4]
ret
Yes, this is super inefficient. If you called your function anything other than main, it would already assume ESP was aligned by 16 on function entry:
# GCC10.2 -m32 -O0
.LC0:
.string "hello, world"
foo:
push ebp
mov ebp, esp
sub esp, 8 # reach a 16-byte boundary, assuming ESP%16 = 12 on entry
#
sub esp, 12
push OFFSET FLAT:.LC0
call puts
add esp, 16
mov eax, 0
leave
ret
So it still doesn't combine the two sub instructions, but you did tell it not to optimize so braindead code is expected. See Why does clang produce inefficient asm with -O0 (for this simple floating point sum)? for example.
My GCC will very eagerly swap a call to printf to puts! I did not manage to find the command line options that would make the compiler to not do this. I.e. the program has the same external behaviour but the machine code is that of
#include <stdio.h>
int main(void)
{
puts("hello, world");
}
Thus, you'll have really hard time trying to get the exact same assembly as in the book, as the assembly from that book has a call to printf instead of puts!
First of all you compile not decompile.
You get a lots of noise as you compile without the optimizations. If you compile with optimizations you will get much smaller code almost identical with the one you have (to prevent change from printf to puts you need to remove the '\n' https://godbolt.org/z/cs4qe9):
.LC0:
.string "hello, world"
main:
lea ecx, [esp+4]
and esp, -16
push DWORD PTR [ecx-4]
push ebp
mov ebp, esp
push ecx
sub esp, 16
push OFFSET FLAT:.LC0
call puts
mov ecx, DWORD PTR [ebp-4]
add esp, 16
xor eax, eax
leave
lea esp, [ecx-4]
ret
https://godbolt.org/z/xMqo33
I'm trying to make a program in C that uses a function from Assembly. Below you can see the code:
sum_c.c
#include <stdio.h>
extern int _assemblySum(int x, int y);
int main(int argc, char *argv[]){
int total;
total = _assemblySum(4, 2);
printf("%d\n", total);
return 0;
}
assembly_Sum.asm
SECTION .DATA
SECTION .TEXT
GLOBAL _assemblySum
_assemblySum:
push rbp
mov rbp, rsp
mov rax, [rbp+16]
mov rbx, [rbp+24]
add rax, rbx
pop rbp
ret
COMPILE
nasm -f elf64 assembly_sum.asm -o assembly_sum.o
gcc c_sum.c assembly_sum.o -o sum
./sum
When I run the program I just get random numbers like -1214984584 or 2046906200. I know that I need to use the registers rdi, rsi, rdx and rcx because the 64bit GNU/Linux compiler uses them (Passing arguments from C to 64bit linux Assembly). But how can I do that?
You may have confused which calling convention is being used.
Linux uses the 64-bit System V calling convention. Under this convention, registers are strongly preferred over the stack for the passing of INTEGER type parameters. The registers for integer passing are used in the following order:
%rdi
%rsi
%rdx
%rcx
%r8
%r9
If additional Integer parameters are used, they will be passed on the stack.
You can find detailed information in the System V ABI specification.
I'm trying to learn x86 assembler, and I want to call a NASM function in C. When i run my program I get this error:
Segmentation fault (Core dumped)
I've tried dozens of variations of my simple test function but it stops every time at the same position.
Here are my asm and c files:
div.asm:
global _test
_test:
push ebp
mov ebp, esp
push ebx
mov eax, [ebp+8]
mov ebx, [ebp+12]
div ebx
pop ebp
ret
main.c:
#include <stdio.h>
extern unsigned int test (unsigned int, unsigned int);
int main(void)
{
printf("%d\n", div(85,5));
return 0;
}
I compile & link the files with:
nasm -f elf -o div.o div.asm
gcc -m32 -c -o main.o main.c
gcc -m32 -o run div.o main.o
I use a 64 Bit Linux in a Virtual Machine.
What is my mistake here, and how can I fix it?
You forget to pop ebx (or at least make the stack in order):
push ebp
mov ebp, esp
push ebx ; you push it here
mov eax, [ebp+8]
mov ebx, [ebp+12]
xor edx,edx ; ..and you must zero edx
div ebx
pop ebx ; forgot to pop it here
pop ebp
ret
It is unclear if you ever got your problem solved. In addition to the other issues, you would need to make your function call in your main.c match the call in div.asm. For example if you have created an assembly function _test, you need to declare it as extern and actually use the function in main. e.g.:
#include <stdio.h>
extern unsigned int _test (unsigned int, unsigned int);
int main(void)
{
printf("%d\n", _test (85,5)); /* you are calling div here, not _test */
return 0;
}
(your function name is not the name for your assembly object file div.o -- and as pointed out in the comments, div is an unsigned division declared in stdlib.h along with ldiv, and lldiv)
Your global declaration in your assembly function file must match the name you declared in main. e.g.:
global _test
_test:
push ebp
mov ebp, esp
mov eax, [ebp+8]
xor edx, edx
div dword [ebp+12]
mov esp, ebp
pop ebp
ret
Now, you can compile, link and run your test file:
$ nasm -f elf -o div.o div.asm
$ gcc -m32 -c -o main.o main.c
$ gcc -m32 -o run div.o main.o
$./run
17
or for the compilation/link, simply:
$ nasm -f elf -o div.o div.asm
$ gcc -m32 -o run main.c div.o
I'm working with a project that implements a function in assembly that is called in a main.c. The signature function declaration in C is void strrev(char *str) ; The Ret instruction is giving me an illegal instruction error. Why? This is my first time doing this.
Trying to only post the relevant code:
SECTION .text
global strrev
strrev:
push ebp
mov ebp, esp
push esi
push edi
push ebx
// doing things with al, bl, ecx, edi, and esi registers here
// restore registers and return
mov esp, ebp
pop ebx
pop edi
pop esi
pop ebp
ret
Error:
(gdb)
Program received signal SIGILL, Illegal instruction.
0xbffff49a in ?? ()
Compiling and linking this way:
nasm -f elf -g strrepl.asm
nasm -f elf -g strrev.asm
gcc -Wall -g -c main7.c
gcc -Wall -g strrepl.o strrev.o main7.o
mov esp, ebp changes esp to point to where it was when mov ebp, esp was executed. That was before you pushed esi, edi, and ebx onto the stack, so you can no longer pop them. Since you do, the stack is wrong, and the ret does not work as desired.
You can likely delete the mov esp, ebp instruction. Restoring the stack pointer like that is needed only if you have variable changes to the stack pointer in the routine (e.g., to move the stack to a desired alignment or to make space for a variable-length array). If your stack is handled simply, then you merely pop in reverse order of what you push. If you do have variable changes to the stack, then you need to restore the pointer to a different location, not the ebp you have saved, so that you can pop ebx, edi, and esi.
I'm learning assembly and I have a very basic loop here
segment .data
msg: db '%d',10,0
segment .text
global _asm_main
extern _printf
_asm_main:
push DWORD 5 ; Should loop 5 times
call dump_stack
add esp,4
ret
dump_stack:
push ebp
mov ebp, esp
mov ecx, 0
loop_start:
cmp ecx,[ebp+8] ;compare to the first param of dump_stack, (5)
jnle loop_end
push ecx ;push the value of my loop onto the stack
push DWORD msg ;push the msg (%d) should just print the value of my loop
call _printf
add esp, 8 ;clear the stack
inc ecx ;increment ecx
jmp loop_start ; go back to my loop start
loop_end:
mov esp, ebp
pop ebp
ret
My output looks something like this
program.exe
0
Just 0, then a newline. I tried to verify the loop was executing by moving my printf to the loop_end part, and it came out with ecx as 6, which is correct. So the loop is executing but printf is not... What am I doing wrong?
(Also, the function is called dump stack because it was initially supposed to dump the details of the stack, but that didn't work because of the same reason here)
And I am compiling with nasm -f win32 program.asm -o program.o
Then I have a cpp file that includes windows.h, and I compiled it with gcc -c include
and finally I linked them with gcc -o program program.o include.o
and I run program.exe
My guess is that printf() modifies ecx, it becomes >= [ebp+8] and your loop body executes only once. If that's the case, you need to read up on the calling conventions used in your compiler and manually preserve and restore the so-called volatile registers (which a called function can freely modify without restoring). Note that there may be several different calling conventions. Use the debugger!