Author Topic: LKMs (linux modules) with nasm don't work  (Read 40513 times)

Offline Cyrill Gorcunov

  • NASM Developer
  • Full Member
  • *****
  • Posts: 179
  • Country: 00
Re: LKMs (linux modules) with nasm don't work
« Reply #15 on: July 22, 2010, 08:43:35 PM »
OK, here is very quick result of loadable module on x86-64

Code: [Select]
[bits 64]

global init_module
global cleanup_module

section .modinfo
__mod_description8 db   'description=Simple module',0
align 16,db 0
__mod_author7 db   'author=That´s me',0
__mod_license6 db   'license=GPL',0
align 16,db 0
__module_depends db   'depends=',0
align 32,db 0
__mod_vermagic5 db   'vermagic=2.6.34 SMP preempt mod_unload ',0   ;from a .ko module of my system

section __versions
____versions db   0x9d,'V',0x1e,'$struct_module',0   ;from a .ko module of my system
align 64,db 0

section .data
init_t db   'init_module\n',0
exit_t db   'cleanup_module\n',0

section .text

cleanup_module:
mov eax, 0
ret

init_module:
mov eax, 0
ret

section .gnu.linkonce.this_module
times 24 db 0
__name: db 'Simple', 0
times (0x168 - 24 - 7) db 0
__init_module: dq init_module
times 0x2ac db 0
__cleanup_module: dq cleanup_module
times 1152 db 0

It boots and unloads fine. The key moment is to use proper offsets to your init/exit pointers.

To find out which they are on my system I used objdump with -O binary which just extract the section I'm interested in. There also a "pahole" tool which will say you the offsets of the structure members but it didn't
work on my system for some reason (ie I know why it doesn't work but it's a different story).

I'll take a look more precisely when I get spare time. Note that this is a dirty hack not for any kind "real" project usage :)

Offline Cyrill Gorcunov

  • NASM Developer
  • Full Member
  • *****
  • Posts: 179
  • Country: 00
Re: LKMs (linux modules) with nasm don't work
« Reply #16 on: July 22, 2010, 08:47:45 PM »
on x86-32 there will be different offsets, I would suggest you to do

objcopy -O binary -j .gnu.linkonce.this_module some-module.ko some-module.ko.gnu.linkonce.this_module

where some-module.ko is some existing module. This will extract the content of .gnu.linkonce.this_module section so you will be able to inspect it under any hex editor to find out the offsets.

Also big fat note is that building modules highly depends on kernel configuration you're planning to load module in. Some kernels may not even have cleanup_module entry point at all. :)

Offline Cyrill Gorcunov

  • NASM Developer
  • Full Member
  • *****
  • Posts: 179
  • Country: 00
Re: LKMs (linux modules) with nasm don't work
« Reply #17 on: July 22, 2010, 08:54:32 PM »
one (or two) more things:

 - as only you have the .gnu.linkonce.this_module section extracted -- check out at which offset the module name is placed
 - then used objdump -x some-module.ko to find out offsets of module init/exit relocations points, at this offsets you will have to put reference to init/exit routines

And don't forget to see dmesg output where kernel will say you what is wrong (and btw printk output will be there as well).

Hope it helps. I know it might be not that easy but once you've done it... :)

Offline Cyrill Gorcunov

  • NASM Developer
  • Full Member
  • *****
  • Posts: 179
  • Country: 00
Re: LKMs (linux modules) with nasm don't work
« Reply #18 on: July 22, 2010, 09:03:18 PM »
ok, here is a summary of what to be done for proper "nasm" module

1) the structure module from module.h must be placed into .gnu.linkonce.this_module section in binary form. The key fields there will be the following members (from struct module)

Code: [Select]
struct module {
...
char name[MODULE_NAME_LEN];
...
int (*init)(void);
...
void (*exit)(void);
}

Other fields could be set to 0. The problem is say "exit" is depends on CONFIG_MODULE_UNLOAD preprocessor definition. So an easier way to find out this offsets is to use objcopy and objdump as I menationed before.

Same applies to .modinfo setion but I just took yours and it worked as well.

Code: [Select]
cyrill@lenovo nasm.git $ sudo insmod ./module.ko
cyrill@lenovo nasm.git $ lsmod
Module                  Size  Used by
Simple                  2492  0
nvidia              10832678  41
cyrill@lenovo nasm.git $ sudo rmmod Simple
cyrill@lenovo nasm.git $ lsmod
Module                  Size  Used by
nvidia              10832678  41

Offline Cyrill Gorcunov

  • NASM Developer
  • Full Member
  • *****
  • Posts: 179
  • Country: 00
Re: LKMs (linux modules) with nasm don't work
« Reply #19 on: July 22, 2010, 09:12:51 PM »
Actually, if I were you I woldn't write the whole kernel module with nasm. I would rather write some core functions with nasm (or say computing core) and all callers in C in separate file.

