Use of "-m32 -march=i686" to replace the standard toolchain

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
himAllThatBoyME
Posts: 1
Joined: Sat Jun 19, 2021 6:19 pm
Libera.chat IRC: himAllThatBoyME

Use of "-m32 -march=i686" to replace the standard toolchain

Post by himAllThatBoyME »

I'm just starting out with OS development with C++, and have not found anything in the OsDev book about why it is necessary to use the toolchain rather than simply add "-m32 -march=i686" to a normal g++ compile command. Does this work? If not, is there a reason why I shouldn't do it?
Don't you just hate forum signatures that try to be funny?
Ethin
Member
Member
Posts: 625
Joined: Sun Jun 23, 2019 5:36 pm
Location: North Dakota, United States

Re: Use of "-m32 -march=i686" to replace the standard toolch

Post by Ethin »

This has been heavily discussed in another forum topic, and somewhat in the wiki, but to recap: the reason that this doesn't work is that your compiler on Linux/Cygwin/Mac OS/BSD/... will build your code for the host system. This means it will pull in libgcc -- but not the libgcc you want, but rather the libgcc that your host OS provides. It will also generate code that just won't work in real mode or other execution environments where hardware extensions are not enabled, such as code that uses SSE, AVX, neon, etc., or in environments where extensions are nonexistent outright, such as generating RISC-V atomic instructions to be run in an environment that does not support those instructions.
To a point, generation of these extensions can be toggled, but it requires a great deal of technical knowledge of how the compiler works and your bound to still generate code that still isn't going to work. This is because some processor architectures, such as x86, initially start in a highly restricted environment to emulate old architectural environments, like real mode. Your host OS might be 32, 64, or 128-bit, and such code would not run in real mode, for example.
This is the primary reason a cross-compiler toolchain is required. You can get away with a smaller build process using LLVM or Rust, but you will (still) need to compile compiler-rt for clang/clang++, or compiler_builtins, alloc, and core for Rust, for your target operating environment. Trying to get around this is going to make your OS development experience extremely hellish and is most likely going to give you the wrong idea. To save yourself the pain and complexity of trying to affectively reverse-engineer your compiler toolchain, build a cross-compiler toolchain or use Rust.
kerravon
Member
Member
Posts: 278
Joined: Fri Nov 17, 2006 5:26 am

Re: Use of "-m32 -march=i686" to replace the standard toolch

Post by kerravon »

himAllThatBoyME wrote:I'm just starting out with OS development with C++, and have not found anything in the OsDev book about why it is necessary to use the toolchain rather than simply add "-m32 -march=i686" to a normal g++ compile command. Does this work? If not, is there a reason why I shouldn't do it?
I'm not 100% sure what I am doing differently to others, but I use the same C compiler (gcc386, generates a.out) for both the OS and for a.out applications. I also have a gccwin to generate PE/COFF instead of a.out, but I have not yet switched the kernel to that format because that requires me to modify the loader too. I don't see any technical barrier to that either. I note that others use something called a "linker script", but I never noticed a need for that either. You can find my tools here: http://pdos.org (look for custom.zip).
Korona
Member
Member
Posts: 1000
Joined: Thu May 17, 2007 1:27 pm
Contact:

Re: Use of "-m32 -march=i686" to replace the standard toolch

Post by Korona »

