NASM - The Netwide Assembler

NASM Forum => Programming with NASM => Topic started by: bastl on July 07, 2010, 09:35:43 PM

Title: LKMs (linux modules) with nasm don't work
Post by: bastl on July 07, 2010, 09:35:43 PM
Why can't I programm LKMs with nasm? (they won't load)

I think because of a bigger BSS section than given ( the "nasm - version" string).

Is there any possibility to void this string ?
Title: Re: LKMs (linux modules) with nasm don't work
Post by: Frank Kotler on July 08, 2010, 12:21:51 AM
The nasm version string "should" be in .comment, not .bss, I think. Possibly try "strip -R.comment" to get rid of it. That's a WAG - never done a kernel module. Got a simple example? (always looking for examples!) Or... do newer versions of Nasm add that string by default? I think that's been dropped(?)...

http://www.nasm.us

Best,
Frank

Title: Re: LKMs (linux modules) with nasm don't work
Post by: bastl on July 10, 2010, 11:23:40 PM
Yes your right - the nasm string is dropped with newer versions.
O.K. I work out the misses to get a good example here or maybe I get it.

Title: Re: LKMs (linux modules) with nasm don't work
Post by: bastl on July 18, 2010, 03:14:51 PM
Now I worked out a little module that stands the module check and loads - but with an paging request bug.
The tool I worked with on the object and module files is:
objdump -dxs object.o #or module.ko .

File simple.nasm:
Code: [Select]
section .modinfo
__mod_description8 db 'description=Simple module',0
align 16,db 0
__mod_author7 db 'author=Your name',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.26.2 SMP preempt mod_unload modversions K8 ',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 'Hello, initializing the module',0
l_init_t equ $-init_t
exit_t db 'cleaning ... Bye bye !',0
l_exit_t equ $-exit_t

section .exit.text  exec
global cleanup_module:
mov eax,4 ;write
mov ebx,1 ;to Terminal
mov ecx,exit_t ;from address
mov edx,l_exit_t ;count bytes
int $80
ret

section .init.text  exec
global init_module:
mov eax,4 ;write
mov ebx,1 ;to Terminal
mov ecx,init_t ;from address
mov edx,l_init_t ;count bytes
int $80
mov eax,0
ret

section .gnu.linkonce.this_module
__this_module db 0,0,0,0,0,0,0,0,0,0,0,0,'simple',0   ;linking space before the module name
align 1024, db 0 ;Space to link the module in (guessed)
What has to be customised are the areas:

The modules Makefile (gmake) I use is:
Code: [Select]
#define assembler execution
AS=nasm
ASFLAGS= -f elf -O2

#define assembler code files usage to get object files
%.o : %.nasm
$(AS) $(ASFLAGS) $<

#define target to get from source
simple.o : simple.nasm

obj-m := simple.o

#only there to remember that the kernel build process can do the translation from object.o to module.ko file.
#However, a C source file which defines the memory (areas - functions, variables) has to be present.
default:
# make -C /lib/modules/`uname -r`/build M=`pwd`

install:
# make -C /lib/modules/`uname -r`/build M=`pwd` modules_install
cp simple.o simple.ko
cp simple.ko /lib/modules/`uname -r`/extra/

uninstall:
rm /lib/modules/`uname -r`/extra/simple.ko

The error I get is:
paging request bug
and the kernel module (load, unload) process breaks (does not return)

I'm not sure about:
- what the meaning of section info <2**5, 2**7> of objdump is ?
- and if that could cause that bug if the sections:
   - .gnu.linkonce.this_module has 2**0 intead of 2**7
   - __versions has 2**0 instead of 2**5
   - .modinfo has 2**0 instead of 2**5 ?
- how I can get such sections (2**5, 2**7) with nasm ?

Title: Re: LKMs (linux modules) with nasm don't work
Post by: Frank Kotler on July 18, 2010, 04:37:27 PM
Thanks for the example! I'm afraid I'm going to have to read up on kernel modules before I understand it. :)

