Read a C variable from inline assembly.

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.
Post Reply
User avatar
Roman
Member
Member
Posts: 568
Joined: Thu Mar 27, 2014 3:57 am
Location: Moscow, Russia
Contact:

Read a C variable from inline assembly.

Post by Roman »

What should I put instead of (something) to read the function arguments and write a byte to a given port?

Code: Select all

void sendByteToPort(int port, int byte)
{
        asm("out (something)");
}
Also, why does dumpCPUControlRegisters() cause triple fault?

From cpu.h:

Code: Select all

int dumpCPUControlRegisters()
{
        asm("mov eax, cr0");
        register int controlRegister0Dump asm("eax");

        asm("mov eax, cr1");
        register int controlRegister1Dump asm("eax");

        asm("mov eax, cr2");
        register int controlRegister2Dump asm("eax");

        asm("mov eax, cr3");
        register int controlRegister3Dump asm("eax");

        asm("mov eax, cr4");
        register int controlRegister4Dump asm("eax");

        return controlRegister0Dump, controlRegister1Dump, controlRegister2Dump, controlRegister3Dump, controlRegister4Dump;
}
From panic.h:

Code: Select all

printf("CR0: %d\n CR1: %d\n CR2: %d\n CR3: %d\n CR4: %d\n", dumpCPUControlRegisters());
"If you don't fail at least 90 percent of the time, you're not aiming high enough."
- Alan Kay
User avatar
Bender
Member
Member
Posts: 449
Joined: Wed Aug 21, 2013 3:53 am
Libera.chat IRC: bender|
Location: Asia, Singapore

Re: Read a C variable from inline assembly.

Post by Bender »

In C the arguments are pushed onto the stack, EBP must be used for deriving stuff from stack. GCC has it's compiler specific mechanism to do that in the "other" way. If you want to use EBP then Something like:

Code: Select all

void crap(uint32_t arg1, uint32_ arg2)
To derive arg1 and arg2 into EAX and EBX respectively this code snippet should be able to do that:

Code: Select all

