IncFile() and IncArray() macros [Updated 22-1-2009]
-
- Posts: 605
- Joined: Feb 18, 2006 13:30
- Location: Alexandria / Egypt
- Contact:
-
- Posts: 605
- Joined: Feb 18, 2006 13:30
- Location: Alexandria / Egypt
- Contact:
Another update, now IncFile() works inside functions once more, by adding some initialization code to the function body, at module level it will not generate a single ASM instruction (except for the jump when debugging).
Currently working on a way to make IncArray() work inside functions too.
P.S: IncFile() will not work inside SCOPE blocks at module level, since EXTERN is not allowed at that point.
Currently working on a way to make IncArray() work inside functions too.
P.S: IncFile() will not work inside SCOPE blocks at module level, since EXTERN is not allowed at that point.
-
- Posts: 149
- Joined: Jun 18, 2008 22:10
Re: IncFile() and IncArray() macros [Updated 8-3-2008]
Nice, I was looking for something like this... but could you explain me how this work... "the theory"? what's happen here? which is the main idea?... where can I find any documentation about this?voodooattack wrote:IncFile() and IncArray() are macros that allow you, as the names suggest, to embed files into your executable at compile-time.
The embedded files can then be accessed just like regular memory pointers (or as arrays, with IncArray).
incfile.biUsage:Code: Select all
#IFNDEF INCFILE_BI #DEFINE INCFILE_BI #MACRO IncFileEx(label, file, sectionName, attr) #if __FUNCTION__ <> "__FB_MAINPROC__" dim label as const ubyte ptr = any dim label##_len as uinteger = any #if __FB_DEBUG__ asm jmp .LT_END_OF_FILE_##label##_DEBUG_JMP #else ' Switch to/Create the specified section #if attr = "" asm .section sectionName #else asm .section sectionName, attr #endif #endif ' Assign a label to the beginning of the file asm .LT_START_OF_FILE_##label#: asm __##label##__start = . ' Include the file asm .incbin ##file ' Mark the end of the the file asm __##label##__len = . - __##label##__start asm .LT_END_OF_FILE_##label: ' Pad it with a NULL Integer (harmless, yet useful for text files) asm .LONG 0 #if __FB_DEBUG__ asm .LT_END_OF_FILE_##label##_DEBUG_JMP: #else ' Switch back to the .text (code) section asm .section .text asm .balign 16 #endif asm .LT_SKIP_FILE_##label: asm lea eax, .LT_START_OF_FILE_##label# asm mov dword ptr [label], eax asm mov dword ptr [label##_len], __##label##__len #else extern "c" extern label As ubyte ptr extern label##_len as uinteger end extern #if __FB_DEBUG__ asm jmp .LT_END_OF_FILE_##label##_DEBUG_JMP #else ' Switch to/create the specified section #if attr = "" asm .section sectionName #else asm .section sectionName, attr #endif #endif ' Assign a label to the beginning of the file asm .LT_START_OF_FILE_##label#: asm __##label##__start = . ' Include the file asm .incbin ##file ' Mark the end of the the file asm __##label##__len = . - __##label##__start asm .LT_END_OF_FILE_##label: ' Pad it with a NULL Integer (harmless, yet useful for text files) asm .LONG 0 asm label: asm .int .LT_START_OF_FILE_##label# asm label##_len: asm .int __##label##__len #if __FB_DEBUG__ asm .LT_END_OF_FILE_##label##_DEBUG_JMP: #else ' Switch back to the .text (code) section asm .section .text asm .balign 16 #endif asm .LT_SKIP_FILE_##label: #endif #endmacro #macro IncFile(label, file) IncFileEx(label, file, .data, "") 'Use the .data (storage) section (SHARED) #endmacro #endif
IncFile(label, filename)
creates a variable named "label" that points to the file contents, stores the file in the .data section, the length of the contents is stored in another variable called "label_len".
IncFileEx(label, filename, section_name, attr)
same as the above, but lets you specify a name for the section to store data in and the attributes of the section (can be 0 for default).
I hope some one finds it useful :)
I'd like understand why it works
thanks :)
-
- Posts: 149
- Joined: Jun 18, 2008 22:10
I'm trying to undertand how it works... I'm reading asm stuff on www... But I'm having problems to find documentation on google because google search omits terms like "##" or "_#" or "__##"... Ok, on freebasic "##" creates a new token by concatenating the texts at both sides of it.... but on asm i don't know what it does ("asm .incbin ##file" or "asm .LT_START_OF_FILE_##label#" with a single "#" at ends...)
And I see
__##label##__start = .
__##label##__len = . - __##label##__start
but this variables are not declared... only "label" and "label##_len" are declared... why don't you need declare these?
EDIT: I've cleaned a stupid question :P
Other questions about:
#if __FB_DEBUG__
asm jmp .LT_END_OF_FILE_##label##_DEBUG_JMP
#else
' Switch to/Create the specified section
#if attr = ""
asm .section sectionName
#else
asm .section sectionName, attr
#endif
#endif
and about...
#if __FB_DEBUG__
asm .LT_END_OF_FILE_##label##_DEBUG_JMP:
#else
' Switch back to the .text (code) section
asm .section .text
asm .balign 16
#endif
When debug option is set, section "sectionName" is no created... then... where is file loaded? (which section?)
When debug option is set, doesn't go to .text section... why?...was it on .text section already????
is filed loades on .text section when debug option is set????
Please, Could you give me some explanationa about these code lines?
thanks :)
Something else: I can't find documentation for "__FB_MAINPROC__" (a value of __FUNCTION__ ???, what values could __FUNCTION__ take????)
And I see
__##label##__start = .
__##label##__len = . - __##label##__start
but this variables are not declared... only "label" and "label##_len" are declared... why don't you need declare these?
EDIT: I've cleaned a stupid question :P
Other questions about:
#if __FB_DEBUG__
asm jmp .LT_END_OF_FILE_##label##_DEBUG_JMP
#else
' Switch to/Create the specified section
#if attr = ""
asm .section sectionName
#else
asm .section sectionName, attr
#endif
#endif
and about...
#if __FB_DEBUG__
asm .LT_END_OF_FILE_##label##_DEBUG_JMP:
#else
' Switch back to the .text (code) section
asm .section .text
asm .balign 16
#endif
When debug option is set, section "sectionName" is no created... then... where is file loaded? (which section?)
When debug option is set, doesn't go to .text section... why?...was it on .text section already????
is filed loades on .text section when debug option is set????
Please, Could you give me some explanationa about these code lines?
thanks :)
Something else: I can't find documentation for "__FB_MAINPROC__" (a value of __FUNCTION__ ???, what values could __FUNCTION__ take????)
Last edited by darkblacklife on Sep 30, 2008 16:13, edited 2 times in total.
-
- Site Admin
- Posts: 6323
- Joined: Jul 05, 2005 17:32
- Location: Manchester, Lancs
__FB_MAINPROC__ is the dummy name for __FUNCTION__ when it's used at module-level in the main module.darkblacklife wrote:Something else: I can't find documentation for "__FB_MAINPROC__" (a value of __FUNCTION__ ???, what values could __FUNCTION__ take????)
I've just updated __FUNCTION__'s page to show this:
http://www.freebasic.net/wiki/KeyPgDdfunction
-
- Posts: 149
- Joined: Jun 18, 2008 22:10
ok, thanks :)counting_pine wrote:__FB_MAINPROC__ is the dummy name for __FUNCTION__ when it's used at module-level in the main module.darkblacklife wrote:Something else: I can't find documentation for "__FB_MAINPROC__" (a value of __FUNCTION__ ???, what values could __FUNCTION__ take????)
I've just updated __FUNCTION__'s page to show this:
http://www.freebasic.net/wiki/KeyPgDdfunction
-
- Posts: 605
- Joined: Feb 18, 2006 13:30
- Location: Alexandria / Egypt
- Contact:
Yep, this is done to make unique symbol names in the gAS context, if you try to use the same identifiers twice in a macro, you'll get a duplicate definition, to avoid this, we simply derive a new identifier from the original macro argument to avoid conflicts with previous (or future) instances of the macro.darkblacklife wrote:I'm trying to undertand how it works... I'm reading asm stuff on www... But I'm having problems to find documentation on google because google search omits terms like "##" or "_#" or "__##"... Ok, on freebasic "##" creates a new token by concatenating the texts at both sides of it....
.incbin is a gAS statement that includes the target file into the assembler output, the hash characters are parsed at the FreeBASIC preprocessor level, the final output would be:darkblacklife wrote:but on asm i don't know what it does ("asm .incbin ##file" or "asm .LT_START_OF_FILE_##label#" with a single "#" at ends...)
Code: Select all
asm .LT_STARTOF_FILE_myFile
Code: Select all
asm .LT_STARTOF_FILE_label
so the last hash makes sure FBC treats "label" as a #define, and not a literal value.
I explained this in the other thread, I'll provide the link in case someone reads this in the future: http://www.freebasic.net/forum/viewtopi ... 094#108094darkblacklife wrote:And I see
__##label##__start = .
__##label##__len = . - __##label##__start
but this variables are not declared... only "label" and "label##_len" are declared... why don't you need declare these?
Yes, due to problems with how FB emits debug data, it's not possible to include the files in .data/other sections when compiling in debug mode, the compiler emits debug data per line. (switching between .stabs and .text once per line), once this interferes with how the macro works, you'll get assembler errors and assembly would fail.darkblacklife wrote: Other questions about:
#if __FB_DEBUG__
asm jmp .LT_END_OF_FILE_##label##_DEBUG_JMP
#else
' Switch to/Create the specified section
#if attr = ""
asm .section sectionName
#else
asm .section sectionName, attr
#endif
#endif
and about...
#if __FB_DEBUG__
asm .LT_END_OF_FILE_##label##_DEBUG_JMP:
#else
' Switch back to the .text (code) section
asm .section .text
asm .balign 16
#endif
When debug option is set, section "sectionName" is no created... then... where is file loaded? (which section?)
When debug option is set, doesn't go to .text section... why?...was it on .text section already????
is filed loades on .text section when debug option is set????
Please, Could you give me some explanationa about these code lines?
thanks :)
The only trick I could come with was to include the target file INSIDE code blocks (.text), and jump over it instead, a bit hack-ish, but it works, and the transition is mostly transparent, and as far as I can tell, does not interfere with the debugger at all, I don't think it's not that important in a debug build anyways ;)
I think counting_pine pretty much explained what it does, now I'll explain why I used it in the macro..darkblacklife wrote: Something else: I can't find documentation for "__FB_MAINPROC__" (a value of __FUNCTION__ ???, what values could __FUNCTION__ take????)
This macro is context-sensitive, meaning, it functions differently when used at module-level, than inside the body of a function.
When you instantiate it at module-level, it detects it using that __FB_MAINPROC__ trick, and uses EXTERN to access your data (the proper way), everything is static and is resolved at link-time and no assembly code is generated at all (except for the jump instruction in debug builds).
But when you instantiate it inside a function's body, and because we're not allowed to use EXTERN inside functions, things are a bit different, the macro defines two variables and fills them with the values instead, and from there, they follow scoping rules properly like all other variables.
-
- Posts: 149
- Joined: Jun 18, 2008 22:10
Ok, but I tried deleting ## on "asm .incbin ##file" and single # on "asm .LT_START_OF_FILE_##label#" and compiling with -r option.... I get same .asm code ... so ... could these be not needed?voodooattack wrote:.incbin is a gAS statement that includes the target file into the assembler output, the hash characters are parsed at the FreeBASIC preprocessor level, the final output would be:darkblacklife wrote:but on asm i don't know what it does ("asm .incbin ##file" or "asm .LT_START_OF_FILE_##label#" with a single "#" at ends...)if you take off the last hash character, it would be:Code: Select all
asm .LT_STARTOF_FILE_myFile
so the last hash makes sure FBC treats "label" as a #define, and not a literal value.Code: Select all
asm .LT_STARTOF_FILE_label
Yes I think you did ... I re-asked a doubt about it in that same thread ...voodooattack wrote:I explained this in the other thread, I'll provide the link in case someone reads this in the future: http://www.freebasic.net/forum/viewtopi ... 094#108094darkblacklife wrote:And I see
__##label##__start = .
__##label##__len = . - __##label##__start
but this variables are not declared... only "label" and "label##_len" are declared... why don't you need declare these?
Thanks for all the time that you spent to aswer me ... :)myself wrote:don't you need to declare "__source__start" or "__source__len"???
is it due to in the very final output these are not present???
... And I have other questions :D
I assume you write:
Code: Select all
lea eax, .LT_START_OF_FILE_##label#
mov dword Ptr [label], eax
Code: Select all
mov dword Ptr [label], OFFSET .LT_START_OF_FILE_##label#
Code: Select all
mov dword Ptr [label], OFFSET __##label##__start
but you write:
Code: Select all
asm mov dword Ptr [label##_len], __##label##__len
Code: Select all
asm mov eax, __##label##__len
asm mov dword Ptr [label##_len], eax
and something else...
I tried this:
Code: Select all
mov dword Ptr [label], __##label##__start
Error: too many memory references for 'mov'
I was thinking that on flat memory model offset address is THE address ... why do I have this error message???
Thank you
-
- Posts: 605
- Joined: Feb 18, 2006 13:30
- Location: Alexandria / Egypt
- Contact:
As for the preprocessor stuff, I wrote this for FB v0.18 or something around that if I remember correctly, and it was (and probably still) full of quirks..
The correct answer is that those were mostly work-arounds for issues that got fixed later, or stuff that I forgot to change/remove after revising this macro over 4 times already.
About OFFSET, I guess you're right, I guess I forgot about it because I never use incfile inside a function, I just provided that functionality in case someone needs it. I always do it at module-level.. thanks for pointing that out, I'll update the macro when I have time to test it. :)
The correct answer is that those were mostly work-arounds for issues that got fixed later, or stuff that I forgot to change/remove after revising this macro over 4 times already.
About OFFSET, I guess you're right, I guess I forgot about it because I never use incfile inside a function, I just provided that functionality in case someone needs it. I always do it at module-level.. thanks for pointing that out, I'll update the macro when I have time to test it. :)
That error message generally means that you need to move the value to an intermediate register first.. I'm no expert but as far as I know, if you omit OFFSET, the assembler treats both operands as dynamic values, in which case you'd need an extra register, OFFSET tells it to use a static value instead.and something else...
I tried this:without "OFFSET" operator and I had this error message:Code: Select all
mov dword Ptr [label], __##label##__start
Error: too many memory references for 'mov'
I was thinking that on flat memory model offset address is THE address ... why do I have this error message???
Thank you
-
- Posts: 149
- Joined: Jun 18, 2008 22:10
Yes but...voodooattack wrote:That error message generally means that you need to move the value to an intermediate register first.. I'm no expert but as far as I know, if you omit OFFSET, the assembler treats both operands as dynamic values, in which case you'd need an extra register, OFFSET tells it to use a static value instead.and something else...
I tried this:without "OFFSET" operator and I had this error message:Code: Select all
mov dword Ptr [label], __##label##__start
Error: too many memory references for 'mov'
I was thinking that on flat memory model offset address is THE address ... why do I have this error message???
Thank you
asm mov dword Ptr [label##_len], __##label##__len
it doesn't need OFFSET operator... why?
Hello,
Yesterday I created a thread about adding images to my EXE file and got redirected to this thread.
Which include source do I actually need to embed a BMP image and how do I access it? I guess BLOAD won't work at this level?
I see a lot of sources in this thread, long and small ones but it's not clear which one should be used (to me atleast ;o) )
Yesterday I created a thread about adding images to my EXE file and got redirected to this thread.
Which include source do I actually need to embed a BMP image and how do I access it? I guess BLOAD won't work at this level?
I see a lot of sources in this thread, long and small ones but it's not clear which one should be used (to me atleast ;o) )
-
- Posts: 605
- Joined: Feb 18, 2006 13:30
- Location: Alexandria / Egypt
- Contact:
The second value resolves to a constant value, same as if you had put a literal number in there..darkblacklife wrote:Yes but...
asm mov dword Ptr [label##_len], __##label##__len
it doesn't need OFFSET operator... why?
asm mov dword ptr [myvar], 5
I wouldn't recommend using bitmaps for embedding images, I'd recommend use PNGs instead..sorex wrote:Hello,
Yesterday I created a thread about adding images to my EXE file and got redirected to this thread.
Which include source do I actually need to embed a BMP image and how do I access it? I guess BLOAD won't work at this level?
I see a lot of sources in this thread, long and small ones but it's not clear which one should be used (to me atleast ;o) )
You can use yetifoot's png library here: http://www.freebasic.net/viewtopic.php?t=8024&start=0
and then use this macro:
Code: Select all
#macro IncPNG(label, file)
incfile (p##label, file)
#if __FUNCTION__ = "__FB_MAINPROC__"
dim shared as FB.IMAGE ptr label = any
#else
dim as FB.IMAGE ptr label = any
#endif
label = PNG_Load_Mem(cast(any ptr, p##label), p##label##_len, PNG_TARGET_FBNEW)
#endmacro
Code: Select all
#include "incfile.bi"
#include "fbpng.bi"
#include "fbgfx.bi"
incpng(test, "test.png")
screenres 640, 480, 32
put (0,0), test
sleep
-
- Posts: 149
- Joined: Jun 18, 2008 22:10
But "__##label##__start" and "__##label##__len" are similar.... why is "__##label##__len" like a constant? and why is "__##label##__start" like a dynamic value?voodooattack wrote:The second value resolves to a constant value, same as if you had put a literal number in there..darkblacklife wrote:Yes but...
asm mov dword Ptr [label##_len], __##label##__len
it doesn't need OFFSET operator... why?
and do you say to use OFFSET and mov is better (more efficient) than lea?voodooattack wrote: [ Macro updated to use OFFSET instead of LEA and I fixed some new glitches I found, check first post. ]
Thanks Voodoo,
It seems to include my PNG but at execution it's nagging about a missing zlib.dll.
Can I include/attach that to my EXE aswell or will I still end up with several files instead of just 1 EXE file?
Edit: ok, grabbed zlib1.dll from that mp3 player in the projects thread and now it works.
odd thing is that my 8bpp (256 colors) PNG doesn't get shown with mode 13, need to change it to 320x200 32 before it shows up.
It seems to include my PNG but at execution it's nagging about a missing zlib.dll.
Can I include/attach that to my EXE aswell or will I still end up with several files instead of just 1 EXE file?
Edit: ok, grabbed zlib1.dll from that mp3 player in the projects thread and now it works.
odd thing is that my 8bpp (256 colors) PNG doesn't get shown with mode 13, need to change it to 320x200 32 before it shows up.
please correct me if I'm doing something wrong. (which i am)
I compiled the voodooattack's code at the start, named it incfile.bi
then I run voodooattack's example, but then for some reason FBIDE goes and opens up incfile.bi and the only text in that is 'MZ' which it says "expected '=' "
It also wont compile
I'm supposed to see a read out of the demo program arnt I? (if it were working)
Thanks
I compiled the voodooattack's code at the start, named it incfile.bi
then I run voodooattack's example, but then for some reason FBIDE goes and opens up incfile.bi and the only text in that is 'MZ' which it says "expected '=' "
It also wont compile
I'm supposed to see a read out of the demo program arnt I? (if it were working)
Thanks