Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can GNU as process struct and function prototypes in assembly file(.s)?

Tags:

gcc

assembly

As we know, assembly files(.S) would get preprocessing before assembling, but I found that after preprocessing there may be struct/function prototypes in the resulting assembly files, How would the gnu as deal with these prototypes? Just ignored it?

For example, the following command:

gcc -E -o tmp.result arch/x86/boot/copy.S -Iinclude/ -Iarch/x86/include/

and the resulting assembly file (tmp.result) is:

# 1 "arch/x86/boot/copy.S"                                                                                                                                                                   
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "arch/x86/boot/copy.S"
# 11 "arch/x86/boot/copy.S"
# 1 "include/linux/linkage.h" 1
# 1 "include/linux/compiler.h" 1
# 5 "include/linux/linkage.h" 2
# 1 "include/linux/stringify.h" 1
# 6 "include/linux/linkage.h" 2
# 1 "include/linux/export.h" 1
# 26 "include/linux/export.h"
struct kernel_symbol
{
 unsigned long value;
 const char *name;
};
# 7 "include/linux/linkage.h" 2
# 1 "arch/x86/include/asm/linkage.h" 1
# 8 "include/linux/linkage.h" 2
# 12 "arch/x86/boot/copy.S" 2
.code16
.text
GLOBAL(memcpy)
 pushw %si 
 pushw %di 
 movw %ax, %di 
 movw %dx, %si 
 pushw %cx 
 shrw $2, %cx 
 rep; movsl
 popw %cx 
 andw $3, %cx 
 rep; movsb
 popw %di 
 popw %si 
 retl
ENDPROC(memcpy)

but when trying to assemble this file:

as -o tmp.o tmp.result

produce following error:

include/linux/export.h: Assembler messages:
include/linux/export.h:26: Error: no such instruction: `struct kernel_symbol'
include/linux/export.h:27: Error: junk at end of line, first unrecognized character is `{'
include/linux/export.h:28: Error: no such instruction: `unsigned long value'
include/linux/export.h:29: Error: no such instruction: `const char *name'
include/linux/export.h:30: Error: junk at end of line, first unrecognized character is `}'
arch/x86/boot/copy.S:20: Error: invalid character '(' in mnemonic
arch/x86/boot/copy.S:34: Error: invalid character '(' in mnemonic
arch/x86/boot/copy.S:36: Error: invalid character '(' in mnemonic
arch/x86/boot/copy.S:49: Error: invalid character '(' in mnemonic
arch/x86/boot/copy.S:51: Error: invalid character '(' in mnemonic
arch/x86/boot/copy.S:58: Error: invalid character '(' in mnemonic
arch/x86/boot/copy.S:60: Error: invalid character '(' in mnemonic
arch/x86/boot/copy.S:67: Error: invalid character '(' in mnemonic

It seems that the assembler can not deal with the struct in tmp.result. How can Linux source code(.S) get through the assembling?

like image 884
Kingwah Avatar asked Sep 27 '16 09:09

Kingwah


1 Answers

as cannot process struct and function prototypes - they are just for the C compiler, and get "pulled in" in your preprocessing by mistake. In facts, if you look at the header that provides that struct definition, you'll see:

#ifndef __ASSEMBLY__
struct kernel_symbol
{
        unsigned long value;
        const char *name;
};

So, the header above is thought to be included both from assembly and from C, but you didn't define __ASSEMBLY__ to tell it that you are including it into an assembly file.

Interestingly, gcc does have a builtin __ASSEMBLER__ predefined macro to discriminate between an inclusion in an assembly file or a C file, but it seems that the kernel does not use it for historical reasons, relying instead on defining manually __ASSEMBLY__ when preprocessing assembly files.

Long story short: to get the correct output from the preprocessor, you should be doing something like

gcc -E -D__ASSEMBLY__ -o tmp.result arch/x86/boot/copy.S -Iinclude/ -Iarch/x86/include/

(disclaimer: I'm not entirely familiar with the kernel build process, the line above may have other problems with include paths, or maybe the correct way would be to invoke cpp instead of gcc or whatever - I don't know)

like image 87
Matteo Italia Avatar answered Oct 23 '22 05:10

Matteo Italia