I think the "2**5" and "2**7" refer to alignment. Try "align=32" and "align=128" in the section declarations(?).

One suggestion... in the makefile, "-O2" may give different results with different Nasm versions. :( I would use "-Ox". In the very latest version, this has been made the default. (This will break Brian Raiter's "true.asm", I think. Sorry, Brian.)

One thing in the code I'm not sure about: will "global init_module:" work? You might need to use separate " global init_ module" and "init_module:"...

If I develop enough ambition to try this, and if I learn anything, I'll get back to ya!

Best,
Frank

Title: Re: LKMs (linux modules) with nasm don't work
Post by: Cyrill Gorcunov on July 18, 2010, 06:48:00 PM
Code: [Select]
section .gnu.linkonce.this_module
__this_module db 0,0,0,0,0,0,0,0,0,0,0,0,'simple',0   ;linking space before the module name
align 1024, db 0 ;Space to link the module in (guessed)

This is a bit strange. This section should contain struct module (in terms of "C") filled with proper data.
And 2**10 align is a side effect of your align 1024 statement. It should not be like that.
Use "times" statement instead when you need to reserve space. I suspect we have this in manual.

I must admit I didn't build kernel modules with nasm myself so I fear I can't give you an example
from practice ;) Though struct module is described in scripts/mod/modpost.h in linux
sources I believe.

Hope this helps.
Title: Re: LKMs (linux modules) with nasm don't work
Post by: bastl on July 18, 2010, 08:13:27 PM
I use align, that i don't have to calculate the length of that section to fit in 128 byte boundry. So the section is 1024 bytes big no mather what I define else in.
Here the module get linked in and however the module name is layed here that way at that position, maybe elf specific.
If you decrease this space so the module can not be linked in you get also a special error for that.
First I also looked at the C definitions how the memory gets arranged but I did give up soon and took the object and module files instead.
Think about that the modul object file gets modified to a module with "make -C /lib/modules/`uname -r`/build M=`pwd`" So the whole kernel make process is involved. The result can not be find in C code at all or only parts of it.
Title: Re: LKMs (linux modules) with nasm don't work
Post by: Cyrill Gorcunov on July 18, 2010, 09:08:55 PM
Well, actually I think the right place where the module structure is defined -- is module.h rather the one I was referring to, sorry.

And your section .gnu.linkonce.this_module should contain the refs to init/exit functions of your module otherwise kernel would not find which procedure to call at module loading/unloading time.
Title: Re: LKMs (linux modules) with nasm don't work
Post by: Cyrill Gorcunov on July 18, 2010, 09:19:39 PM
Think about that the modul object file gets modified to a module with "make -C /lib/modules/`uname -r`/build M=`pwd`" So the whole kernel make process is involved. The result can not be find in C code at all or only parts of it.

In your kernel source tree you will find *.cmd file for every module kernel being build. Which consists of commands passed to gcc and ld. This might be worth to inspect as well.
Title: Re: LKMs (linux modules) with nasm don't work
Post by: Frank Kotler on July 19, 2010, 07:24:45 AM
The reason I'm so ignorant (one of 'em), is that RTFM puts me to sleep. I tackled "module-HOWTO", and sure enough... I'll get back into it when I'm ready for another nap. :)

This is an old one, came with a 2.4 kernel, but it explains differences with 2.6. I'm definitely going to have to upgrade my kernel before I can "follow along"! Probably should do that before I bother reading "module-HOWTO". As  I understand it, we now assemble/compile to an .o file, run "modpost" (a script?) on our .o file and it creates C code. Then we link our .o file with the .o file created by this file into a .ko file. Yow!

My system doesn't have .ko files - the modules seem to be .gz. But, as it happens, I have a partially installed (on a too-small partition) 2.6 kernel, so I grabbed "cpuid.ko" from there... thinking "I know cpuid, maybe I can recognize something." Hah! Only thing I recognized was the author's name (Peter, naturally). I disassembled it with Agner Fog's "objconv", rather than "objdump", just 'cause I'm more familiar with it.

