Need help with code generation

Adding back the “all recipients” - sorry, sending message from my phone, I forgot…

Since my runtime is for a Pascal compiler, it has to “adapt” the C startup into a suitable Pascal environment. This means running the init portion of other modules as well as discarding the argc, argv arguments. So, I have a C main, which calls __PascalMain, which is the “main” for the pascal program itself after some other setup code.

The whole runtime of C is quite complex (in terms of “what code is executed in what order”, at least), and C++ is a little worse on top of that, but basically there is code “before main” in C. If you don’t use the C library, you will probably have to replace this by some other code that does something similar.

But assuming you don’t have a very good reason for doing so, I would certainly suggest that you make your code simply pass the .bc or .o file that your compiler generates to the C compiler.

I would also ignore things like “is it faster to do puts than fputc” - at least until you have other things working reasonably well. This according to the principle of “avoid premature optimisat”. Unless you are really familiar with how compilers work and the design thereof, you have “bigger fish to fry” than micro-optimising your string output… I have two years of experience in writing my own LLVM frontend, and I guarantee that optimising string output is dead easy to do “later”. Getting the compiler to deal with some of the more complex parts of whatever language it is will not be…

I think I’ll have to do as you did for the runtime, but will the lib’s main function be the resulting program’s real main function? And your __PascalMain implementation is in the object file your compiler created, isn’t it?
We can say that the main function a programmer writes is not the very first thing that is called in the final program (well obviously).

Yes, in my case, main is in the runtime library and is the first thing that runs from MY code, and in turn calls the __PascalMain that the compiler generated. The compiler knows about certain built-in functions such as write and writeln, and will replace those with corresponding calls to the runtime library function equivalent.

Of course, you can either completely forego the convenience of the C library, and implement your own library, starting with Linux or Windows system calls written in assembler [and if you plan on supporting further OS’s, obviously you need to implement those too] - it’s worth noting that system calls are different per architecture, so if you plan on supporting more than x86-32 and x86-64, you will need to write assembler code for each of those too. Oh, and system calls are quite different between OS’s.

You will then be able to simply call ld -o name-supplied-by-compiler object-files-supplied-by-compiler -lyour-runtime.a. I decided to go the simple route of using the already existing C runtime for file and console I/O, random number, a few floating point functions and some other functions. Because I’m a bit lazy and think that it’s OK to do that. Like I said early in this thread, I do have some plans to replace this in the future, but it’s nowhere near the top of the todo-list.

Just as a reference, the ld line of my compiler is:

/usr/bin/ld" --hash-style=gnu --no-add-needed --build-id --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o gol /usr/lib/gcc/x86_64-redhat-linux/4.9.2/…/…/…/…/lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.9.2/…/…/…/…/lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.9.2/crtbegin.o -L/home/mats/src/lacsap -L/usr/lib/gcc/x86_64-redhat-linux/4.9.2 -L/usr/lib/gcc/x86_64-redhat-linux/4.9.2/…/…/…/…/lib64 -L/usr/local/bin/…/lib64 -L/lib/…/lib64 -L/usr/lib/…/lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.9.2/…/…/… -L/usr/local/bin/…/lib -L/lib -L/usr/lib gol.o -lruntime -lm -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.9.2/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.9.2/…/…/…/…/lib64/crtn.o

Looking at that, you can probably understand why I decided to NOT write a bit of code that finds and links to all of those things myself.

Great, and where will the code that initializes stdout and stdin (for example) be executed? Even before lib’s main function?

I already thought about linker call, maybe with an execv() call.
Anyway I’m quite sure about what to do with the linker now thanks!

My only problem now is the runtime and the runtime library