Page 1 of 1

64bit variable in x86 mode, possible? [SOLVED]

Posted: Tue Mar 22, 2016 10:35 am
by ashishkumar4
Ibam Making a x86 OS with an x86 gcc compiler. Was developing my own FileSystem (no name given to it, its not fat or anything like that). Now the problem is, until now (before I stumbled on FS), I only required uint32_t provided by GCC. But now (as you might guess) the problem is, I am required to work with secondary storage media (SATA for now) which are generally more then 4GB. That means I require 64 bit addressing. Now there are several possible alternatives (thought of many) for this but I would like to use something like uint64_t just for simplicity sake. Now GCC 32bit provides a working uint64_t but as the compiler I compiled was 32 bits, even still I cant manage numbers more then 4*1024*1024*1024 :/ and that's the trouble. I have some alternatives for this like using 2 uint32_t vars(array) or using uint64_t itself by bit shifting (it still takes 8bytes space on RAM, checked it). But in either case, things like dividing the number by say size of sectors (512) would become a bit complicated and given my FileSystem is already so complicated, would only slow the performance if I don't do things the right way. further it would be an invitations for several bugs and flaws by even a single mistake; It would simply be too cumbersome. Now as a lazy person, I need a way to use 64 bit variables in GCC 32 bit compiler, manipulating as a unit. If I had one, I can just use it to address some location on the hard disk say above 4GB, and then get the data at that location by using my already working AHCI SATA drivers (with the read write functions provided by the wiki, just more abstracted away; I would just need to pass lower 32bits to appropriate places in the command table and higher bits to respective places)

Please help me, you see that now I am lazy + dumb :3

NOTE: I have completed my FileSystem (mostly, just the permissions things remain though already supported). But as you see, It only works with <4GB drives. Help

Re: 64bit variable in x86 mode, possible?

Posted: Tue Mar 22, 2016 11:20 am
by Octocontrabass
Even 32-bit GCC is capable of generating functional code with 64-bit variables, using uint64_t and int64_t. If it's not working properly, it means you're doing something wrong, such as performing arithmetic between two 32-bit values and storing the result (which is truncated to 32-bits) into a 64-bit variable.

Re: 64bit variable in x86 mode, possible?

Posted: Tue Mar 22, 2016 3:13 pm
by azblue
Like Octo said, the compiler can handle it. For example, if you did x = y + z (all 64 bit ints), the compiler might do something like:

Code: Select all

mov eax, [y.lower32]
mov ebx, [y.upper32]
add eax, [z.lower32]
adc ebx, [z.upper32]
mov [x.lower32], eax
mov [x.upper32], ebx
For division things get more complicated, just as you said, but you don't have to worry about it; the compiler will figure it all out.

Re: 64bit variable in x86 mode, possible?

Posted: Tue Mar 22, 2016 10:36 pm
by ashishkumar4
:/ ok sorry, I got it. It worked earlier too but the problem was my printf wont print it. But now I am having this problem: Though I can get the upper 32bits and lower 32bits easily (and print them too for testing); I still can just divide them by say 512 and get the lower 32bits and put them somewhere and the upper 32bits and put them somewhere; like:

