GCC emits mov instead of lea

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
SomePerson
Posts: 7
Joined: Sun Sep 15, 2024 8:05 am
Libera.chat IRC: SomePerson

GCC emits mov instead of lea

Post by SomePerson »

For my IDT I load function pointers into the IDT, but instead of loading the address of the function pointers gcc emits a mov and loads 8 bytes from the function instead. Additionally this works correctly if the function is in the same file.

Example:

Code: Select all

IDT_set_gate(0, ISR0, ...)
Emits:

Code: Select all

mov -0x...(%rip), %rsi
Instead of:

Code: Select all

lea -0x...(%rip), %rsi
But

Code: Select all

IDT_set_gate(0, IDT_initialize, ...)
With IDT_initialize in the same file emits the correct lea.

What is causing this and how can I fix this?
nullplan
Member
Member
Posts: 1733
Joined: Wed Aug 30, 2017 8:24 am

Re: GCC emits mov instead of lea

Post by nullplan »

There's not enough code here to tell what is going on. But I suspect you declare ISR0 with the wrong type in C. Typically, it should be something like

Code: Select all

extern const char ISR0[];
And I suspect you have something like

Code: Select all

extern unsigned long ISR0;
How close am I?
Carpe diem!
SomePerson
Posts: 7
Joined: Sun Sep 15, 2024 8:05 am
Libera.chat IRC: SomePerson

Re: GCC emits mov instead of lea

Post by SomePerson »

ISR0 is a function declared like this:

Code: Select all

void ISR0();
User avatar
iansjack
Member
Member
Posts: 4662
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: GCC emits mov instead of lea

Post by iansjack »

Do you declare ISR0() in the file containing the IDT functions? If not the compiler will assume that ISR0 an int rather than a pointer to a function.
SomePerson
Posts: 7
Joined: Sun Sep 15, 2024 8:05 am
Libera.chat IRC: SomePerson

Re: GCC emits mov instead of lea

Post by SomePerson »

Yes and the same problem also occurs with functions that I can call that are in another file.
User avatar
iansjack
Member
Member
Posts: 4662
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: GCC emits mov instead of lea

Post by iansjack »

I think, as null plan says, that we need to see the code.
SomePerson
Posts: 7
Joined: Sun Sep 15, 2024 8:05 am
Libera.chat IRC: SomePerson

Re: GCC emits mov instead of lea

Post by SomePerson »

isr.c:

Code: Select all

void ISR0();
void ISR1();
void ISR2();
void ISR3();
void ISR4();
...

void ISR_initialize()
{
    IDT_set_gate(0, ISR_initialize, GDT_KCS, 0, 0xf); // "Works"
    //	-> lea -0x1e(%rip), %rsi
    IDT_set_gate(0, ISR0, GDT_KCS, 0, 0xf); // Does not work
    //	-> mov -0x33a(%rip), %rsi
    IDT_set_gate(1, ISR1, GDT_KCS, 0, 0xf);
    IDT_set_gate(2, ISR2, GDT_KCS, 0, 0xf);
    IDT_set_gate(3, ISR3, GDT_KCS, 0, 0xf);
    IDT_set_gate(4, ISR4, GDT_KCS, 0, 0xf);
    ...
}
idt.c:

Code: Select all

void IDT_set_gate(int interrupt, void (*base)(), uint16_t segment, int privilege, int type)
{
    if(interrupt > 255)return;

    idt[interrupt].base_low = ((uintptr_t)base) & 0xffff;
    idt[interrupt].base_mid = (((uintptr_t)base) >> 16) & 0xffff;
    idt[interrupt].base_high = ((uintptr_t)base) >> 32;
    idt[interrupt].segment = segment;
    idt[interrupt].flags = (privilege << 13) | ((type & 0xf) << 8);
    idt[interrupt].flags |= IDT_ENABLE_FLAG;
}
sebihepp
Member
Member
Posts: 177
Joined: Tue Aug 26, 2008 11:24 am
GitHub: https://github.com/sebihepp

