Jump to content
  • Advertisement
Sign in to follow this  
CPPNick

Assembly in C++

This topic is 3417 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello! I have decided to write oen of my routines for my app in assembly, and need some help. So far i have a working copy of a program that I made as a sample, but I still have some questions. I know that I how to include the *.asm file in my project, how to make it compile with the project, and how to declare it for use like "extern "C" {void sample();}". I'm unclear on a few things though. I Know how to declare the proc with single DWORD arguments, but How do I use an entire C struct like a vertex with x, y, z, and w or something? I need an example of this if anyone can link me. The other thing I am wondering about, is when I use inline, or a separate asm proc, which registers can I not touch? because if there is a pointer to the heap memory, and I overwrite it or something, that will crash my program, or cause the C++ compiler to add extra code or something right? do I have to push all the registers to the stack when before I alter them with my own assembly code? Thx for links! =)

Share this post


Link to post
Share on other sites
Advertisement
Well, the heap has nothing to do with registers. If you have the address to a memory location stored in a register, then you could loose that address - but then again, why did you only have the address in a register (automatic variable with very limited scope)? It's more likely you have it saved on the stack somewhere, or you should explicitly do that first. When you modify register contents you should really focus on the difference between callee save and caller save registers, so I suggest you google that. You'll want to look up SSE registers for working with more complicated things than individual, and a very limited number of, integers/floats (which both use different types of registers as well), and think about representing your vertex as vectors. I only use assembly for debugging, so I'm not really able to give you more tips off the top of my head without pulling out my notes.

Share this post


Link to post
Share on other sites
Quote:
Original post by CPPNick
Hello! I have decided to write oen of my routines for my app in assembly, and need some help. So far i have a working copy of a program that I made as a sample, but I still have some questions. I know that I how to include the *.asm file in my project, how to make it compile with the project, and how to declare it for use like "extern "C" {void sample();}".


ok, um why?
these days, the compiler will most likely do a far better job of writing assembly than you ever will :) can you use intrinsics instead of bare asm?

Quote:

I'm unclear on a few things though. I Know how to declare the proc with single DWORD arguments, but How do I use an entire C struct like a vertex with x, y, z, and w or something? I need an example of this if anyone can link me.


you pass a pointer via the DWORD. the DWORD's value is then the address of the struct.
im not going to paste code, you need to figure it out :) this sort of thing is fundamental to how the CPU actually works. you need to understand it if you want to write things in assembly

Quote:

The other thing I am wondering about, is when I use inline, or a separate asm proc, which registers can I not touch? because if there is a pointer to the heap memory, and I overwrite it or something, that will crash my program, or cause the C++ compiler to add extra code or something right? do I have to push all the registers to the stack when before I alter them with my own assembly code?


first up, it would be impossible to tell ahead of time which registers you cant touch, as thats a compile time issue. it wouldnt surprise me if the compiler simply dumped everything out of the registers back into memory before your inline asm code ran to make sure that your hand written asm wont trash something important. and when your asm code is finished, load its own state back.

secondly, which registers you shouldnt play with are dictated by the ABI, in particular the state on entry to, and exit from the function. (things like stack pointers and what not). you *can* play with them (and the compiler will) but they need to be set correctly before the function exits.

before you barge headlong into asm, you really need to understand how things work. read the ABI, read the compiler documentation, work out exactly what is going on. ASM is less forgiving than C, there is no compiler to help catch simple errors. if you dont know something, cutting and pasting wont help. youll just have to read the documentation and work it out.

but back to my original point. why?
if you want to learn asm, cool, but its more important to be able to read it than be able to write it. Ive been working in IT for 10 years, and games for 4 of that, and ive never had to write bare assembly, even on console titles. sure, I can read it (debugging release builds with no symbols is one of those times where its very handy to be able to do so)

intrinsics however are awesome. they give you access to instructions, but let the compiler optimise things as it sees fit. perhaps you can use those to do what you want instead.

if you really are set on asm, see if you can find the x86 equivalent of "See MIPS Run", or hell, even read that.


Share this post


Link to post
Share on other sites
I want to try and optimize my fragment drawer in my 3d engine, just as a hobby. I don't really expect much to come of it, but I took one quick look at the assembly generated by the compiler of the function in question and i think i can get it to run a little faster.

I tried to google ABI, but found nothing. what does that mean?

edit: this is my code so far

TEST.CPP

extern "C" WORD _add(WORD num1, WORD num2);
int _tmain(int argc, _TCHAR* argv[])
{
WORD number = 0;

number = _add(1, 1);
cout << number << endl;

getch();
return 1;
}



_ADD.ASM

.586
.MODEL FLAT, C
.STACK
.DATA
.CODE

_add PROC num1:WORD, num2:WORD

mov ax, num1
cmp ax, num2
mov ax, bx
ret

_add ENDP
END



So if I wanted a struct as input, would the following code be correct?

.586
.MODEL FLAT, C
.STACK
.DATA
.CODE

_add PROC num1:DWORD, num2:DWORD

mov ax, [num1]
cmp ax, [num2]
mov ax, bx
ret

_add ENDP
END


and call it like _add(&value1, &value2); ?

thx =)

[Edited by - CPPNick on May 17, 2009 6:26:03 PM]

Share this post


Link to post
Share on other sites
have you tried looking at the various optimization options you have for the compiler?

Anyway, I dont really know how to do structs, but you could compile a c++ program and look at the assembly the program makes ;)

Share this post


Link to post
Share on other sites
Quote:
Original post by Matt_D

you pass a pointer via the DWORD. the DWORD's value is then the address of the struct.
im not going to paste code, you need to figure it out :) this sort of thing is fundamental to how the CPU actually works. you need to understand it if you want to write things in assembly


I think he ment somthing like this:



mov ax, word ptr [myStruct]
add ax, word ptr [myStruct + 1]
add ax, word ptr [myStruct + 2]
add ax, word ptr [myStruct + 3]




I assume that is correct (the word ptr is because i'm learning good ole' 16-bit asm)

etc...

Share this post


Link to post
Share on other sites
I Know how to declare the proc with single DWORD arguments, but How do I use an entire C struct like a vertex with x, y, z, and w or something?


If you want to use a C-struct, then use C. Asm doesn't have that concept, so it's just a case of passing the address around and dereferencing. To be honest though, rather than writing all of this in x86 (and then throwing it all away when you move to 64 bit), you might as well bite the bullet and just use intrinsics.


#include <xmmintrin.h>
#include <malloc.h>

__declspec(align(16))
struct vec3
{
inline vec3() { sse = _mm_setzero_ps(); }
inline vec3(const __m128 a) { sse = a; }
struct {
float x;
float y;
float z;
float w;
};
__m128 sse;

void* operator new(size_t s){
return _aligned_malloc(s,16);
}
void* operator new[](size_t s) {
return _aligned_malloc(s,16);
}
void operator delete(void* ptr) {
_aligned_free(ptr);
}
void operator delete[](void* ptr) {
_aligned_free(ptr);
}
};

vec3 _add(const vec3& a, const vec3& b)
{
return vec3( _mm_add_ps(a.sse,b.sse) );
}

Share this post


Link to post
Share on other sites
Quote:

You'll want to look up SSE registers

Quote:

ok, um why?

Quote:

have you tried looking at the various optimization options you have for the compiler?

Quote:

you might as well bite the bullet and just use intrinsics



Ugh...can I just PLEASE learn some ASM? pretty please? I know all about intrinsics, and may include it in my asm result. But I just wanna learn some asm, and see what kind of results I can get.

I appreciate the answers, but you guys are talking to me like I've got 6 inches of forhead and a wooden club!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!