uint64_t abc=0xffffffffffff; //random number :P
printf("\n%x %x",(abc>>32),(abc & 0xffffffff); //This works, prints equivalent decimal for 0xffff and 0xffffffff
uint32_t a=(uint32_t)abc/1000000000;
printint(a);

This gives error on linking that "__udivdi3" :/ help me

Re: 64bit variable in x86 mode, possible?

Posted: Wed Mar 23, 2016 12:13 am
by alexfru
ashishkumar4 wrote: This gives error on linking that "__udivdi3" :/ help me
http://llvm.org/svn/llvm-project/compil ... /udivdi3.c
or
https://sourceware.org/git/?p=glibc.git ... .c;hb=HEAD

Re: 64bit variable in x86 mode, possible?

Posted: Wed Mar 23, 2016 12:25 am
by Octocontrabass
That error means you aren't linking libgcc (which contains __udivdi3) against your code. It can also be an indication of other problems, such as not using a cross-compiler.

Re: 64bit variable in x86 mode, possible?

Posted: Thu Mar 24, 2016 11:12 am
by kzinti
This has nothing to do with having a cross compiler or not. You will get that even with a cross compiler if you don't link with standard libraries, which is implied with "-ffreestanding".

You need to explictly link with libgcc in this case, as it contains 64 bits integer arithmetic functions such as __udivdi3.

Now just using -lgcc probably won't work with "-ffreestanding" as the system library search path won't be set. What I do is find where libgcc is (using gcc!) and then add the full path to the linker. From my makefile:

Code: Select all

libgcc_path := $(shell $(CC) -print-file-name=libgcc.a)

kernel.elf: $(OBJECTS)
	$(LD) $(LDFLAGS) $(OBJECTS) $(libgcc_path) -o $@
Where CC is gcc and LD is ld.

Re: 64bit variable in x86 mode, possible?

Posted: Thu Mar 24, 2016 2:18 pm
by onlyonemac
I used a uint64_t with 32-bit gcc and no libgcc (on the other hand, I explicitly told it not to use libgcc). This is my compiler command line:

Code: Select all

gcc -ffreestanding -fno-builtin -nostdlib -nostdinc -m32 -Wl,-Bstatic -Wall -c kernel/main.c -o kernel/main.o

Re: 64bit variable in x86 mode, possible?

Posted: Thu Mar 24, 2016 4:41 pm
by Octocontrabass
If gcc doesn't emit any references to libgcc, you won't have any errors from not linking libgcc. However, gcc can emit those references whenever it wants, so it's better to do things right from the beginning. You'll just end up fighting with it otherwise.

Same goes for not using a cross compiler.

Re: 64bit variable in x86 mode, possible?

Posted: Thu Mar 24, 2016 10:43 pm
by ashishkumar4
Ah thanks everyone, Everything is now working as I wanted, the filesystem now supports 64bit addressing (probably, the true test would be conducted when the FS is completed in as what I call "The Stage 3 of FS dev" ). The only thing I did to make everything fit was to just use arithmatics on 64bit vars with 64bit vars and storing them in 64bit vars only. Means,

instead of
uint32_t abc=bc/512; //where bc is uint64_t var with possible value >4*1024*1024*1024

I just always do
uint64_t abc=bc/512; //It works well, no bugs till now
and just pass this 'abc' which in this case I would use as addressing for sectors to my read or write-to-sata drive functions which are just diferent versions of my general 'sata commander' function which itself does the task to separate the 64 bit value to upper 32 and lower 32 bits.
Thanks everyone :)

EDIT: I still don't have 100% confidence on this as I haven't tested writing more then 4GB data on any hard disk

Re: 64bit variable in x86 mode, possible?

Posted: Fri Mar 25, 2016 7:18 am
by jnc100
kiznit wrote:This has nothing to do with having a cross compiler or not. You will get that even with a cross compiler if you don't link with standard libraries, which is implied with "-ffreestanding".
Not quite. libgcc is not included if you either 1) use ld to link (instead of driving it through gcc) or 2) use gcc to link but pass the -nostdlib or -nodefaultlibs options to it. -ffreestanding is a compiler option (i.e. only affecting the translation of source code to object code, rather than the link itself) that tells gcc to make certain defines and not others, and only support a few default headers (see e.g. C Library).

The recommended way to compile and link is something like:

Code: Select all

; Compile
i686-elf-gcc -ffreestanding -mno-mmx (insert other -mno-cpu-features here) -c -o main.o main.c

; Link
i686-elf-gcc -nostdlib -T linker.ld -o kernel.elf main.o -lgcc
which should accomplish what you want without having to resort to such Makefile trickery.
onlyonemac wrote:I used a uint64_t with 32-bit gcc and no libgcc
Whilst this may have worked in your particular use case, the moment you start using functionality that cannot easily be expressed in simple machine operations, gcc will start to emit calls to libgcc and your build may break at any time (even with the same code and different compiler versions). To quote libgcc: All code compiled with gcc must be linked with libgcc.

Specifically for 64-bit integer support on 32-bit platforms, gcc is quite clever and will avoid libgcc calls if at all possible. Examples where it is not called include addition and subtraction (add/adc and sub/sbb are used instead), single-bit shifts (using shifts via CF) and simple power-of-two multiplications and divides (where shifts are used). It is when you start doing more complex stuff that libgcc gets used. On other platforms that don't support any form of interger divide (even word size) such as certain ARM platforms, libgcc is even more heavily relied upon.

Regards,
John.