Re: GCC emits mov instead of lea

Post by sebihepp »

Try &ISR0 instead of ISR0
SomePerson
Posts: 7
Joined: Sun Sep 15, 2024 8:05 am
Libera.chat IRC: SomePerson

Re: GCC emits mov instead of lea

Post by SomePerson »

1: I tried &ISR0, but it did not work. (Also that should be equivalent to ISR0 anyway)

2: I got around the problem by doing this:

Code: Select all

void (*isrs[])() = {
    ISR0, ISR1, ISR2, ISR3,
    ISR4, ISR5, ISR6, ISR7,
    ISR8, ISR9, ISR10, ISR11,
    ISR12, ISR13, ISR14, ISR15,
    ISR16, ISR17, ISR18, ISR19,
    ISR20, ISR21, ISR22, ISR23,
    ISR24, ISR25, ISR26, ISR27,
    ISR28, ISR29, ISR30, ISR31,
    ISR32, ISR33, ISR34, ISR35,
    ISR36, ISR37, ISR38, ISR39,
    ISR40, ISR41, ISR42, ISR43,
    ISR44, ISR45, ISR46, ISR47,
};
and then calling IDT_set_gate like this:

Code: Select all

IDT_set_gate(0, isrs[0], GDT_KCS, 0, 0xf);
Octocontrabass
Member
Member
Posts: 5418
Joined: Mon Mar 25, 2013 7:01 pm

Re: GCC emits mov instead of lea

Post by Octocontrabass »

How are you compiling and linking this code? That looks a bit like a PIC relocation that didn't get linked correctly.
SomePerson
Posts: 7
Joined: Sun Sep 15, 2024 8:05 am
Libera.chat IRC: SomePerson

Re: GCC emits mov instead of lea

Post by SomePerson »

Compiling:
gcc -Wall -Wextra -O3 -ffreestanding -nostdlib -c $< -o $@
Linking:
gcc -Tx86_64.ld -nostdlib $^ -lgcc -o $@
x86_64.ld:

Code: Select all

KERNEL_PM = 0x100000
KERNEL_VM = 0xffff800000100000
KERNEL_VM_OFFSET = KERNEL_VM - KERNEL_PM

ENTRY(k32_entry)
OUTPUT_FORMAT("binary")
SECTIONS
{
	. = KERNEL_PM;
	... k32 stuff
	. = ALIGN(4096);
	. += KERNEL_VM_OFFSET;
	.text : AT(ADDR(.text) - KERNEL_VM_OFFSET) {...}
	+ other sections
	+ discards
}
Also I am having the same problem again with an array (loads first 8 bytes instead of pointer).
Octocontrabass
Member
Member
Posts: 5418
Joined: Mon Mar 25, 2013 7:01 pm

Re: GCC emits mov instead of lea

Post by Octocontrabass »

SomePerson wrote: Sun Sep 15, 2024 3:33 pmgcc -Wall -Wextra -O3 -ffreestanding -nostdlib -c $< -o $@
You should use a cross-compiler. Since you're not using a cross-compiler, you get whatever default options the package maintainers decided to use when they built your copy of GCC, and I'd guess they decided to enable PIC by default. I'm not sure why your resulting binary isn't statically linked correctly, but disabling PIC (-fno-pic) will fix that. If you disable PIC you'll also need to specify the code model according to the address where your kernel is linked. The current address you're using requires the large code model (-mcmodel=large), but if you change it to 0xFFFFFFFF80000000 or higher, you can use the kernel code model (-mcmodel=kernel).

You also need to disable the red zone (-mno-red-zone), and you probably want to disable the use of extended registers (-mgeneral-regs-only).
SomePerson
Posts: 7
Joined: Sun Sep 15, 2024 8:05 am
Libera.chat IRC: SomePerson

Re: GCC emits mov instead of lea

Post by SomePerson »

Thank you.
Post Reply