Dark Bit Factory & Gravity

PROGRAMMING => Freebasic => Topic started by: Jim on July 09, 2007

Title: Making tiny FB executable programs
Post by: Jim on July 09, 2007
I was looking at nino's latest tiny executables, and trying to see how to link them without linking in freebasic's startup code and default libraries.  These are really large, so it's important to be able to get rid of them for tiny exes.  The problem is that FB's linker and compiler hard code a few things and that means the startup code always gets linked.

So here's my solution to the problem.

First, write your program as usual, obviously NOT using an built-in FB functions like print, graphics, etc.
Here's my test program (tiny.bas)
Code: [Select]
#include "windows.bi"

declare function WinMainCRTStartup alias "WinMainCRTStartup"

function WinMainCRTStartup() as integer
messagebox(0,"Very Small FB EXE Sample","Hello",MB_OK)
return 0
end function

compile this using

Code: [Select]
fbc -c tiny.bas
The -c tells the FB compiler just to make a .o file and not an .exe.  .o files are the building blocks used by linkers to make executable files.

Next, we need to stub the functions that FB has hardcoded.
I used assembler for this (stub.asm)
Code: [Select]
.386p
.model flat
.code
public _fb_RtInit@0
_fb_RtInit@0:
end
I assembled it with MASM, but it can be built with lots of other assemblers.
Command line
Code: [Select]
ml /c /coff stub.asmThis produces stub.obj.

Finally, you need to link these all together.  FB is no use for this, you need a proper linker.  I've used crinkler, which has the added advantage of compressing while it links.  You can download it from www.crinkler.net (http://www.crinkler.net)

The command line I used to do the link is
Code: [Select]
crinkler /SUBSYSTEM:WINDOWS /OUT:tiny.exe /LIBPATH:"C:\program files\microsoft platform sdk for windows server 2003 r2\lib" kernel32.lib user32.lib tiny.o stub.obj



You will need the libs from Microsoft Platform SDK to perform this step.  You will need to change LIBPATH to point to wherever you have them installed.  You can change the name of the output file by changing OUT.

And that produces an exe which is just 605 bytes in size!

Included in the archive are:
All the source from this article, stub.obj for those who don't have MASM, and the final exe.
Crinkler is here www.crinkler.net (http://www.crinkler.net)

Have fun!

Jim
Title: Re: Making tiny FB executable programs
Post by: ninogenio on July 09, 2007
cool k+ jim!

lots of new stuff there for me to have fun with cheers.
Title: Re: Making tiny FB executable programs
Post by: Stonemonkey on July 09, 2007
Yep, very cool Jim.
Title: Re: Making tiny FB executable programs
Post by: Jim on July 09, 2007
Here's taj's pixel shader 3.0 demo in FB.  Using the above technique it comes out at 1081 bytes.  Can anyone get it under the magic 1Kb?

Nino, this will definitely help you port trinity :)
Code: [Select]
' Chris Thornborrow (auld)... lalala credit would be nice ... lalala
' Example OGL + shaders in 1k
' Requires crinkler

' VS2005 modifications by benny!weltenkonstrukteur.de

' Freebasic modifications by Jim 9/7/2007

option explicit

#include "windows.bi"
#include "GL/gl.bi"
#include "GL/glu.bi"
#include "GL/glext.bi"

declare sub WinMainCRTStartup alias "WinMainCRTStartup"

' Draws the labyrinth using a pair of shaders...
' Vertex shader does NOT transform incoming vertex but stores that in p instead for later use
' The fragment shader is a complicated. It essentially raycasts into a constantly changing
' equation, similar in concept to chladni :-). Its carfully tuned so we dont crash into it as we move
' and so we get a feeling of depth. The for loop could be smaller when written as a do .. while but then
' it wouldnt work on NVidia cards of 7xxx series or below.
' Fragment shader has 2 lines for setup, 1 line for raycasting and function testing, 1 line for colour.

dim shared labvsh as zstring * 68 => "varying vec4 p;void main(){p=ftransform();gl_Position=gl_Vertex;}"
dim shared labfsh as zstring * 260 => "varying vec4 p;void main(){vec3 V=vec3(0,3.5*sin(p.z),p.z);vec3 D=vec3(p.x,p.y,0.5)*0.08;for(int i=800;i>0;i--,V+=D)if(length(fract(abs(sin(V))))>1.5+0.5*sin(V.z)*sin(p.z*0.4))i=0;gl_FragColor=vec4(1,0.8,0.8,0)*dot(vec3(0.4),fract(V))-length(V-p.xyz)*0.1;}"

type GenFP as sub () ptr

dim shared glFP(6) as GenFP
dim shared glnames(6) as zstring * 16 => {"glCreateShader", "glShaderSource", "glCompileShader", "glCreateProgram", "glAttachShader", "glLinkProgram", "glUseProgram"}