I've attempted to alter (mutilate) your "simple.asm" so it's "more like" Agner's disassembly of Peter's "cpuid.ko". It is not expected to be correct. Test it at your own risk! I don't even remember if my half-baked 2.6 kernel will boot. If it will, I'll try this, but I wanted to post this "current state of progress", just in case it's a while before I get back. :)

Code: [Select]
%if 0
struct module {
struct module *next;
const char *name;
int gpl_compatible;
struct symbol *unres;
int seen;
int skip;
int has_init;
int has_cleanup;
struct buffer dev_table_buf;
char      srcversion[25];
};

struc module
.next resd 1
.name resd 1
.gpl_compatible resd 1
.unres resd 1
.seen resd 1
.skip resd 1
.has_init resd 1
.has_cleanup resd 1
.dev_table_buf resb 1 ;?
.srcversion resb 25
endstruc
%endif

global init_module
global cleanup_module
global __this_module


section .exit.text  exec align=16
cleanup_module:
mov eax,4 ;write
mov ebx,1 ;to Terminal
mov ecx,exit_t ;from address
mov edx,l_exit_t ;count bytes
int $80
ret

section .init.text  exec align=16
init_module:
mov eax,4 ;write
mov ebx,1 ;to Terminal
mov ecx,init_t ;from address
mov edx,l_init_t ;count bytes
int $80
mov eax,0
ret

section .data
init_t db 'Hello, initializing the module',0
l_init_t equ $-init_t
exit_t db 'cleaning ... Bye bye !',0
l_exit_t equ $-exit_t


section .modinfo align=32 noexec

__mod_license6 db 'license=GPL',0
times 32 - ($ - __mod_license6) db 0


__mod_description8 db 'description=Simple module',0
times 64 - ($ - __mod_description8) db 0

__mod_author7 db 'author=bastl- cyrill-frank',0
times 64 - ($ - __mod_author7) db 0


__module_depends db 'depends=',0
times 32 - ($ - __module_depends) db 0

; CHANGEME!
__mod_vermagic5 db 'vermagic='
db '2.6.21.5' ; uname -r
; db ' SMP preempt mod_unload modversions K8 ',0   ;from a .ko module of my system
db ' mod_unload modversions 486 ',0   ;from a cpuid.ko

; don't care about size(?)
; end section .modinfo


section __versions align=4 noexec ; ?
____versions db 0x9d,'V',0x1e,'$struct_module',0   ;from a .ko module of my system
times 64 - ($ - ____versions) db 0

section .gnu.linkonce.this_module align=128 noexec
__this_module:
times 12 db 0
db 'simple',0   ;linking space before the module name

times 228 - ($ - __this_module) db 0
dd init_module

times 524 - ($ - __this_module) db 0
dd cleanup_module

;times 1024 - ($ - __this_module) db 0 ;Space to link the module in (guessed)
times 640 - ($ - __this_module) db 0 ;Space to link the module in (guessed again)

Best,
Frank


Title: Re: LKMs (linux modules) with nasm don't work
Post by: Frank Kotler on July 19, 2010, 10:26:29 AM
Oh, my! Yeah, that kernel boots alright. I suppose I should have asked how we go about about testing this LKM... :)

I tried rebooting - didn't seem to do anything. Tried "insmod simple.ko" - "invalid module format". But, advised by "dmesg", I changed "vermagic" until it "did something". A message about "paging request"... and a whole bunch of other stuff! I think there was a "segfault" in there, but it kept going after that(!). I attempted to retry and capture the error message(s) but the retry just hung, and I was unable to get anything. What's more, "reboot" hung at "Shutting down PCMCIA services: cards". Gave it the three-fingered salute - claimed it was going down for reboot "NOW!"... but it didn't. Tried the Big Red Switch. Well, it's migrated around front and is a "soft" pushbutton... which declined to shut off! I literally had to yank the cord to reboot the thing!

