C code and Linkier script: calculate jump locations

Programming, for all ages and all languages.
Post Reply
nintyfan
Posts: 23
Joined: Wed Nov 07, 2018 10:15 am

C code and Linkier script: calculate jump locations

Post 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?
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: C code and Linkier script: calculate jump locations

Post by Solar »

What you are looking for is "position independent code" (PIC).
Every good solution is obvious once you've found it.
nintyfan
Posts: 23
Joined: Wed Nov 07, 2018 10:15 am

Re: C code and Linkier script: calculate jump locations

Post 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.
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: C code and Linkier script: calculate jump locations

Post 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.
Carpe diem!
nintyfan
Posts: 23
Joined: Wed Nov 07, 2018 10:15 am

Re: C code and Linkier script: calculate jump locations

Post 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.
MichaelPetch
Member
Member
Posts: 797
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: C code and Linkier script: calculate jump locations

Post 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)
  }
nintyfan
Posts: 23
Joined: Wed Nov 07, 2018 10:15 am

Re: C code and Linkier script: calculate jump locations

Post 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!
Post Reply