dim shared pfd as PIXELFORMATDESCRIPTOR
dim shared dmScreenSettings as DEVMODE

' declare everything global to save bytes
dim shared q as zstring ptr
dim shared i as integer
dim shared as GLuint v,f,p
dim shared hDC as HDC

dim shared m(15) as GLfloat ={1,-0.01f,0,0,0.01f,1,0,0,0,0,1,0,0,0,0.04f,1}

sub WinMainCRTStartup()
dmScreenSettings.dmSize=sizeof(dmScreenSettings)
dmScreenSettings.dmPelsWidth   = 640
dmScreenSettings.dmPelsHeight  = 480
'dmScreenSettings.dmBitsPerPel = 32
' its risky to remove the flag and bits but probably safe on compo machine :-)
dmScreenSettings.dmFields=DM_PELSWIDTH Or DM_PELSHEIGHT
ChangeDisplaySettings(@dmScreenSettings,CDS_FULLSCREEN)

' minimal windows setup code for opengl 
pfd.cColorBits = 32
pfd.cDepthBits = 32
pfd.dwFlags    = PFD_SUPPORT_OPENGL Or PFD_DOUBLEBUFFER
hDC = GetDC(CreateWindow("edit", 0, WS_POPUP Or WS_VISIBLE Or WS_MAXIMIZE, 0, 0, 0, 0, 0, 0, 0, 0))

SetPixelFormat(hDC, ChoosePixelFormat(hDC, @pfd), @pfd)
wglMakeCurrent(hDC, wglCreateContext(hDC))

' create the shaders inlined to save bytes
for i=0 to 6
glFP(i) = cast(GenFP, wglGetProcAddress(glnames(i)))
next

v = cast(PFNGLCREATESHADERPROC, glFP(0))(GL_VERTEX_SHADER)
f = cast(PFNGLCREATESHADERPROC, glFP(0))(GL_FRAGMENT_SHADER)
p = cast(PFNGLCREATEPROGRAMPROC, glFP(3))()

q = @labvsh
cast(PFNGLSHADERSOURCEPROC, glFP(1))(v, 1, cast(byte ptr ptr, @q), NULL)
cast(PFNGLCOMPILESHADERPROC, glFP(2))(v)

q = @labfsh
cast(PFNGLSHADERSOURCEPROC, glFP(1))(f, 1, cast(byte ptr ptr, @q), NULL)
cast(PFNGLCOMPILESHADERPROC, glFP(2))(f)

cast(PFNGLATTACHSHADERPROC, glFP(4))(p,v)
cast(PFNGLATTACHSHADERPROC, glFP(4))(p,f)

cast(PFNGLLINKPROGRAMPROC, glFP(5))(p)
cast(PFNGLUSEPROGRAMPROC, glFP(6))(p)

ShowCursor(FALSE)

'**********************
' NOW THE MAIN LOOP...
'**********************

' there is no depth test or clear screen...as we draw in order and cover
' the whole area of the screen.

while GetAsyncKeyState(VK_ESCAPE) = 0
' move forward and rotate slightly each frame
' glMultMatrix is smaller (20 bytes) than glTranslatef and glRotatef!!
glMultMatrixf(@m(0))
glRecti(-1,-1,1,1)
SwapBuffers(hDC)
wend
' necessary under vista it seems... :-( extra bytes required.
ExitProcess(0)
end sub

Jim
Title: Re: Making tiny FB executable programs
Post by: slippy on July 09, 2007
wow ... that's a fat tut ... k+ m8 ... and thanks for this :)
Title: Re: Making tiny FB executable programs
Post by: ninogenio on July 09, 2007
Cool cheers jim that helps a lot!
Title: Re: Making tiny FB executable programs
Post by: Shockwave on July 09, 2007
Also fails to compile here It is failing in glu.bi
Any clues?
Title: Re: Making tiny FB executable programs
Post by: benny! on July 09, 2007
I am not using FB ... but this is a very interesting tutorial, Jim.

K++ !!!
Title: Re: Making tiny FB executable programs
Post by: p01 on July 09, 2007
Nifty.
Title: Re: Making tiny FB executable programs
Post by: Jim on July 09, 2007
Quote
Also fails to compile here It is failing in glu.bi
Any clues?
Different versions of FB.  Me and nino are both using 0.16b.  Has everyone else upgraded while we weren't looking? :P
I'll try to get a fix for 0.17b later.

Jim
Title: Re: Making tiny FB executable programs
Post by: Stonemonkey on July 09, 2007
I'm using 0.17b and it's working here.
Title: Re: Making tiny FB executable programs
Post by: Jim on July 09, 2007
I've just downloaded 0.17b and it works for me too (I just had to remove 'option explicit').  Which version of FB are you using Shockwave?

