flat assembler
Message board for the users of flat assembler.

Index > OS Construction > switching to long mode

Author
Thread Post new topic Reply to topic
tejuwala



Joined: 14 May 2008
Posts: 9
Location: Sunnyvale
tejuwala 14 May 2008, 18:42
Hello,

I'm working on a 32-bit BIOS code and as further development I want to test 64-bit CPU in the BIOS. I cannot recompile my BIOS in 32-bit mode due to compatibility reasons and I am trying to compile 64-bit tests (in both C and assembly) in the rest of 32-bit BIOS.

Currently, I've written a 64-bit test in assembly file. I compile it using 64-bit nasm assembler and use the binary file to generate hex-code. I use this hex-code (char hexcode[] = "") in my 32-bit file and run it as function pointer. This seems not to be working so far.

I couldn't find a way to link elf32 and elf64 files together and the way I'm doing it right now allows me to avoid any linking between the two.

Can somebody please help me with this?

Thanks,
/tejas
Post 14 May 2008, 18:42
View user's profile Send private message Yahoo Messenger Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 14 May 2008, 19:35
With fasm you could use the file directive to include the 32-bit plain binary in your 64-bit ELF object/executable.

Example:

a32BitBin.asm
Code:
use32
org $123456 ; Change with the address you think it will work or write position independent code below

add_64: ; EAX:EDX + EBX:ECX
  add eax, ecx
  adc edx, ebx
  ret
    


Then:
Code:
format ELF64
section '.text' executable
.
.
.

binary:
  file 'a32BitBin.bin'
sizeof.binary = $ - binary
    


Of course you must take the proper actions to make the 32-bit code work because doing "call binary" from 64-bit wouldn't produce any reliable result...
Post 14 May 2008, 19:35
View user's profile Send private message Reply with quote
tejuwala



Joined: 14 May 2008
Posts: 9
Location: Sunnyvale
tejuwala 14 May 2008, 23:35
LocoDelAssembly wrote:
With fasm you could use the file directive to include the 32-bit plain binary in your 64-bit ELF object/executable.

Example:

a32BitBin.asm
Code:
use32
org $123456 ; Change with the address you think it will work or write position independent code below

add_64: ; EAX:EDX + EBX:ECX
  add eax, ecx
  adc edx, ebx
  ret
    


Then:
Code:
format ELF64
section '.text' executable
.
.
.

binary:
  file 'a32BitBin.bin'
sizeof.binary = $ - binary
    


Of course you must take the proper actions to make the 32-bit code work because doing "call binary" from 64-bit wouldn't produce any reliable result...


My apologies. My code is 32-bit and I cannot re-compile it in _64-bit_ mode. I know, if I had 64-bit elf then putting "bits 32" (nasm) wouldn't be a problem.

In other words, I have to call 64-bit code from a 32-bit code. How can you do that? How can you link 64-bit code with 32-bit code?

/tejas
Post 14 May 2008, 23:35
View user's profile Send private message Yahoo Messenger Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 15 May 2008, 02:30
Linking different bit wide sizes is supposed to be generally imposible, but you could still apply what I've said but swapping the bit widths. At least fasm does support generation of plain 64-bit binaries that later you can include with "file" directive (and the linker will not complain because the file data is seen as a byte array without relocations).

The full procedure would be something like this:

binary.asm:
Code:
use64
add_64: ; RAX + RDX
  add rax, rdx
  ret
    


object.asm:
Code:
format ELF64 
section '.text' executable 
. 
. 
. 

binary: 
  file 'Binary.bin' 
sizeof.binary = $ - binary 
    


Code:
fasm binary.asm
fasm object.asm
    

Now you should be ready to link. Again, the binary must be position independent code or you must know before hand its memory location at run-time and specify it with org directive. Fortunatelly 64-bit code is a lot easier to make it PIC due to the RIP-relative addressing mode.

This is just the way I would resolve this problem but it doesn't means that it is the unique and best way. Anyone has better ideas?

[edit]BTW, the add_64 label is just informative since its scope is only within binary.asm, object.asm nor the linker will be aware of such label, your only way to reference the binary chunk is by referencing through binary label to binary+sizeof.binary. If you have an small fragment of both, you 64-bit and 32-bit parts perhaps we can hint you better on a solution.[/edit]
Post 15 May 2008, 02:30
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4047
Location: vpcmpistri
bitRAKE 15 May 2008, 03:03
Honestly, I'm not completely understanding the problem, but FASM has no limitations with encoding:
Code:
mov al,1

use32

mov eax,1

use64

mov rax,1    
...there isn't a need to split them into separate files. FASM starts in 16 bit mode (like the processor) and can be switched at will to the desired encoding method.