void crap(uint32_t arg1, uint32_t arg2)
/* My AT&T assembly sucks */
{
asm("mov eax, [ebp + 8]) --- First 4 bytes are the return address, sizeof(uint32_t) = 4
asm("mov ebx, [ebp + 12]) --- EBX Now equals arg2
}
Remember to restore all GPRs (with the exception of EAX) before returning!
Similarly if you want to make an assembly function return a value then you should:
If it's a 8-bit value use AL.
If it's a 16-bit value use AX.
If it's a 32-bit value use EAX.
....
Something else? Pass the pointer to that in the accumulator. (N/AX) I suggest reading the inline assembler examples: http://wiki.osdev.org/Inline_Assembly I recommend reading this too: http://courses.engr.illinois.edu/ece390 ... ixing.html
However inline assembler isn't what I'll personally recommend, it's very compiler specific. I suggest writing those functions in assembly and use the EXTERN keyword provided by most compilers.
"In a time of universal deceit - telling the truth is a revolutionary act." -- George Orwell
(R3X Runtime VM)(CHIP8 Interpreter OS)
User avatar
Roman
Member
Member
Posts: 568
Joined: Thu Mar 27, 2014 3:57 am
Location: Moscow, Russia
Contact:

Re: Read a C variable from inline assembly.

Post by Roman »

Bender wrote:In C the arguments are pushed onto the stack, EBP must be used for deriving stuff from stack. GCC has it's compiler specific mechanism to do that in the "other" way. If you want to use EBP then Something like:

Code: Select all

void crap(uint32_t arg1, uint32_ arg2)
To derive arg1 and arg2 into EAX and EBX respectively this code snippet should be able to do that:

Code: Select all

void crap(uint32_t arg1, uint32_t arg2)
/* My AT&T assembly sucks */
{
asm("mov eax, [ebp + 8]) --- First 4 bytes are the return address, sizeof(uint32_t) = 4
asm("mov ebx, [ebp + 12]) --- EBX Now equals arg2
}
Remember to restore all GPRs (with the exception of EAX) before returning!
Similarly if you want to make an assembly function return a value then you should:
If it's a 8-bit value use AL.
If it's a 16-bit value use AX.
If it's a 32-bit value use EAX.
....
Something else? Pass the pointer to that in the accumulator. (N/AX) I suggest reading the inline assembler examples: http://wiki.osdev.org/Inline_Assembly I recommend reading this too: http://courses.engr.illinois.edu/ece390 ... ixing.html
However inline assembler isn't what I'll personally recommend, it's very compiler specific. I suggest writing those functions in assembly and use the EXTERN keyword provided by most compilers.
Thanks.
"If you don't fail at least 90 percent of the time, you're not aiming high enough."
- Alan Kay
User avatar
qw
Member
Member
Posts: 792
Joined: Mon Jan 26, 2009 2:48 am

Re: Read a C variable from inline assembly.

Post by qw »

Read up on inline assembly. There's an article on the Wiki, and it is explained fairly well in the GCC manual.

BTW You should read up on C too. A function cannot return five values at once.
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Read a C variable from inline assembly.

Post by iansjack »

In C the arguments are pushed onto the stack
That's a big assumption which may or may not be justified. It's certainly not true for my 64-bit OS.

It is never safe to make generalized assumptions.
User avatar
sortie
Member
Member
Posts: 931
Joined: Wed Mar 21, 2012 3:01 pm
Libera.chat IRC: sortie

Re: Read a C variable from inline assembly.

Post by sortie »

NO.

Do not write inline assembly like the manners suggested so far, especially by Bender!

First of all search the wiki and read the article: http://wiki.osdev.org/Inline_Assembly

Second, reuse existing inline assembly from the wiki that has been peer-reviewed and verified as safe (hopefully): http://wiki.osdev.org/Inline_Assembly/Examples

Third, learn the C programming language. Your example code looks truly badly written by someone that doesn't know it. Don't expect to succeed at this, especially not at inline assembly, until you know your tools well. I'm not even sure all of the registers you used actually exist.

Fourth, inline assemby should be treated as extremely dangerous and fragile. You must be an expert in inline assembly to do it reliably and precisely. It is a very powerful tool that lets you cooperate with the compiler code generation and you can achieve very good results if you do your job well. However, if you lie to the compiler in any way, the optimizer can do truly horrific things to your inline assembly that seems perfectly reasonable to the compiler. The compiler does look look at your inline assembly at all except to substitute registers and makes no attempt to understand it.

Fifth, the inline assembly uses AT&T syntax (same as the GNU assembler) as preprocessed by GCC. You need to prefix registers with % (double %% actually if you really don't want to use virtual registers) and use the correct operand order. You can change this using particular gcc options, but that is obviously really bad style.

Sixth, the function stack frame and register are the property of the compiler. Do not assume that particular registers contain particular values in your inline assembly unless you told the compiler to do so in your input list. Do not assume that the local stack frame has a particular layout and that you can access variables without them being in the input list. Do not assume you can sneak values in particular registers behind the back of the compiler between inline assembly statements. Unite them if needed.

Seventh, read carefully what Bender wrote and remember that it is is unsafe bullshit. He uses ABI knowledge but forgets the existence of the compiler and optimizer and that C is not a high-level assembler. Do not trust and thank people that appear to know what they are talking about when they obviously don't.

Eigth, don't do inline assembly. It's for experts only, and I mean experts that really read the GCC documentation (that is unfortunately hard to find good information on inline assembly for i386 in) and carefully verified its correctness. Use a normal assembly file instead.

Nineth, use compiler builtins and compiler headers or extensions instead. Unlike inline assembly, the compiler understands those at a much deeper level and can do some truly amazing optimizations.

Tenth, don't use inline assembly for the sake of performance. You can usually write normal C that does the job just as well and that future compilers can optimize really well.

Eleventh, the inline assembly isn't correct just because it happens to work. You may not have triggered the optimization case where your lies cause trouble. You should carefully verify you told the compiler the truth.

Finally. Be careful and safe. You can make some really useful constructions with inline assembly, but it is a tool that easily backfires and you can construct horrificly ugly hacks using them that didn't need to exist in the first place. Be careful who you trust. Learn C. Cooperate with your compiler.

See also the System V ABI specifics if you are using a i686-elf cross-compiler: http://wiki.osdev.org/System_V_ABI

- Your local committee for prevention of compiler crime.
AbstractYouShudNow
Member
Member
Posts: 92
Joined: Tue Aug 14, 2012 8:51 am

Re: Read a C variable from inline assembly.

Post by AbstractYouShudNow »

Additionally, your second function does not work because in gcc, inline assembly uses at&t syntax, in which the order of registers is different from the Intel syntax that nasm uses. Hence, when you write

Code: Select all

mov %eax, %cr0
then this means "move the value of eax to cr0" while it seems that you want to do the opposite.
User avatar
sortie
Member
Member
Posts: 931
Joined: Wed Mar 21, 2012 3:01 pm
Libera.chat IRC: sortie

Re: Read a C variable from inline assembly.

Post by sortie »

AbstractYouShudNow: Yes, except inline assembly in functions doesn't use AT&T syntax, but AT&T syntax as preprocessed by GCC with register substitution.
User avatar
Bender
Member
Member
Posts: 449
Joined: Wed Aug 21, 2013 3:53 am
Libera.chat IRC: bender|
Location: Asia, Singapore

Re: Read a C variable from inline assembly.

Post by Bender »

sortie wrote:Do not write inline assembly like the manners suggested so far, especially by Bender!
Yea, using GCC's inline assembly features is better, and also because I never use inline assembler.
Seventh, read carefully what Bender wrote and remember that it is is unsafe bullshit. He uses ABI knowledge but forgets the existence of the compiler and optimizer and that C is not a high-level assembler. Do not trust and thank people that appear to know what they are talking about when they obviously don't.
:)
That's a big assumption which may or may not be justified. It's certainly not true for my 64-bit OS.

It is never safe to make generalized assumptions.
Though I should agree to that, but additional arguments are still pushed on stack. :)
"In a time of universal deceit - telling the truth is a revolutionary act." -- George Orwell
(R3X Runtime VM)(CHIP8 Interpreter OS)
AbstractYouShudNow
Member
Member
Posts: 92
Joined: Tue Aug 14, 2012 8:51 am

Re: Read a C variable from inline assembly.

Post by AbstractYouShudNow »

sortie: maybe should-I have doubled the %'s then. Not like he should use %0 and corresponding stuff anyways :)
User avatar
iansjack
Member
Member
Posts: 4711
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Read a C variable from inline assembly.

Post by iansjack »

Bender wrote:
sortie wrote:Do not write inline assembly like the manners suggested so far, especially by Bender!
Yea, using GCC's inline assembly features is better, and also because I never use inline assembler.
Seventh, read carefully what Bender wrote and remember that it is is unsafe bullshit. He uses ABI knowledge but forgets the existence of the compiler and optimizer and that C is not a high-level assembler. Do not trust and thank people that appear to know what they are talking about when they obviously don't.
:)
That's a big assumption which may or may not be justified. It's certainly not true for my 64-bit OS.

It is never safe to make generalized assumptions.
Though I should agree to that, but additional arguments are still pushed on stack. :)
When you're in a hole it's best to stop digging. Just accept that you gave all-round, terrible advice and leave it at that.
Post Reply