Jim
Title: Re: Making tiny FB executable programs
Post by: ninogenio on July 09, 2007
it could be 0.15 he is yousing as the problem he is getting is an incompatibility between glu.bi and windows.bi im sure check my trinity port thread for further details.
Title: Re: Making tiny FB executable programs
Post by: Jim on July 09, 2007
Any idea where I can download 0.15b - it's not available at freebasic.net any more!

Jim
Title: Re: Making tiny FB executable programs
Post by: ninogenio on July 09, 2007
not sure if it can be downloaded any more jim as i dont think many people use it anymore  :-\
Title: Re: Making tiny FB executable programs
Post by: Stonemonkey on July 09, 2007
I have it here on my hd.
Title: Re: Making tiny FB executable programs
Post by: Jim on July 09, 2007
Found it.  It's hidden on sourceforge :)
Jim
Title: Re: Making tiny FB executable programs
Post by: Jim on July 09, 2007
I'm really sorry Shockwave, there's no way 0.15b will ever compile this code.  It's easy to get round the 'max' problem, but then it fails on all the function pointer stuff :(
If anyone else wants a look, the 'max' fix is just
Code: [Select]
#define max
#include "windows.bi"
#undef max

Jim
Title: Re: Making tiny FB executable programs
Post by: ninogenio on July 09, 2007
bugger thats a real shame is there no way you could update sw?
Title: Re: Making tiny FB executable programs
Post by: Jim on July 09, 2007
You can install as many versions of fb into different directories/program groups as you like.  I've now got 0.15/0.16/0.17 all installed at the same time :)  You just have to change the default values the installer gives you.

Jim
Title: Re: Making tiny FB executable programs
Post by: Rbz on July 09, 2007
Karma boost!
Title: Re: Making tiny FB executable programs
Post by: ninogenio on July 10, 2007
i followed all above steps and so far so good now im on to the platform sdk will the newer windows sdk work ok? and its over a gigs worth of download!

i already have visual studio so do i still need the platfom sdk?
Title: Re: Making tiny FB executable programs
Post by: Jim on July 10, 2007
Any version of the SDK should do.  Visual Studio will have them in, I think.
Mine are here
C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\Lib

Jim
Title: Re: Making tiny FB executable programs
Post by: ninogenio on July 10, 2007
phew thanks jim they are there!  :) i thought i was going to be on the think end of a huge download.
Title: Re: Making tiny FB executable programs
Post by: ninogenio on July 10, 2007
im getting a linker error now in the form of

Code: [Select]
C:\Documents and Settings\nino\Desktop\trinity>Fbc.exe -c trinity.Bas

C:\Documents and Settings\nino\Desktop\trinity>\MASM32\BIN\ml /c /coff stub.asm

Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997.  All rights reserved.

 Assembling: stub.asm

C:\Documents and Settings\nino\Desktop\trinity>crinkler /SUBSYSTEM:WINDOWS /OUT:
trinity.exe /LIBPATH:"C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\
Lib" kernel32.lib user32.lib trinity.o stub.obj
Crinkler 1.0a (Jan  7 2007) (c) 2005-2007 Aske Simon Christensen & Rune Stubbe

Target: trinity.exe
Subsystem type: WINDOWS
Compression mode: FAST
Hash size: 100 MB
Hash tries: 20
Order tries: 0
Transforms: NONE
Replace DLLs: NONE
Range DLLs: NONE

loading:
  kernel32.lib  user32.lib  trinity.o  stub.obj

 : fatal error: LNK   0: could not find symbol '_ChoosePixelFormat@8'


C:\Documents and Settings\nino\Desktop\trinity>pause
Press any key to continue . . .

have i missed a lib out?
Title: Re: Making tiny FB executable programs
Post by: Jim on July 10, 2007
You need to add opengl32.lib glu32.lib gdi32.lib to the link.

Jim
Title: Re: Making tiny FB executable programs
Post by: ninogenio on July 10, 2007
doh of course,

cheers jim the best i can get the trinity example to is 1028 bytes thats with rearanging the code and messing around with crinkler.
Title: Re: Making tiny FB executable programs
Post by: ninogenio on July 10, 2007
hey jim i had a little mess about with your example and the best i could get was 1066 but one thing i noticed was streight away it was linking to 1076 bytes so i guess i must be getting slightly better compresion using these switches.

crinkler /SUBSYSTEM:WINDOWS /ORDERTRIES:10000 /HASHTRIES:500 /OUT:trinity.exe /LIBPATH:"C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\Lib" kernel32.lib user32.lib trinity.o stub.obj opengl32.lib glu32.lib gdi32.lib
Title: Re: Making tiny FB executable programs
Post by: Shockwave on July 10, 2007
Thanks Jim for the excellent help as always! K+

