Let's get rid of it - Compiling C without the C Runtime

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi if you're currently coding or ever have coded a c application you might have heard of the C runtime library that gets statically or dynamically linked into your executable by default uh this Library contains all the necessary function defined by the C standard such as F open print F now this is actually the glue that makes your C program portable because every platform that allows you to use the C programming language uh will have its own implement ation of the C runtime Library which usually is a nice thing right I don't have to worry what kind of platform I'm running in except that's not quite true because for example on Windows it doesn't even implement the whole C standard so there might be some things missing now underneath the hood what actually happens if I call F open for example the C code will just you know provide me with the file structure that I can use throughout the program but then actually at some point point it will call out into the kernel apis specifically for that platform that will then the openen the actual file handle and return it to the C runtime library now if I don't really care about you know portability and don't really want to Port my program over to different platforms such as Linux or Mac why not just use the kernel apis directly and not rely on the C runtime at all it would make my executable much smaller and I'm in direct control of the code that I'm writing and I can fix things easily and I can reason about what I ship of course to make the executable smaller I could also just dynamically link the C runtime library but then I still need to ship it potentially to the user because there's no guarantee that they might actually have the exact version that I need uh installed and in fact if you have ever installed a video game on Steam or something like that you might see a setup uh pop up that uh tries to install the VC runtime which is exactly that it is the C runtime that's being installed on your system that particular ular version that this game requires so obviously your mileage may vary whether you find that useful or actually is something you might want to consider for your own project but I got really interested in that and wanted to figure out if I can actually just compile a Windows application without the cun time included and I found a bunch of online resources which I will link down in the description as well and yeah I got it working so let me show you so I created this example application right here all the that it's doing is it's opening a file reading the contents of that file out into an array closing the file and then printing all the contents of the array out onto the screen and as you can see it's importing stdi iio and STD lib and I'm using very common C library functions such as F open F read F close and puts and I'm just going to go ahead and build this program and then run it just so you can see that it works here are all the contents of the file and I'm printing all done at the end here and if we look at the executable we can see it's roughly 126 kiloby big um that is because the whole C runtime library is statically linked into the executable so the first step to remove the dependency to the C library is of course remove the include files but now I'm not going to be able to use f open and F read and puts of course um I have to provide my own implementations of these things or at least find an Windows equivalent I can use so I'm going to start by including the windows header file now fop can be replaced with create file um which basically means create me a file handle uh for this file name and I want to be able to read from it and uh fail if the file does not exist and instead of checking the file handle for null I'm going to check for invalid handle value which is what create file will return if it fails similar F read can be replaced with read file which needs the file handle the destination array of where we want to read the data into the amount of bytes we want to read and then it wants a pointer to a dword which will be the amount of data that actually has been read from the file similar to what I have done down here so the new if would look something like this if not read file or read it doesn't equal data size F close can just be replaced with close handle and that is pretty much it for the file reading now the only thing left to do is having a replacement for put s for that I'm just going to Define my own function and because I'm building this program with the subsystem console the operating system will make sure that I already have a console window attached to it so all I need to do is get the handle of that console window which I can do with get STD handle for the standard output handle this is the equivalent to STD out in C then I can use right console a uh pass in the console handle write out the value uh I also need to specify the length of the value which I can just do with st Str Len and in the C standard Library put s usually puts in a new line at the end of the value that I pass in so I'm just going to write that to the console as well now we have a Bare Bones C Windows application that is not using any functions as defined in the headers except you might be wondering well I'm using St Len here which is usually a C library function but as it happens the Microsoft C compiler provides this implementation as an intrinsic if the compiler encounters stln it will provide us an implementation now if I go ahead and build this and then run it you see it still works and if we now look at the executable size I can see that it is 113 Koby a tiny bit smaller because I'm not using any C library functions however the C standard library is still being statically linked in even though I technically do not really use it anymore well apart from the main function if I completely want to exclude the PC runtime I would have to add this link option which is called No default link this will now prevent any default libraries of being statically linked into my program however because I'm using Windows functions I also need to link in the kernel 32 lip previously it has been included by default but now because I specify no default lip it will no longer be pulled into my executable so now with the cun time Library excluded from my project let me go ahead and build it and as you can see I'm now getting a few errors here uh mostly about unresolved external symbols the one I'm going to focus first is this main CRT startup now all that means is main is actually not the first function that is being called in my application in actuality it is this main CRT startup uh the C standard Library calls out into this function which will set up a bunch of C runtime specific features and pass command lines and all this stuff and then this function will call out into main but now because I'm no longer providing the C library uh into my executable I need to provide a definition for this myself because this function no longer exists so I'm going to do that right now and all I'm going to do here is call out into Main and store the results in an integer now if my program starts it will actually find the main CRT startup function it will call into main uh which will then return a result but then I'm just doing nothing afterwards with that result that has the effect that the process will still be alive because I have not told the operating system that my Pro process is done and it should close it so what I need to do is call exit process and pass in the result so it can then be displayed to the user in the console window if I go ahead and compile this now I can see that the main CRT startup um reference is actually now been resolved however I do not really like the name main CRT startup it still suggests that there's a c runtime attached to this program that kind of needs to be set up so I'm just going to Reen name this function to something that I like more and specify a flag on the Linker to use this new entry point instead so I'm just going to name this program start and on the Linker I'm going to provide a new entry point to use which is also Program start so now instead of using main CRT startup it will jump into Program start first now there's a few other errors uh left to deal with such as the GS Handler check security check check cookie and security cookie I could provide my own implementation for all these functions but for this project I'm just going to disable this feature Al together all these methods have to do with um buffer overrun checks which is a common attack Vector but since this is not a security minded application I do not care about this feature so I'm just going to disable it so if I go ahead and build this now there's only two unresolved external symbols left to deal with and one of the things left to deal with is the check stack function right here I'm also not going to provide my own implementation for it but essentially what this is doing is for every function call it will check if there's still room left on the stack for the arguments that we pass in and if not it would dynamically allocate or rather commit a new page of memory for the stack on Windows every program by default gets a 1 MB stack but only 4 kiloby of Stack are actually committed and that means whenever we actually need more memory than 4 kiloby on the stack it will just go ahead and dynamically uh commit another page of memory for us so because I do not want to um deal with this I'm just going to provide a ridiculously large probing value and then I'm also going to tell the Linker to not only Reserve 1 Megabyte of Stack but also immediately commit it so now if I go ahead and build this you can see I only have one unresolved external symbol left and that is for memset why does the compiler need to call memset that is because our ridiculously large data array right here um is being zeroed out and the way the compiler is doing this by actually calling mset with the value of zero to set all this memory and because memet is a C library function I need to provide my own implementation for that as well now I'm just going to copy paste an implementation in here right now but it is fairly simple it just basically has a destination and then we Loop over the amount of count that we specified and then set each bite uh of however many counts we have to the value that is specified so if I go ahead and build this now you see that I get another error that memet is actually an intrinsic function and cannot be defined so the C compiler uh the Microsoft C compiler similar to sdn actually has an intrinsic for memset so I could be using memet down here for example anywhere in my program without actually specifying this function but for some reason it still relies on the C implementation somehow even if this is an intrinsic I'm not quite sure why if anyone knows um just leave a comment down below I would be very curious to know but I actually have to to tell the compiler now to not use the intrinsic memet function but rather use my own specified one right here and I can do this by using this pragma right here where I just say pragma function memet so this basically means do not use the intrinsic um but rather we Define it ourselves right here so if I go ahead and compile this now we see no errors anymore and let's run it and it works and if I now look at the output size of the executable we can see is actually 4 kilobyte um that is because I now have an executable without the C run time included I'm just using Windows kernel functions and actually if I check the properties uh you can see it's slightly under 4 kiloby actually it's just that this hard drive is using 4 kiloby sector sizes so it always allocates 4 kilobyte blocks but the actual data is just 3.5 [Music] kiloby and as you can see it's quite involved to get thec runtime Library um out of your application you have to provide all your implementation for these functions that you've been using before and then you're also giving up some things like the buffer overrun check for example obviously if you're a very security minded application you should probably consider putting that back in but for me personally for my projects I do not really care about it I'm also going to put the example projects that you just saw up for download and you will find the link down in the description as well together with all the links to the documentation of all the command line flags that I used I hope this was somewhat interesting to you and maybe let me know down in the comments if you would ever consider compiling without the C runtime library or if you actually prefer it included in your application and that's about it and I see you next time bye oh
Info
Channel: Dani Crunch
Views: 38,559
Rating: undefined out of 5
Keywords: VLOG, Dani, Tutorial, C11, C17, CRT, C Runtime, Programming, Coding, Example, Showcase, Compiling, Compiler, Linker
Id: kcCngf0R9QQ
Channel Id: undefined
Length: 15min 14sec (914 seconds)
Published: Sat Jan 27 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.