Stubborn, I tried it again (you don't get far with asm if you're not stubborn!) "to see if it failed the same way". It did, pretty much. This time, the three-fingered salute did nothing, but the switch worked. Still didn't capture the error messsage(s), and no idea why the  "paging request" failed, or what the rest of it was about - or why it hung "reboot"!

So I'm making progress backwards, but here's the current state of the "progress". (actually the opposite of progress: congress!). It is *not* a working example!

Code: [Select]

global init_module
global cleanup_module
global __this_module

section .text ; cpuid.ko has one...


section .exit.text  exec align=16
cleanup_module:
mov eax,4 ;write
mov ebx,1 ;to Terminal
mov ecx,exit_t ;from address
mov edx,l_exit_t ;count bytes
int $80
ret

section .init.text  exec align=16
init_module:
mov eax,4 ;write
mov ebx,1 ;to Terminal
mov ecx,init_t ;from address
mov edx,l_init_t ;count bytes
int $80
mov eax,0
ret

section .rodata
init_t db 'Hello, initializing the module',0
l_init_t equ $-init_t
exit_t db 'cleaning ... Bye bye !',0
l_exit_t equ $-exit_t


section .modinfo align=32 noexec

__mod_license6 db 'license=GPL',0
times 32 - ($ - __mod_license6) db 0


__mod_description8 db 'description=Simple module',0
times 64 - ($ - __mod_description8) db 0

__mod_author7 db 'author=bastl- cyrill-frank',0
times 64 - ($ - __mod_author7) db 0


__module_depends db 'depends=',0
times 32 - ($ - __module_depends) db 0

; CHANGEME!
__mod_vermagic5 db 'vermagic='
db '2.6.21.5-smp' ; uname -r
; db ' SMP preempt mod_unload modversions K8 ',0   ;from a .ko module of my system
db ' SMP mod_unload 686 ',0   ;from a cpuid.ko

; don't care about size(?)
; end section .modinfo

; cpuid.ko doesn't have this...
%if 0
section __versions align=4 noexec ; ?
____versions db 0x9d,'V',0x1e,'$struct_module',0   ;from a .ko module of my system
times 64 - ($ - ____versions) db 0
%endif

section .data ; per cpuid.ko...

section .gnu.linkonce.this_module align=128 noexec
__this_module:
times 12 db 0
db 'simple',0   ;linking space before the module name

times 228 - ($ - __this_module) db 0
dd init_module

times 524 - ($ - __this_module) db 0
dd cleanup_module

;times 1024 - ($ - __this_module) db 0 ;Space to link the module in (guessed)
times 640 - ($ - __this_module) db 0 ;Space to link the module in (guessed again)

section .bss ; per cpuid.ko...

The research continues... later...

Best,
Frank

Title: Re: LKMs (linux modules) with nasm don't work
Post by: bastl on July 19, 2010, 09:21:28 PM
Now I did get it !
After some reading about paging in the web I did read that the linux kernel paging is done with 4k pages.
So I extended my funktions to 4k and what a pleasure, it works. The module loads and unloads and is listed.
The only thing I wasn't able to figure out was, where the terminal outputs are gone they were not printed to my terminal and nowhere else.
So I can not confirm that the init_module and cleanup_module functions have been executed.

Here the module:

simple.nasm
Quote
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.26.2 SMP preempt mod_unload modversions K8 ',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   'Hello, initializing the module',0
;l_init_t         equ   $-init_t
exit_t            db   'cleaning ... Bye bye !',0
;l_exit_t         equ   $-exit_t


section .text

global cleanup_module:
   align 4096
   mov   eax,4         ;write
   mov   ebx,1         ;to Terminal
   mov   ecx,exit_t      ;from address
   mov   edx,30      ;count bytes
   int   $80
   ret