Calling one type of code from another is a programing problem and not a problem with using the assembler. Is this what you are asking - How to call 64-bit code from 32-bit code? Might want to call a 32-bit stub which does the far call to the 64-bit code (assuming a valid 64-bit code selector has been setup). Making a far call in C would be compiler specific, imho.

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 15 May 2008, 03:03
View user's profile Send private message Visit poster's website Reply with quote
tejuwala



Joined: 14 May 2008
Posts: 9
Location: Sunnyvale
tejuwala 15 May 2008, 18:15
bitRAKE wrote:
Calling one type of code from another is a programing problem and not a problem with using the assembler. Is this what you are asking - How to call 64-bit code from 32-bit code? Might want to call a 32-bit stub which does the far call to the 64-bit code (assuming a valid 64-bit code selector has been setup).


Technically, what you are saying is mentioned in Intel document under "Initializing IA-32e Mode". My problem is, I'm running a 32-bit C code in 32 bit mode and just to test 64-bit CPU, I want to switch to 64-bit mode, run some 64-bit code (for now, you can assume I just want to print a char) _and_ switch back to 32-bit mode and resume executing 32-bit C code.

bitRAKE wrote:
Making a far call in C would be compiler specific, imho.

I am not sure what you are implying here. Can you please explain?

The way it looks in program is:
1) 32-bit C program running in 32-bit mode,
2) 32-bit wrapper function is called that does switching to long mode (still in 32-bit mode) and makes far jump to 64-bit code (either C or assembly code); now processor is in 64-bit mode
3) 64-bit (either C or an assembly) code runs in 64-bit mode
4) the 64-bit code switches the processor back to 32-bit mode
5) 32-bit C programs resumes in 32-bit mode.

