Page 1 of 1

C code and Linkier script: calculate jump locations

Posted: Wed Nov 07, 2018 10:25 am
by nintyfan
I have a problem, with I resolve in simple way. The problem was I creating my own kernel, which cannot use multi cores, etc. It handles modules. Modules is a binary blob loaded by Grub2 bootloader. Because I don't know the exactly address module is loaded, I use variable at fixed address. In both kernel and module address I use extern directive to have access to this variable and write linker script to put this variable into specific place of memory. Before accessing module code, I simply set these variable to beginning of my module in memory.

Only modules without forks works. I cannot use jumps, so if, while, do... while, for and goto isn't usable. Either I cannot use function call in my module code.

Question is: How to tell linker or compiler to calculate each jump by value placed in some place of memory?

Re: C code and Linkier script: calculate jump locations

Posted: Wed Nov 07, 2018 11:16 am
by Solar
What you are looking for is "position independent code" (PIC).

Re: C code and Linkier script: calculate jump locations

Posted: Wed Nov 07, 2018 1:18 pm
by nintyfan
Thank you.

I created shared objects previously for GNU/Linux, but I don't know how to use this flag, when programming an kernel. How to use this flag with conjunction giving address to read start of my kernel module?

That's a my linker script:

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY("init")
PROVIDE(__module_load_addr = 0x1000);
SECTIONS {
  . = 0;
  .text : {
    *(.text)
  }
  
  .rodata : {
    *(.rodata)
  }
  
  .data  : {
    *(.data)
  }
  
  .bss : {
    *(.bss)
  }

}

Module_load_addr is a void * to variable keeping address whereas my kernel module is loaded.
So the format is binary, not elf. It is possible to change this linker script without changing output format? My OS will probably support elf in future, but in another time.

Re: C code and Linkier script: calculate jump locations

Posted: Wed Nov 07, 2018 11:07 pm
by nullplan
You should probably investigate why loops and conditionals don't work right now. Because those typically are position independent (short and near jumps use a relative offset).

I would suggest compiling your modules with load address 0, and in PIC mode. I don't know how you locate a specific function in the module right now, but I would add an offset table to the start. Then the kernel can just calculate a function pointer when the module is loaded by adding the base address to the offsets, and then call the function pointers. I don't know how the module would call back into the kernel. You might want to hand it a couple of function pointers as well.

Re: C code and Linkier script: calculate jump locations

Posted: Thu Nov 08, 2018 12:10 pm
by nintyfan
I discovered the problem. Linker puts my print function (module is called text_console) at the beginning of binary output file. My kernel jump to the beginning of module to initialize it. That's my linker script:

Code: Select all

OUTPUT_FORMAT("binary")
ENTRY("init")
PROVIDE(__module_load_addr = 0x1000);
SECTIONS {
  
  
  .text : {
    *(init)
    *(.text)
  }
  
  .rodata : {
    *(.rodata)
  }
  
  .data  : {
    *(.data)
  }
  
  .bss : {
    *(.bss)
  }

}
That's a part of definition of my init function:

Code: Select all

__attribute__ ((section ("entry"))) char init(struct drivers*dr, int driver_count) {
...
}
I must tell that gcc internals are not known for me, so I can do mistakes in many places. Be polite. Is there a way to force linker/compiler to put my init function on top of output file? I think creating one pointer to init function at the beginning of file (as nullplan suggested) is a waste of space.

Re: C code and Linkier script: calculate jump locations

Posted: Fri Nov 09, 2018 9:07 am
by MichaelPetch
If you put function init in the section entry in the code then don't you mean to use:

Code: Select all

  .text : {
    *(entry)
    *(.text)
  }

Re: C code and Linkier script: calculate jump locations

Posted: Sun Nov 11, 2018 2:49 am
by nintyfan
Ok. Nothing works, but solution given by Employed Russian on https://stackoverflow.com/questions/661 ... -toolchain worked.
You need to use --ffunction-sections and similar linker script to this bellow:

Code: Select all

OUTPUT_FORMAT("binary")
SECTIONS {
  
  . = 0;
  .text : {
 
    *(.text.init);
    *(.text.*)
  }
  
  .rodata : {
    *(.rodata)
  }
  
  .data  : {
    *(.data)
  }
  
  .bss : {
    *(.bss)
  }

}

Then init will be at beginning of output file. Thanks for help!