global init_module:
   align 4096
   mov   eax,4         ;write
   mov   ebx,1         ;to Terminal
   mov   ecx,init_t      ;from address
   mov   edx,23      ;count bytes
   int   $80
   mov   eax,0
   ret
   

section .gnu.linkonce.this_module
__this_module      times 12 db 0
            db   'simple',0   ;linking space before the module name
align 8704, db 0      ;Space to link the module in (guessed)

What to do with this stuff:
--- added 20.07.2010 03:45:40 PM---

Title: Re: LKMs (linux modules) with nasm don't work
Post by: Frank Kotler on July 20, 2010, 02:01:35 AM
Okay... I was doing everything but the last step. I did the naive thing and just added the name to the end of modules.dep. Didn't seem to do anything for me - "simple" still doesn't seem to load on boot. However, with this latest version, I can load it with "insmod", and load and unload it with "modprobe" (as shown by "lsmod"). Good progress!

No output. Why should it? You haven't told the kernel where to find init_module or cleanup_module, have you? Here's the relevant portion of Agner's disassembly of Peter's "cpuid.ko":

Code: [Select]
SECTION .gnu.linkonce.this_module align=128 noexecute   ; section number 9, data

__this_module:                                          ; byte
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0000 _ ........
        db 00H, 00H, 00H, 00H, 63H, 70H, 75H, 69H       ; 0008 _ ....cpui
        db 64H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0010 _ d.......
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0018 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0020 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0028 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0030 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0038 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0040 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0048 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0050 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0058 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0060 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0068 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0070 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0078 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0080 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0088 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0090 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 0098 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 00A0 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 00A8 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 00B0 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 00B8 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 00C0 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 00C8 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 00D0 _ ........
        db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H       ; 00D8 _ ........
        db 00H, 00H, 00H, 00H                           ; 00E0 _ ....
        dd init_module                                  ; 00E4 _ 00000000 (d)
        dd 00000000H, 00000000H                         ; 00E8 _ 0 0
        dd 00000000H, 00000000H                         ; 00F0 _ 0 0
        dd 00000000H, 00000000H                         ; 00F8 _ 0 0
        dd 00000000H, 00000000H                         ; 0100 _ 0 0
        dd 00000000H, 00000000H                         ; 0108 _ 0 0
        dd 00000000H, 00000000H                         ; 0110 _ 0 0
        dd 00000000H, 00000000H                         ; 0118 _ 0 0
        dd 00000000H, 00000000H                         ; 0120 _ 0 0
        dd 00000000H, 00000000H                         ; 0128 _ 0 0
        dd 00000000H, 00000000H                         ; 0130 _ 0 0
        dd 00000000H, 00000000H                         ; 0138 _ 0 0
        dd 00000000H, 00000000H                         ; 0140 _ 0 0
        dd 00000000H, 00000000H                         ; 0148 _ 0 0
        dd 00000000H, 00000000H                         ; 0150 _ 0 0
        dd 00000000H, 00000000H                         ; 0158 _ 0 0
        dd 00000000H, 00000000H                         ; 0160 _ 0 0
        dd 00000000H, 00000000H                         ; 0168 _ 0 0
        dd 00000000H, 00000000H                         ; 0170 _ 0 0
        dd 00000000H, 00000000H                         ; 0178 _ 0 0
        dd 00000000H, 00000000H                         ; 0180 _ 0 0
        dd 00000000H, 00000000H                         ; 0188 _ 0 0
        dd 00000000H, 00000000H                         ; 0190 _ 0 0
        dd 00000000H, 00000000H                         ; 0198 _ 0 0
        dd 00000000H, 00000000H                         ; 01A0 _ 0 0
        dd 00000000H, 00000000H                         ; 01A8 _ 0 0
        dd 00000000H, 00000000H                         ; 01B0 _ 0 0
        dd 00000000H, 00000000H                         ; 01B8 _ 0 0
        dd 00000000H, 00000000H                         ; 01C0 _ 0 0
        dd 00000000H, 00000000H                         ; 01C8 _ 0 0
        dd 00000000H, 00000000H                         ; 01D0 _ 0 0
        dd 00000000H, 00000000H                         ; 01D8 _ 0 0
        dd 00000000H, 00000000H                         ; 01E0 _ 0 0
        dd 00000000H, 00000000H                         ; 01E8 _ 0 0
        dd 00000000H, 00000000H                         ; 01F0 _ 0 0
        dd 00000000H, 00000000H                         ; 01F8 _ 0 0
        dd 00000000H, 00000000H                         ; 0200 _ 0 0
        dd 00000000H                                    ; 0208 _ 0
        dd cleanup_module                               ; 020C _ 00000000 (d)
        dd 00000000H, 00000000H                         ; 0210 _ 0 0
        dd 00000000H, 00000000H                         ; 0218 _ 0 0
        dd 00000000H, 00000000H                         ; 0220 _ 0 0
        dd 00000000H, 00000000H                         ; 0228 _ 0 0
        dd 00000000H, 00000000H                         ; 0230 _ 0 0
        dd 00000000H, 00000000H                         ; 0238 _ 0 0
        dd 00000000H, 00000000H                         ; 0240 _ 0 0
        dd 00000000H, 00000000H                         ; 0248 _ 0 0
        dd 00000000H, 00000000H                         ; 0250 _ 0 0
        dd 00000000H, 00000000H                         ; 0258 _ 0 0
        dd 00000000H, 00000000H                         ; 0260 _ 0 0
        dd 00000000H, 00000000H                         ; 0268 _ 0 0
        dd 00000000H, 00000000H                         ; 0270 _ 0 0
        dd 00000000H, 00000000H                         ; 0278 _ 0 0

