gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

ASM > Errors re-writing a "C" in assembly

#177085 - blessingta@hotmail.co.uk - Thu Dec 08, 2011 2:35 pm

Basically, I'm trying to rewrite a "C" function in assembly but it refuses to work.

here is the code & errors: (my original C file is the one commented out)



Code:

//VRAM = video ram
#include <gba_console.h>
#include <gba_video.h>
#include <gba_interrupt.h>
#include <gba_systemcalls.h>
#include <gba_input.h>

#include <stdio.h>

/*
void ASSEMBLY_FUNC_HERE()
{

volatile unsigned char * pvuc_Im_in_assembly = "find me here in assembly";

}
*/
asm (
".align   2                           \n\t"
".global   ASSEMBLY_FUNC_HERE      \n\t"
"   .code   16                      \n\t"
"   .thumb_func                     \n\t"
"   .type   ASSEMBLY_FUNC_HERE, %function \n\t"
"ASSEMBLY_FUNC_HERE:                  \n\t"
//".LFB6:                                \n\t"
   
"   .loc 1 11 0                      \n\t"
"   .cfi_startproc                   \n\t" 
//".LVL0:                              \n\t"
"   .loc 1 15 0                     \n\t"
"   @ sp needed for prologue          \n\t"
"   bx   lr                          \n\t"
"   .cfi_endproc                    \n\t"
//".LFE6:                              \n\t"
"   .size   ASSEMBLY_FUNC_HERE, .-ASSEMBLY_FUNC_HERE \n\t"
   );

int NEWFUNC (int i)
{
 i += 9000;
return i;
}

//---------------------------------------------------------------------------------
// Program entry point
//---------------------------------------------------------------------------------
int main(void) {
//---------------------------------------------------------------------------------

   // the vblank interrupt must be enabled for VBlankIntrWait() to work
   // since the default dispatcher handles the bios flags no vblank handler
   // is required
   irqInit();
   irqEnable(IRQ_VBLANK);

   consoleDemoInit();
   
   ASSEMBLY_FUNC_HERE();
   NEWFUNC(1);
   
   while (1) {
      VBlankIntrWait();
   }
}




Quote:

> "make"
main.c
arm-eabi-gcc -MMD -MP -MF /h/YEAR2/Console_Programming_CONPRG/Course_Work/gba/my_gba_asm/build/main.d -g -Wall -O3 -save-temps -mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer -ffast-math -mthumb -mthumb-interwork -I/h/YEAR2/Console_Programming_CONPRG/Course_Work/gba/my_gba_asm/include -I/c/devkitPro/libgba/include -I/h/YEAR2/Console_Programming_CONPRG/Course_Work/gba/my_gba_asm/build -c /h/YEAR2/Console_Programming_CONPRG/Course_Work/gba/my_gba_asm/source/main.c -o main.o
h:/YEAR2/Console_Programming_CONPRG/Course_Work/gba/my_gba_asm/source/main.c: In function 'main':
h:/YEAR2/Console_Programming_CONPRG/Course_Work/gba/my_gba_asm/source/main.c:58:2: warning: implicit declaration of function 'ASSEMBLY_FUNC_HERE' [-Wimplicit-function-declaration]
main.s: Assembler messages:
main.s:20: Error: unassigned file number 1
main.s:20: Error: junk at end of line, first unrecognized character is `0'
main.s:22: Error: unassigned file number 1
main.s:22: Error: junk at end of line, first unrecognized character is `0'
make[1]: *** [main.o] Error 1
"make": *** [build] Error 2

> Process Exit Code: 2
> Time Taken: 00:01

#177086 - blessingta@hotmail.co.uk - Thu Dec 08, 2011 2:44 pm

Are functions declared in assembly hidden from "C"? Do I have to declare my function in "C" instead?


From reading a bit, I'm guessing align 2 is a place in memory,
but what is LFB6?Is it a subroutine within a function?

Plus why is the line below returning an error and that does it do?
"loc 1 11 0 \n\t"