So there would be two files: one .c and one .asm, both compiled to .o then. And then I would use standard kernel make-way to build a module. At least this would be more portable and easy I believe.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: LKMs (linux modules) with nasm don't work
« Reply #20 on: July 22, 2010, 09:19:03 PM »
Thanks for the link to the C file. I could have found that myself (probably), but I figured it would be better if we were looking at the same one. I'm reading it in small increments - stopping when I just start to yawn. :)

There may be a clue there - "printk" (not "kprintf", idiot!) seems to take a parameter, "KERN_INFO" (or others) to tell it where to put its output. How do we do an equivalent with sys_write? Try using stderr instead of stdout? And/or look in dmesg for our output (as Cyrill has suggested)?

Just "notes to myself" to try when/if I get back into it. Been too "scattered" to try anything lately... just wanted to touch base with you...

Best,
Frank


Offline Cyrill Gorcunov

  • NASM Developer
  • Full Member
  • *****
  • Posts: 179
  • Country: 00
Re: LKMs (linux modules) with nasm don't work
« Reply #21 on: July 22, 2010, 09:27:00 PM »
If KERN_INFO is not specified the kernel "thinks" such message have KERN_WARN level. So they should appear in dmesg output (if only you didn't rise loglevel at boot option :)

hmm, I found that mine printk didn't flood syslog ;) so I presume I've calculated offsets wrong :/

I probably take more closer look at weekend.

Offline Cyrill Gorcunov

  • NASM Developer
  • Full Member
  • *****
  • Posts: 179
  • Country: 00
Re: LKMs (linux modules) with nasm don't work
« Reply #22 on: July 22, 2010, 09:31:11 PM »
About output itself (ie the way to tune printk so it would print message to X terminal) -- there should be some hints on google how to play with ttyS. I don't recall it from my head,  tried it only several times :)

Offline Cyrill Gorcunov

  • NASM Developer
  • Full Member
  • *****
  • Posts: 179
  • Country: 00
Re: LKMs (linux modules) with nasm don't work
« Reply #23 on: July 22, 2010, 09:36:09 PM »
Just recall, if the message prefixed with "<0> " (which is KERN_EMERG) it will definitely appear in dmesg output.
So we might use db "<0> some message" for debug purpose at the moment.

Offline bastl

  • Jr. Member
  • *
  • Posts: 17
Re: LKMs (linux modules) with nasm don't work
« Reply #24 on: July 23, 2010, 12:07:20 PM »
Maybe I was not clear - I have no responses of my functions ( init_module, cleanup_module) anywere, because they are not executed - what else ?
I have done fundamental hardware access in that functions that must have consequences -> but nothing.
To bring some light to the module loading process I found a good article at IBM:
http://www.ibm.com/developerworks/linux/library/l-lkm/ -> Module loading details (somewhere in the middle)
And I think the bug is located at -->"load_module / 9.)" (fixup symbols).
Keep in mind that elf is a very powerful instrument.
 

Offline Cyrill Gorcunov

  • NASM Developer
  • Full Member
  • *****
  • Posts: 179
  • Country: 00
Re: LKMs (linux modules) with nasm don't work
« Reply #25 on: July 23, 2010, 03:18:52 PM »
Quote
Maybe I was not clear - I have no responses of my functions ( init_module, cleanup_module) anywere, because they are not executed - what else ?

ok, seems my english is so crappy that you don't understand me :)

The problem IS IN OFFSETS of init/exit references in .gnu.linkonce.this_module.

This section very-very-very sensitive to kernel configuration. So that every new configuration may not allow
you to load module being compiled for same kernel but with different configuration.

Lets simplify the things. Check out any existing module you have in your /lib/modules/. For example on my 64bit custom
linux system I have /lib/modules/2.6.34/kernel/drivers/leds/ledtrig-default-on.ko.

So I eat it to objdump -x to find offsets of init/exit functions in .gnu.linkonce.this_module. For my particular kernel they are placed
to

Code: [Select]
RELOCATION RECORDS FOR [.gnu.linkonce.this_module]:
OFFSET           TYPE              VALUE
0000000000000148 R_X86_64_64       init_module
0000000000000238 R_X86_64_64       cleanup_module

So for init it's 0x148 and for exit 0x238. Now I can modify the source code of our asm file this way:

Code: [Select]
section .gnu.linkonce.this_module
__this:
pad 24
__name: db 'Simple', 0
pad 0x148
__init_module: dq init_module
pad 0x238
__cleanup_module: dq cleanup_module
pad 1152

The "pad" here is a macro which yields 0x0 up to aligned value. Ie it's
Code: [Select]
%imacro pad 1-2.nolist
    %ifnempty %2
        %define __PAD_VALUE %2
    %else
        %define __PAD_VALUE 0
    %endif
    %if ($-$$) == 0
        times (%1) db __PAD_VALUE
    %else
        times (((%1) - (($-$$) % (%1))) % (%1)) db __PAD_VALUE
    %endif
%endmacro

So after this modification I see in dmesg output the module's init/exit being called

Code: [Select]
[12213.055821]  init_module
[12217.929404]  cleanup_module

And eventually the whole source code.
Code: [Select]
%imacro pad 1-2.nolist
    %ifnempty %2
        %define __PAD_VALUE %2
    %else
        %define __PAD_VALUE 0
    %endif
    %if ($-$$) == 0
        times (%1) db __PAD_VALUE
    %else
        times (((%1) - (($-$$) % (%1))) % (%1)) db __PAD_VALUE
    %endif
%endmacro

[bits 64]

extern printk

section .modinfo
__mod_description8 db   'description=Simple module',0
pad 16
__mod_author7 db   'author=That´s me',0
__mod_license6 db   'license=GPL',0
pad 16
__module_depends db   'depends=',0
pad 32
__mod_vermagic5 db   'vermagic=2.6.34 SMP preempt mod_unload ',0   ;from a .ko module of my system

section __versions
____versions db   0x9d,'V',0x1e,'$struct_module',0   ;from a .ko module of my system
pad 64

section .data
fmt db   '%s', 0
init_t db   '<0> init_module', 0xA, 0
exit_t db   '<0> cleanup_module', 0xA, 0
__this_module dq   __this

section .exit.text exec
global cleanup_module
cleanup_module:
mov eax, 0
mov rdx, 2
mov rdi, exit_t
mov rsi, fmt
call printk
mov eax, 0
ret

section .init.text exec
global init_module
init_module:
mov eax, 0
mov rdx, 2
mov rdi, init_t
mov rsi, fmt
call printk
mov eax, 0
ret

section .gnu.linkonce.this_module
__this:
pad 24
__name: db 'Simple', 0
pad 0x148
__init_module: dq init_module
pad 0x238
__cleanup_module: dq cleanup_module
pad 1152

Note that it's for x86-64 system.

Hope this helps.

Offline bastl

  • Jr. Member
  • *
  • Posts: 17
Re: LKMs (linux modules) with nasm don't work
« Reply #26 on: July 23, 2010, 07:50:30 PM »
So I eat it to objdump -x to find offsets of init/exit functions in .gnu.linkonce.this_module. For my particular kernel they are placed
to
Sorry, I don't have meant you in particular so more to get my wishes be answered. ("common" option for global functions, so what you do by hand the linker does, or something similar)
Your idea is good but not very portable, sorry. And what you do also does not work for me for example, because I  have different values there in each *.ko file.

Offline Cyrill Gorcunov

  • NASM Developer
  • Full Member
  • *****
  • Posts: 179
  • Country: 00
Re: LKMs (linux modules) with nasm don't work
« Reply #27 on: July 23, 2010, 08:02:18 PM »
So I eat it to objdump -x to find offsets of init/exit functions in .gnu.linkonce.this_module. For my particular kernel they are placed
to
Sorry, I don't have meant you in particular so more to get my wishes be answered. ("common" option for global functions, so what you do by hand the linker does, or something similar)
Your idea is good but not very portable, sorry. And what you do also does not work for me for example, because I  have different values there in each *.ko file.


Yes, it's not portable by any means -- the only idea was to show an example how to make it work. To make it portable you'll need %ifdef's and a number of additional field described (but even then there could be tricks as well).

Offline bastl

  • Jr. Member
  • *
  • Posts: 17
Re: LKMs (linux modules) with nasm don't work
« Reply #28 on: July 23, 2010, 08:26:27 PM »
I think there of somehting like this:
Quote
...
global init_module:function common

init_module :
   <code>
...

But I can not find anything similar to this in NASM's documentation. Or something else that gives the right values to the linker (elf).

Offline bastl

  • Jr. Member
  • *
  • Posts: 17
Re: LKMs (linux modules) with nasm don't work
« Reply #29 on: July 26, 2010, 08:31:41 PM »
No responds so far... ?
Then It is right that NASM can't give the directive common to all symbols.
With elf you have more possibilities than just linking some code together, you can also link into running code, so to all symbols in your environment (segment).
Also into loaded libraries or like this example here shows - the need to link into the running kernel for module load.
So I think common should be implemented as a directive that it can be used like aline.
So common should be addable to all global symbols.
Mybe like this:
Code: [Select]
section .data
global base   db 23   common   ;or
global base common   db 23     ;or
global common base   db 23     ;or

section .text
global common overall:
     ...
     <code>
     ...                                        ;or

global common cleanup_module:function
cleanup_module:
     ...
     <code>
     ...        

Without such a common directive you can't do real sophisticated OOP.
« Last Edit: July 26, 2010, 08:35:29 PM by bastl »