As you can see, there's more in that section than just the name (and zeros). I tried to do similar with your code. First thing that happens is Nasm whines about undefined symbols. I'm quite sure that your "global init_module:" is not enough. I think you need:

Code: [Select]
global init_module
init_module:

for it to work. I tried that - still no output. I ASSume that int 80h writes to stdout work from within the kernel... but everybody seems to use "kprintf". Peter's cpuid.ko also declares "global  __this_module". I didn't try that. Perhaps it would help?

I suppose the "hello" example - written in C - produces output? Where would I find that?

More later, if I get to it.

Best,
Frank


Title: Re: LKMs (linux modules) with nasm don't work
Post by: bastl on July 20, 2010, 03:31:38 PM
Yes, I use modprobe, too. I edit that post to make it clear.
The "Hello world"  C example is located at  http://tldp.org/LDP/lkmpg/2.6/html/x121.html (http://tldp.org/LDP/lkmpg/2.6/html/x121.html).
And how I can remember does printk also use the same syscall like I do.
The functions get linked into the kernel by a kernel extern access and the kernel also defines them also by its self.
I guess that my functions are not linked correctly so the kernel calls its dummy functions instead (it's paging, so parts or funktions at whole can overlap each other and need so more linking informations - only a guess).
I will test your hints !
Title: Re: LKMs (linux modules) with nasm don't work
Post by: bastl on July 22, 2010, 07:26:17 PM
No way to get my functions called!
I want the linker to overwrite existing global functions with the same name so my function get in place and will be unique and get called but I can't find a corresponding option for that in NASM for functions.
COMMON is only for variables but should also be possible for functions (for all labels).
Title: Re: LKMs (linux modules) with nasm don't work
Post by: Cyrill Gorcunov 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 :)
Title: Re: LKMs (linux modules) with nasm don't work
Post by: Cyrill Gorcunov 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. :)
Title: Re: LKMs (linux modules) with nasm don't work
Post by: Cyrill Gorcunov 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... :)
Title: Re: LKMs (linux modules) with nasm don't work
Post by: Cyrill Gorcunov 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
Title: Re: LKMs (linux modules) with nasm don't work
Post by: Cyrill Gorcunov 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.
Title: Re: LKMs (linux modules) with nasm don't work
Post by: Frank Kotler 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

