process to inspect generated assembly of a function

Nicholas Mc Guire der.herr at hofr.at
Fri Jun 6 13:26:34 EDT 2014


n Fri, 06 Jun 2014, Valdis.Kletnieks at vt.edu wrote:

> On Fri, 06 Jun 2014 12:23:35 -0400, Andev said:
> 
> > I am trying to inspect the generated assembly for a function in the
> > kernel. Are there any documents explaining how to do this? I want to
> > see how it changes when I change the function body.
> 
> The same exact way you'd do it for any .o file for userspace.
> 
> objdump and gdb are your friends.

in the kernel build system there is support for understanding assembler code
by generating the .lst files which include the decoded assembler interleaved
with the C source (roughly) making it easier to understand the code.
Also --verbose-asm used when generating .s files in the kernel helps as gcc 
is creating variables that are not in your C-code and that can be confusing 
to decode if one does not see it from the names.
finally looking at the source code can be challenging as there are many 
macros and build dependencies so its probably easier to look at the 
preprocessor output .i rather than the original C-source file.

for kernel sources its:

hofrat at rtl27:~/linux-stable# make defconfig
*** Default configuration is based on 'x86_64_defconfig'
#
# configuration written to .config
#
hofrat at rtl27:~/linux-stable# make kernel/mutex.lst
scripts/kconfig/conf --silentoldconfig Kconfig
...
  HOSTCC  scripts/conmakehash
  HOSTCC  scripts/sortextable
  MKLST   kernel/mutex.lst
hofrat at rtl27:~/linux-stable# more kernel/mutex.lst
<snip>
void
__mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
{
        atomic_set(&lock->count, 1);
        spin_lock_init(&lock->wait_lock);
   b:   66 c7 47 04 00 00       movw   $0x0,0x4(%rdi)
        lock->owner = current;
}
...
<snip>

hofrat at rtl27:~/linux-stable# make kernel/mutex.s
...
  CHK     include/generated/utsrelease.h
  CALL    scripts/checksyscalls.sh
  CC      kernel/mutex.s
hofrat at rtl27:~/linux-stable# more kernel/mutex.s
<snip>
...
        .text
        .p2align 4,,15
.globl __mutex_init
        .type   __mutex_init, @function
__mutex_init:
        pushq   %rbp    #
        leaq    8(%rdi), %rax   #, D.20779
        movl    $1, (%rdi)      #, <variable>.count.counter
        movw    $0, 4(%rdi)     #, <variable>.wait_lock.D.3891.rlock
        movq    $0, 24(%rdi)    #, <variable>.owner
        movq    %rsp, %rbp      #,
        movq    %rax, 8(%rdi)   # D.20779, <variable>.wait_list.next
        movq    %rax, 16(%rdi)  # D.20779, <variable>.wait_list.prev
        movq    $0, 32(%rdi)    #, <variable>.spin_mlock
        leave
        ret
 ...
<snip>

 The variables named D.# are those that gcc created.
 Note that the code looks different because of the #defines that were
 resolved and translated in .s case but not in the .lst case.

 having both the .s and the .lst file at hand along with the preprocessor
 output generated by  


hofrat at rtl27:~/linux-stable# make kernel/mutex.i 
hofrat at rtl27:~/linux-stable# more kernel/mutex.i 
<snip>
 ...
void
__mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
{
 atomic_set(&lock->count, 1);
 do { spinlock_check(&lock->wait_lock); do { *(&(&lock->wait_lock)->rlock) = (raw_spinlock_t) { .raw_lock = { { 0 } }, }; } while (0); } while (0);
 INIT_LIST_HEAD(&lock->wait_list);
 mutex_clear_owner(lock);

 lock->spin_mlock = ((void *)0);


 do { } while (0);
}
...
<snip>

 should allow you to figure out the details of what is going on in the assembler
 code of your functions. 

thx!
hofrat



More information about the Kernelnewbies mailing list