I will have to install 1.7 I think. I don't use the laptop anymore for programming so there's no reason not to update any more I guess.
Title: Re: Making tiny FB executable programs
Post by: neumanix on August 30, 2007
I tried this with a couple of programs, one using tinyptc and one using glfw. On both attempts I get a linker error that says "could not find symbol WinMainCRTStartup".
What am i missing here?!
Title: Re: Making tiny FB executable programs
Post by: ninogenio on August 30, 2007
i think you might have to rework some of the steps to get tinyptc or glfw working with this as it was geard towards aulds 1k ogl framework also remember with this you cant youse any of fbs commands as jim stubbs them off to get tiny fb executables.
Title: Re: Making tiny FB executable programs
Post by: neumanix on August 30, 2007
ok, I solved the problem that I had... I didn't undertand that there has to be a function called "WinMainCRTStartup" in your code.
But now I get other linking errors, some kind of rnd stuff. I guess that's because I used RND which is a freebasic command.
I'll try some more to get the glfw code to work. I'll need a static glfw.lib I guess, gonna try to figure out how to make one :)
Title: Re: Making tiny FB executable programs
Post by: ninogenio on August 30, 2007
yeah the rnd errors are because rnd belongs to freebasic not sure about glfw but ptc stuff should be possible i think.
Title: Re: Making tiny FB executable programs
Post by: coderJeff on October 23, 2007
Here's a trick that makes small exes.  It won't be as small as crinkler,
but it is fairly easy to set-up, and you need no other resources except what's packaged with fbc 0.18.2.

Assume that FreeBASIC is installed at:
C:\FreeBASIC\

and that our "trick" is installed at:
F:\tinyfb\

Create some directories like so:
mkdir F:\tinyfb\
mkdir F:\tinyfb\bin\
mkdir F:\tinyfb\bin\win32\
mkdir F:\tinyfb\lib\
mkdir F:\tinyfb\lib\win32\


Copy two files from C:\FreeBASIC\ to our new directory:
copy C:\FreeBASIC\bin\win32\i386pe.x F:\tinyfb\bin\win32\i386pe.x
copy C:\FreeBASIC\bin\win32\ld.exe F:\tinyfb\bin\win32\ld.exe


Go into F:\tinyfb\lib\win32\ and create some empty object files just to make the fbc.exe command line happy:
F:
cd \tinyfb\lib\win32\
echo REM > crt2.bas
fbc -c crt2.bas
copy crt2.o crtbegin.o
copy crt2.o crtend.o
copy crt2.o fbrt0.o
cd ..\..


Now let's create our example:
Code: [Select]
'' hello.bas

#include once "windows.bi"

function WinMainCRTStartup cdecl _
  alias "WinMainCRTStartup" () as integer

  Messagebox( 0, "Small EXE example", "Hello", MB_OK )
  return 0

end function

Finally, the last two steps are to compile, then to link our exe:
fbc -c hello.bas
fbc hello.o -s gui -prefix F:\tinyfb -p "C:\FreeBASIC\lib\win32"


The "-prefix F:\tinyfb" option tells fbc where to pick up the extra bits of code.  Since we provided empty object files, no size is added.  The "-p" options tells fbc where to find all the import libs.

For me, this compiles to 2560 bytes. 

I know this is an old-ish thread, but I meant to post something here after I saw this, but never did.

Also, if you are making a Windows App and are planning to use MSVCRT, but want to make sure you don't get any fb-runtime stuff, the fbc command line option '-nodeflibs' was updated not to include 'fbrt0.o'.  Don't know if that's any help, but thought I would mention.

Title: Re: Making tiny FB executable programs
Post by: Shockwave on October 23, 2007
Some good tips there CoderJeff :) Have some good Karma for that and welcome to the forum (I know you have been registered a while, but it's always nice to see people posting, especially good stuff like that!).
Title: Re: Making tiny FB executable programs
Post by: ninogenio on October 23, 2007
k+ coderjeff,

its great to hear of other ways size can be reduced in fb. nice one!
Title: Re: Making tiny FB executable programs
Post by: rain_storm on October 25, 2007
Okay I finally got this to work (Just Jim's tiny.exe) it is really my first time working with a commandline tool
now I have a question
Is it better to use OpenGL or tinyptc for creating small exe's if all I'm asking from them is to display a buffer of rgb values (like a xor texture or plasma effect)
Title: Re: Making tiny FB executable programs
Post by: coderJeff on October 25, 2007
Thanks Shockware, ninogenio.  Yeah, I lurk in here from time to time.  You guys put out some impressive stuff.  And use FreeBASIC in ways nobody else is even thinking about.  It's always a pleasure to visit.