Now problem here is, I want to do all 5 steps in C program (I'd use inline assembly if need be). Problem with that is, you can't link 32-bit ELF with 64-bit ELF.

Using assembly (for steps, 2,3 and 4. step 1 and 5 are still in C), I can compile all 16,32 and 64 bit code all together to produce binary. Now, unless I use linker script and put that binary code somewhere in memory and just jump to location, its useless; Thats something I don't want to do. Instead, I am getting hexcode out of binary (e.g. char hexcode[] = "\xc3"), type casting it to a function pointer and calling that function from C file, which seems not to be working yet.

When you say making far call in C, how do you jump to a 64-bit code from 32-bit code in C?

/tejas
Post 15 May 2008, 18:15
View user's profile Send private message Yahoo Messenger Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4047
Location: vpcmpistri
bitRAKE 16 May 2008, 01:35
tejuwala wrote:
bitRAKE wrote:
Making a far call in C would be compiler specific, imho.
I am not sure what you are implying here. Can you please explain?
When I used C - several years ago - far calls were always compiler-dependent extensions. I have no idea if anything has changed since - that is not likely in my opinion.
tejuwala wrote:
Now, unless I use linker script and put that binary code somewhere in memory and just jump to location, its useless; Thats something I don't want to do. Instead, I am getting hexcode out of binary (e.g. char hexcode[] = "\xc3"), type casting it to a function pointer and calling that function from C file, which seems not to be working yet.
I think LocoDelAssembly answered this. If you are accessing memory within the cast function how are you insuring the pointers are fixed (relocated) to their actual address? High bet is on bad pointer - the transition from 16-bit to 32-bit has people hitting the same hurdle.
tejuwala wrote:
When you say making far call in C, how do you jump to a 64-bit code from 32-bit code in C?
I'm not a C programmer, but would look at 64-bit linux kernel to see how they do it (if I was attempting to hack something together using gcc). If it's possible to do without assembly then they would do it, imho.

Any chance you can post the cast function code?

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 16 May 2008, 01:35
View user's profile Send private message Visit poster's website Reply with quote
tejuwala



Joined: 14 May 2008
Posts: 9
Location: Sunnyvale
tejuwala 16 May 2008, 02:55
bitRake wrote:
If you are accessing memory within the cast function how are you insuring the pointers are fixed (relocated) to their actual address? High bet is on bad pointer - the transition from 16-bit to 32-bit has people hitting the same hurdle.


I make sure that the whole code is position independent. I'm following techniques that is used to write shellcode. (http://www.safemode.org/files/zillion/shellcode/doc/Writing_shellcode.html)

bitRake wrote:
I'm not a C programmer, but would look at 64-bit linux kernel to see how they do it (if I was attempting to hack something together using gcc). If it's possible to do without assembly then they would do it, imho.


If you are trying to compile kernel for 64-bit, then gcc and binutils that you are going to use is also gonna be 64-bit and once you compile all the files in 64-bit ELF files you can always create a binary using linker script. In my case, I've only one 64-bit file that needs to be linked in with rest of the 32-bit code(elf32) that was compiled using 32-bit gcc. So that's difference between Linux and my program.


bitRake wrote:
Any chance you can post the cast function code?

Code:
char shellcode[] =  "\xba\xf8\x03\x00\x00";  // this is arbitrary code
void (*fptr)(void);        
fptr = (void (*)(void)) shellcode;
(*fptr)();
    
Post 16 May 2008, 02:55
View user's profile Send private message Yahoo Messenger Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
f0dder 16 May 2008, 04:01
You're compiling your BIOS .c module to elf32? FASM supports elf32, right? So, write your test code with fasm, assemble elf32, and enjoy the use32/use64. Forget about inline assembly and FAR calls from C code, instead call a (near) routine in the .asm module that does the gory stuff that assembly does so well Smile

This is easier to work with than trying to encode stuff as shellcode, since you can have the linker do a lot of the dirty work. You probably won't be able to reference symbols directly from the 64-bit part, though.
Post 16 May 2008, 04:01
View user's profile Send private message Visit poster's website Reply with quote
tejuwala



Joined: 14 May 2008
Posts: 9
Location: Sunnyvale
tejuwala 19 May 2008, 22:11
f0dder wrote:
You're compiling your BIOS .c module to elf32? FASM supports elf32, right?

So as an output we have elf32 object file from .C file

f0dder wrote:
So, write your test code with fasm, assemble elf32, and enjoy the use32/use64.

If you use use64 and compile it with FASM, the o/p file is either gonna be a binary file or elf64 object file based on what you choose. How do you propose to assemble elf32 object file (from .C file) with elf64 file from test code?

f0dder wrote:
This is easier to work with than trying to encode stuff as shellcode, since you can have the linker do a lot of the dirty work. You probably won't be able to reference symbols directly from the 64-bit part, though.

I don't need to refer any symbol in 64-bit code. It is independent code and it does what it does and jumps back to 32-bit mode. I will _not_ call anything in 64-bit code as I'm not planning to _run_ cpu in 64-bit mode; I just want t o _test_ 64-bit mode from my BIOS.
Post 19 May 2008, 22:11
View user's profile Send private message Yahoo Messenger Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
f0dder 19 May 2008, 22:51
tejuwala wrote:
f0dder wrote:
So, write your test code with fasm, assemble elf32, and enjoy the use32/use64.

If you use use64 and compile it with FASM, the o/p file is either gonna be a binary file or elf64 object file based on what you choose. How do you propose to assemble elf32 object file (from .C file) with elf64 file from test code?
Start with elf32/use32... for the blob that needs to be 64bit code, switch to use64 - should be possible as long as you don't need to refer to any symbols.

_________________
Image - carpe noctem
Post 19 May 2008, 22:51
View user's profile Send private message Visit poster's website Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 19 May 2008, 23:52
yup... that's what I love about FASM. Only other option to allow this i know is INCBIN or some GNU linker script... both quite more ugly for proof-of-concept demos.
Post 19 May 2008, 23:52
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
tejuwala



Joined: 14 May 2008
Posts: 9
Location: Sunnyvale
tejuwala 20 May 2008, 18:15
f0dder wrote:
tejuwala wrote:
f0dder wrote:
So, write your test code with fasm, assemble elf32, and enjoy the use32/use64.

If you use use64 and compile it with FASM, the o/p file is either gonna be a binary file or elf64 object file based on what you choose. How do you propose to assemble elf32 object file (from .C file) with elf64 file from test code?
Start with elf32/use32... for the blob that needs to be 64bit code, switch to use64 - should be possible as long as you don't need to refer to any symbols.


I'm not sure if I understood it right; probably because I used the wrong word earlier. My problem is to _LINK_ (and not assemble) an elf32 and elf64 file together.

I have no problems having "USE32" and "USE64" together in one file as it is standard procedure and not a hack to switch to 64-bit mode.

Here is one liner question: I'm running a C program (BIOS) in protected mode (\w paging disabled) on a 64-bit CPU. For sake of testing, I want to switch to 64-bit mode, print a character and return to 32-bit mode. I _CANNOT_ recompile the whole C program to be elf64. So I have to find a way to link 64-bit code (that does transition from 32-bit to 64-bit code and 64-bit char-printing code) with 32-bit code. Any suggestions?

/tejas
Post 20 May 2008, 18:15
View user's profile Send private message Yahoo Messenger Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
f0dder 20 May 2008, 22:46
tejuwala: we already answered you - keep both the C and the ASM modules as elf32, but add "use64" for the 64bit part in the 32bit ASM module... should, (as also mentioned previously) as long as the 64bit portion doesn't need any symbol references.
Post 20 May 2008, 22:46
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.