Title: Re: LKMs (linux modules) with nasm don't work
Post by: Cyrill Gorcunov 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.
Title: Re: LKMs (linux modules) with nasm don't work
Post by: Cyrill Gorcunov 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 :)
Title: Re: LKMs (linux modules) with nasm don't work
Post by: Cyrill Gorcunov 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.
Title: Re: LKMs (linux modules) with nasm don't work
Post by: bastl 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/ (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.
 
Title: Re: LKMs (linux modules) with nasm don't work
Post by: Cyrill Gorcunov 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.
Title: Re: LKMs (linux modules) with nasm don't work
Post by: bastl 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.
Title: Re: LKMs (linux modules) with nasm don't work
Post by: Cyrill Gorcunov 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).
Title: Re: LKMs (linux modules) with nasm don't work
Post by: bastl 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).
Title: Re: LKMs (linux modules) with nasm don't work
Post by: bastl 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.
Title: Re: LKMs (linux modules) with nasm don't work
Post by: Cyrill Gorcunov on July 26, 2010, 09:58:05 PM
no, no common section for the elf at the moment iirc. use "global" and keywords as "function" and please read documentation as well, for example, note section "9.2.4 Exporting Symbols to the Library User".

Quote
Also into loaded libraries or like this example here shows - the need to link into the running kernel for module load.

it will NOT help, i tired to repeat -- module requires predefined structure for "linkonce" section.
Frankly, use C for such cases and nasm for core functions this will eliminate all your problems.
Title: Re: LKMs (linux modules) with nasm don't work
Post by: Cyrill Gorcunov on July 26, 2010, 09:59:12 PM
we have COMMON directive but it's not what you meant I guess.
Title: Re: LKMs (linux modules) with nasm don't work
Post by: bastl on July 27, 2010, 03:41:55 PM
we have COMMON directive but it's not what you meant I guess.
Surely, I did read the documentation and COMMON declaration was the only thing that does what I need (in elf)  but it should be used for all symbols not only for symbols of variables.

All symbols in the running environment have to be overwritten !!!
So all symbols and its offsets are unique and equal  in the running environment


And why not use COMMON as a directive to all symbols in NASM (elf) ? Would be nice to have full support of elf in NASM, or not?

Title: Re: LKMs (linux modules) with nasm don't work
Post by: Cyrill Gorcunov on July 27, 2010, 05:14:29 PM
SHN_COMMON has nothing to do with this particular "kernel modules" problem.

So if you need SHN_COMMON not for variables but for functions names as well then I guess we may take a look and check how much effort it will require to bring this ability in.

Actually better to ping us via bugtracker then -- there is "Feature request" category when you describes what you need and why. So we get notified that there some new request.

See http://nasm.us/ for "Bug Tracker" on top menu and fill request please.
Title: Re: LKMs (linux modules) with nasm don't work
Post by: hoverlees on August 02, 2010, 10:32:37 AM
Why can't I programm LKMs with nasm? (they won't load)

I think because of a bigger BSS section than given ( the "nasm - version" string).

Is there any possibility to void this string ?

Hello bastl, what is your linux kernel version? Your code seems only fit for linux2.4, My linux 2.6 insmod the driver  cause a  "Invalid module format" problem .
What ashamed I havent successfully compiled a linux2.6 kernel module by nasm
Title: Re: LKMs (linux modules) with nasm don't work
Post by: bastl on August 02, 2010, 07:31:06 PM
Hello bastl, what is your linux kernel version? Your code seems only fit for linux2.4, My linux 2.6 insmod the driver  cause a  "Invalid module format" problem .
What ashamed I havent successfully compiled a linux2.6 kernel module by nasm

My linux kernel is 2.6.26.2.
I have a glibc, binutils GNU system.
The 2.6 kernel module loader is more flexible as the 2.4 one.
It all depends on which linker you build the kernel for/with. In the case you want to load the last given simple example above, you need a kernel builded with the gnu binutils ld linker.