Here's how you write an entire function in assembly. The "global bar" keyword in assembly tells the assembler to make the function name "bar" visible from outside the file.
global bar
bar:
add rdi,1000
mov rax,rdi
ret
The "Link With:" box (under "Options") tells NetRun to link together two different projects, in this case one in C++ and the other in assembly. This C++ code calls the assembly here.
extern "C" int bar(int param);
int foo(void) {
return bar(6);
}
You can call C++ code from assembly almost as easily, by making the C++ code extern "C", using "extern someName" in assembly, and then call the function normally--this is exactly the same way you call plain C code from C++ or vice versa. (If you don't do extern "C" on the C++ side, it's difficult to find the function's name, due to C++ name mangling. Name mangling also makes it hard to call C++ operators and methods from C or Assembly, so stick with C++ functions.)
Calling a function bar
written in... |
|||
C++ |
C |
Assembly |
|
Called from C++ |
long bar(long) { ... } long bar(long); |
long bar(long) { ... } extern "C" long bar(long); |
global bar extern "C" long bar(long); |
Called from C |
extern "C" long
bar(long) { ... } extern long bar(long); |
long bar(long) { ... } extern long bar(long); |
global bar extern long bar(long); |
Called from Assembly |
extern "C" long
bar(long) { ... } extern bar |
long bar(long) { ... } extern bar |
global bar extern bar |
The most portable way to include some assembly functions in your code is to compile the assembly in a separate file, then link it with the C++. For example, in a file name "foo.S":
section .text
global _foo
_foo:
mov eax,7
ret
(Note the weird underscore in front of the function name--the compiler adds these on Windows and OS X, but not Linux.)
You'd assemble this into "foo.obj" on windows with this command line:
nasm -f win32 foo.S
Then in a file named "main.cpp", we call foo with an extern "C" prototype:
#include <iostream>
extern "C" int foo(void);
int main() {
std::cout<<"Foo returns "<<foo()<<"\n";
return 0;
}
We compile the C++ and link it to the assembly using the Microsoft Visual C++ compiler like this:
cl -EHsc main.cpp foo.obj
(You may have
to run "vc_vars.bat" to get "cl" into your PATH.)
We now have a functioning C++/Assembly executable! The same
exact command-line trick works on Linux (nasm -f elf32 or
nasm -f elf64) or OS X (nasm -f macho32
or nasm -f macho64) as long as you're compiling with
g++ or gcc. If you don't like the command line, and few
people do (except me!), you can hide
the NASM command line inside Visual C++ as I explain here.