#177094 - Cearn - Sat Dec 10, 2011 11:06 am

blessingta@hotmail.co.uk wrote:
Are functions declared in assembly hidden from "C"? Do I have to declare my function in "C" instead?

Yes and yes.

I think you're missing a very important distinction here. You have function (and variable) definitions and declarations. A definition is the actual function itself and what will appear in the intermediate object files (.o) and the final binary (.gba). The declaration just to tell C that some symbol exists in the project and how to interact with it. A definition can act as a declaration, but not the other way around.

Example:
Code:
// --------------------------------------------------------------------
// DECLARATIONS. Put these in source (.c) or header (.h) files.
// --------------------------------------------------------------------
extern int var;
extern const unsigned int data[256];
void foo(int x);


// --------------------------------------------------------------------
// DEFINITIONS. Put these in source (.c) only.
// --------------------------------------------------------------------

// uninitialized definition
int var;

// initialized definition
const unsigned int data[256]=
{
    // data
};

void foo(int x)
{
    // code
}


In your example, the thing between asm() is the definition, but the C compiler pretty much ignores what's inside because it's for the assembler to handle. As such, no declaration for ASSEMBLY_FUNC_HERE() exists yet.

blessingta@hotmail.co.uk wrote:
From reading a bit, I'm guessing align 2 is a place in memory,
but what is LFB6?Is it a subroutine within a function?
Technically, there are no such things as functions or variables or anything in assembly. There's just instructions, data and labels. "LFB6" is a label, which marks an important location for the assembler, that's all. In practice, though, some labels are useful to think of as functions or variables, but the assembler really doesn't care.

As a rule, anything ending with ":" is a label. By convention, labels that start with "." are supposed to be internal labels, indicating branch destinations for things like ifs and loops. The other things that start with "." (like ".align 2") are directives, telling the assembler how to deal with the next instruction, but don't appear in the generated binary.

blessingta@hotmail.co.uk wrote:
Plus why is the line below returning an error and that does it do?
"loc 1 11 0 \n\t"
This is a potential breakpoint for a debugger (generated by compiler flag "-g"), and they can be removed.

The reason it returns an error is because the first argument is a file number. If you look at the generated asm for NEW_FUNC(), you'll see this:

Code:
NEWFUNC:
.LFB0:
   .file 1 "h:/dev/gba/proj/tonc/test/mini/blessing.c"
   .loc 1 39 0


The .file directive indicates what file is linked to file number 1. Since ASSEMBLY_FUNC_HERE() is above NEW_FUNC, the numer isn't defined yet, and ".loc 1" doesn't work.

If you want to learn asm by looking at what the compiler makes, remove the "-g" compiler flag first. It generates much cleaner assembly that way. I would also strongly suggest using separate assembly files instead of inline assembly for your first tries. Learning assembly can be hard enough without having to learn the intricacies and potential pitfalls that come with inline asm, as you've seen here.

my_asm.s (put this in '/sources')
Code:
@ Standard boilerplate for assembly functions
    .text               @ Put the following stuff in the "text" (== code) section
    .align 2            @ align to 1<<2 bytes
    .thumb              @ Assemble as thumb code
    .thumb_func         @ Call as thumb function
    .global my_func     @ Generate an object symbol for it
my_func:                @ Label for function entry point.
    @ start of function

    bx lr
    @ end of function


in main.c:
Code:
// Function declaration (not definition)
void my_func();

//---------------------------------------------------------------------------------
// Program entry point
//---------------------------------------------------------------------------------
int main(void) {
   irqInit();
   irqEnable(IRQ_VBLANK);

   // function call
   my_func();

   consoleDemoInit();
   
   while (1) {
      VBlankIntrWait();
   }
}


See also thread: 17784

#177106 - blessingta@hotmail.co.uk - Sun Dec 11, 2011 9:50 pm

thanks.

I just need to get assembly working in less than 2days for my assessment deadline.