Aside from libgcc (which you can only build by building the compiler itself, and which is required in many scenarios), it is possible to use a Linux GCC if you also pass a ton of flags to change the default behavior of the compiler (and many of these flags are required changes from one GCC version to another and from one Linux distro to another (since they configure GCC differently)). So yes, save yourself the hassle and just build a cross compiler. You will have to do that anyway once you want to compile user space programs for your OS (since the Linux GCC does not know how to target "i686-yourOS"), so why not do it now.
Ethin wrote:You can get away with a smaller build process using LLVM or Rust, but you will (still) need to compile compiler-rt for clang/clang++, or compiler_builtins, alloc, and core for Rust, for your target operating environment. Trying to get around this is going to make your OS development experience extremely hellish and is most likely going to give you the wrong idea. To save yourself the pain and complexity of trying to affectively reverse-engineer your compiler toolchain, build a cross-compiler toolchain or use Rust.
Using Rust does not save you from building a cross compiler, at least not for user space programs (you do need a Rust cross compiler for that).
managarm: Microkernel-based OS capable of running a Wayland desktop (Discord: https://discord.gg/7WB6Ur3). My OS-dev projects: [mlibc: Portable C library for managarm, qword, Linux, Sigma, ...] [LAI: AML interpreter] [xbstrap: Build system for OS distributions].
kerravon
Member
Member
Posts: 278
Joined: Fri Nov 17, 2006 5:26 am

Re: Use of "-m32 -march=i686" to replace the standard toolch

Post by kerravon »

Korona wrote:Aside from libgcc (which you can only build by building the compiler itself, and which is required in many scenarios), it is possible to use a Linux GCC if you also pass a ton of flags to change the default behavior of the compiler (and many of these flags are required changes from one GCC version to another and from one Linux distro to another (since they configure GCC differently)). So yes, save yourself the hassle and just build a cross compiler. You will have to do that anyway once you want to compile user space programs for your OS (since the Linux GCC does not know how to target "i686-yourOS"), so why not do it now.
Sounds like the Linux GCC is way too complicated. Try replacing it with my GCC 3.2.3 which is a C90-compliant program, and PDPCLIB which is a C90-compliant library. Far easier to understand.
Ethin
Member
Member
Posts: 625
Joined: Sun Jun 23, 2019 5:36 pm
Location: North Dakota, United States

Re: Use of "-m32 -march=i686" to replace the standard toolch

Post by Ethin »

Korona wrote:Aside from libgcc (which you can only build by building the compiler itself, and which is required in many scenarios), it is possible to use a Linux GCC if you also pass a ton of flags to change the default behavior of the compiler (and many of these flags are required changes from one GCC version to another and from one Linux distro to another (since they configure GCC differently)). So yes, save yourself the hassle and just build a cross compiler. You will have to do that anyway once you want to compile user space programs for your OS (since the Linux GCC does not know how to target "i686-yourOS"), so why not do it now.
Ethin wrote:You can get away with a smaller build process using LLVM or Rust, but you will (still) need to compile compiler-rt for clang/clang++, or compiler_builtins, alloc, and core for Rust, for your target operating environment. Trying to get around this is going to make your OS development experience extremely hellish and is most likely going to give you the wrong idea. To save yourself the pain and complexity of trying to affectively reverse-engineer your compiler toolchain, build a cross-compiler toolchain or use Rust.
Using Rust does not save you from building a cross compiler, at least not for user space programs (you do need a Rust cross compiler for that).
I know, I was just addressing the particular question. I'll definitely need to cross-compile Rust, but I don't have userspace apps yet so I can hold off on that for a bit.
Ethin
Member
Member
Posts: 625
Joined: Sun Jun 23, 2019 5:36 pm
Location: North Dakota, United States

Re: Use of "-m32 -march=i686" to replace the standard toolch

Post by Ethin »

kerravon wrote:
Korona wrote:Aside from libgcc (which you can only build by building the compiler itself, and which is required in many scenarios), it is possible to use a Linux GCC if you also pass a ton of flags to change the default behavior of the compiler (and many of these flags are required changes from one GCC version to another and from one Linux distro to another (since they configure GCC differently)). So yes, save yourself the hassle and just build a cross compiler. You will have to do that anyway once you want to compile user space programs for your OS (since the Linux GCC does not know how to target "i686-yourOS"), so why not do it now.
Sounds like the Linux GCC is way too complicated. Try replacing it with my GCC 3.2.3 which is a C90-compliant program, and PDPCLIB which is a C90-compliant library. Far easier to understand.
GCC 3.2.3? Seriously? You do know that was released in 2003, right? We're on 11.1.0 now.
Linux GCC has always been complicated. Every distribution will compile it differently and will use different flags when building your code. The fact that you have to go all the way back to 3.2.3 if not older, and thereby suffer the fact that your OS will never be able to take advantage of any optimizations or other compiler advancements after 3.2.3 proves that. Just build a cross-compiler. I don't get why people are trying to circumvent this process. You'll have to do it in one form or another. You might be able to avoid it now, or half-avoid it, but you can't avoid it forever.
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Use of "-m32 -march=i686" to replace the standard toolch

Post by iansjack »

I'm sure such an old version of GCC is fine if you're building what is essentially a clone of the prehistoric MS-DOS. But not if you're aiming for a more complete OS.
vvaltchev
Member
Member
Posts: 274
Joined: Fri May 11, 2018 6:51 am

Re: Use of "-m32 -march=i686" to replace the standard toolch

Post by vvaltchev »

It is possible to use the host compiler when you target i686, but that's NOT a good idea. And, believe me, adding "-m32 -march=i686" is not really THE problem here at all, as kernel projects require passing a ton of options to the compiler anyway.

The first problem when using the host compiler comes when you need to build software (usermode programs) that will run on your kernel, not the kernel itself. That's a problem because very likely your project won't be 100% compatible with Linux and Glibc. The majority of the kernel projects are not compatible with Linux at binary level. But, some of them still offer a POSIX interface with a custom libc implementation. So, now, how you will use the host compiler to build a regular program with a different libc? It's possible with GCC, but it's a great mess. It requires the use of special "GCC scripts" to be passed with the "-specs" option and also compiler-wrapper scripts to have a simpler pseudo-regular compiler interface for the build system. A GCC script will set new include paths for system headers, the object file to use for _start, the default libc to link with and other stuff like that. But, that will not work with clang. You'll need a different solution for that compiler. Also, that approach has a TON of traps and pitfalls. It's not worth in 99% of the cases.

The second problem is that, if you write a kernel compatible with Linux, your project still won't be 100% compatible with all the modern and advanced syscalls that glibc will use, for years. So, even if you won't need to write a custom libc, you will still need to use lighter libc implementation like libmusl or uclibc-ng to build apps for your kernel. In this case you STILL will need a custom toolchain. I avoided building a custom toolchain myself by using prebuilt libmusl gcc-toolchains from: https://toolchains.bootlin.com/. But, again, that comes at the price of being compatible with Linux at binary level. Most projects here don't do that, by choice.

The third problem with using the host compiler is that generally it won't work if you want to target anything other than i686. So, if you want to build for AARM64, you will still need to build a custom toolchain or, at least, a linux pre-built toolchain if you're in my case.
Tilck, a Tiny Linux-Compatible Kernel: https://github.com/vvaltchev/tilck
vvaltchev
Member
Member
Posts: 274
Joined: Fri May 11, 2018 6:51 am

Re: Use of "-m32 -march=i686" to replace the standard toolch

Post by vvaltchev »

iansjack wrote:I'm sure such an old version of GCC is fine if you're building what is essentially a clone of the prehistoric MS-DOS. But not if you're aiming for a more complete OS.
Older compilers optimize much less and don't generally take advantage of UB like modern ones do. So, it will be terrible to develop a new project using an older compiler and realize much later that it's a mess to make it compile and work correctly with modern ones. Also, older compilers (like old software in general) are not really supported by modern operating systems. Therefore, using them would also mean using an old version of Linux or some old FreeBSD or having a super-tricky setup to make them work: with that premise, the chance of getting any interest in the project really tends to zero.

Better start directly with modern and stable (but not bleeding edge) technologies that are widely available today.
Tilck, a Tiny Linux-Compatible Kernel: https://github.com/vvaltchev/tilck
kerravon
Member
Member
Posts: 278
Joined: Fri Nov 17, 2006 5:26 am

Re: Use of "-m32 -march=i686" to replace the standard toolch

Post by kerravon »

Ethin wrote:
kerravon wrote:
Korona wrote:Aside from libgcc (which you can only build by building the compiler itself, and which is required in many scenarios), it is possible to use a Linux GCC if you also pass a ton of flags to change the default behavior of the compiler (and many of these flags are required changes from one GCC version to another and from one Linux distro to another (since they configure GCC differently)). So yes, save yourself the hassle and just build a cross compiler. You will have to do that anyway once you want to compile user space programs for your OS (since the Linux GCC does not know how to target "i686-yourOS"), so why not do it now.
Sounds like the Linux GCC is way too complicated. Try replacing it with my GCC 3.2.3 which is a C90-compliant program, and PDPCLIB which is a C90-compliant library. Far easier to understand.
GCC 3.2.3? Seriously? You do know that was released in 2003, right? We're on 11.1.0 now.
The latest version of my GCC 3.2.3 was released 2021-06-09. I consider it to be the best C compiler available for Windows. It was created for a reason. It is the only thing that actually meets my requirements. It's also the best C compiler available for Freedos, and the best compiler for MVS.
Linux GCC has always been complicated. Every distribution will compile it differently and will use different flags when building your code. The fact that you have to go all the way back to 3.2.3 if not older, and thereby suffer the fact that your OS will never be able to take advantage of any optimizations or other compiler advancements after 3.2.3 proves that.
No, it doesn't prove that at all. There is probably no barrier to GCC 11.1.0 being as neat and clean as my GCC 3.2.3. Someone just needs to put in the development effort to make it C90-compliant. Every single version of GCC *should* and probably *could* have ben C90-compliant from day one.

And as for "optimizations", feel free to play "spot the speed difference". Best of luck with that. I'd rather have something that actually works. If you find a way of shaving 1% off the runtime, that's great, even though I can't detect it, but make the package C90-compliant first. Also make it target 80386 first. So that it works on essentially every 32-bit x86 computer since 1986. That's a great start.
kerravon
Member
Member
Posts: 278
Joined: Fri Nov 17, 2006 5:26 am

Re: Use of "-m32 -march=i686" to replace the standard toolch

Post by kerravon »

iansjack wrote:I'm sure such an old version of GCC is fine if you're building what is essentially a clone of the prehistoric MS-DOS. But not if you're aiming for a more complete OS.
I know what the output of my GCC 3.2.3 looks like, and I can tell you that I know of no barrier to creating a "more complete OS". Is there a specific instruction it fails to emit (and that can't be satisfied by supplying separate assembly, or inline assembly) that prevents a "more complete OS" from being built?

Also, most of these hobbyist projects aren't going to go very far. At the time the special instruction is required, maybe that is the point at which a "more modern" GCC could be used? What's wrong with that approach?
kerravon
Member
Member
Posts: 278
Joined: Fri Nov 17, 2006 5:26 am

Re: Use of "-m32 -march=i686" to replace the standard toolch

Post by kerravon »

vvaltchev wrote:It is possible to use the host compiler when you target i686, but that's NOT a good idea. And, believe me, adding "-m32 -march=i686" is not really THE problem here at all, as kernel projects require passing a ton of options to the compiler anyway.
My kernel project doesn't.
The first problem when using the host compiler comes when you need to build software (usermode programs) that will run on your kernel, not the kernel itself. That's a problem because very likely your project won't be 100% compatible with Linux and Glibc. The majority of the kernel projects are not compatible with Linux at binary level. But, some of them still offer a POSIX interface with a custom libc implementation. So, now, how you will use the host compiler to build a regular program with a different libc? It's possible with GCC, but it's a great mess. It requires the use of special "GCC scripts" to be passed with the "-specs" option and also compiler-wrapper scripts to have a simpler pseudo-regular compiler interface for the build system. A GCC script will set new include paths for system headers, the object file to use for _start, the default libc to link with and other stuff like that.
The alternative I used is to not try to do everything via the "gcc" command but instead to separate it into its components.

You can see that here:

https://sourceforge.net/p/pdos/gitcode/ ... kefile.p32

That uses my own tools, but the standard GCC that I got with Cygwin works near-identically:

https://sourceforge.net/p/pdos/gitcode/ ... kefile.w32
The second problem is that, if you write a kernel compatible with Linux, your project still won't be 100% compatible with all the modern and advanced syscalls that glibc will use, for years. So, even if you won't need to write a custom libc, you will still need to use lighter libc implementation like libmusl or uclibc-ng to build apps for your kernel. In this case you STILL will need a custom toolchain. I avoided building a custom toolchain myself by using prebuilt libmusl gcc-toolchains from: https://toolchains.bootlin.com/. But, again, that comes at the price of being compatible with Linux at binary level. Most projects here don't do that, by choice.
You only need about 10 syscalls to implement a C library that is good enough to run GCC itself. That is what PDPCLIB gives you. You don't need to change toolchain just to use PDPCLIB.

It seems that people are way over-complicating what is required, and creating a barrier to new people starting. It's not that complicated. The compilers are normally producing perfectly reasonable code. Unless you have a reason to want to change the stack conventions of the compiler you are already using, you can start straight away with your OS and get some immediate feedback. Or you can take PDOS as a whole as a starting point and have a pre-canned starting point. It is public domain so there is no problem using it in your own project, regardless of what copyright you want on it.
The third problem with using the host compiler is that generally it won't work if you want to target anything other than i686. So, if you want to build for AARM64, you will still need to build a custom toolchain or, at least, a linux pre-built toolchain if you're in my case.
Sure. My GCC 3.2.3 also targets S/370, so you need to type in "compile" to build that if you don't want to use the pre-made executables, including the pre-made executables that are available on the S/370 machine itself, so that it's not cross-compiling. The equivalent would be doing your ARM work on a Raspberry Pi instead of an x86 machine.
Ethin
Member
Member
Posts: 625
Joined: Sun Jun 23, 2019 5:36 pm
Location: North Dakota, United States

Re: Use of "-m32 -march=i686" to replace the standard toolch

Post by Ethin »

kerravon wrote:The latest version of my GCC 3.2.3 was released 2021-06-09. I consider it to be the best C compiler available for Windows. It was created for a reason. It is the only thing that actually meets my requirements. It's also the best C compiler available for Freedos, and the best compiler for MVS.
Right. And the original C compiler developed by K&R is the best compiler and everybody should use it.
kerravon wrote:
Linux GCC has always been complicated. Every distribution will compile it differently and will use different flags when building your code. The fact that you have to go all the way back to 3.2.3 if not older, and thereby suffer the fact that your OS will never be able to take advantage of any optimizations or other compiler advancements after 3.2.3 proves that.
No, it doesn't prove that at all. There is probably no barrier to GCC 11.1.0 being as neat and clean as my GCC 3.2.3. Someone just needs to put in the development effort to make it C90-compliant. Every single version of GCC *should* and probably *could* have ben C90-compliant from day one.
Considering that the first version of GCC was released in 1987, that would've been, uh, kinda impossible, since C90 hadn't even been released yet.
keravon wrote:And as for "optimizations", feel free to play "spot the speed difference". Best of luck with that. I'd rather have something that actually works. If you find a way of shaving 1% off the runtime, that's great, even though I can't detect it, but make the package C90-compliant first. Also make it target 80386 first. So that it works on essentially every 32-bit x86 computer since 1986. That's a great start.
The fact that you have to modify your C compiler -- or use a custom version of GCC 3.2.3 that's modified to be C90 compliant -- says a lot about how antequated your toolchain is. Its irrelevant when "your" version of GCC was released; GCC 3.2.3 was released in 2003. A simple google search would reveal this for yourself.
Another nasty problem your going to suffer is compiling your code on more modern compilers. I'm pretty sure that GCC 11 couldn't compile your code. And I haven't even gotten into the other disadvantages of your compiler setup, such as static analysis and the amount of warnings available. And yes, there is a significant difference between how GCC 3.2.3 optimizes code and how GCC 11.1.0 does. Hell, your GCC version might even perform incorrect optimizations that were fixed in later versions of GCC.
Octocontrabass
Member
Member
Posts: 5567
Joined: Mon Mar 25, 2013 7:01 pm

Re: Use of "-m32 -march=i686" to replace the standard toolch

Post by Octocontrabass »

kerravon wrote:And as for "optimizations", feel free to play "spot the speed difference". Best of luck with that.
LTO can make a pretty big difference.
kerravon wrote:Also make it target 80386 first. So that it works on essentially every 32-bit x86 computer since 1986.
Even the latest GCC can still emit binaries that will run on a 386. The trick is finding an OS that doesn't use any x86 features that were added later and doesn't trip over any of the nasty errata in those old CPUs.
Locked