Download your favorite Linux distribution at LQ ISO.
Go Back > Forums > Non-*NIX Forums > Programming
User Name
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.


  Search this Thread
Old 07-27-2017, 03:07 PM   #1
Registered: Feb 2016
Location: Zaragoza, Spain
Distribution: Xubuntu, Tails, etc.
Posts: 55

Rep: Reputation: 9
Question Problem linking a C script with inline assembly to a ASM file.

Hi, lets get into the problem:
I were compiling my prototype of prototype of a kernel (sounds weird, but it really doesnt matter) and in the instalation I need to link the ASM file to a C file compiled with gcc to get a executable that could be used as kernel.
The problem is that, after implementing a swap to protected mode from real mode, I get this error at linking the kernel.c and loader.asm scripts:

kernel.c:(.text+0x1e1): undefined reference to `gdtr'
I will explain how all process of instalation is and I will put the codes below.
Instalation steps:
1: Compile asm:
nasm -f elf32 loader.asm -o kasm.o
2: Compile .c :
gcc -m32 -ffreestanding -c kernel.c -o kc.o
3: Link both:
ld -m elf_i386 -T linker.ld -o kernel kasm.o kc.o
The complete error output is:
kc.o: In function `k_enter_protected_mode':
kernel.c:(.text+0x1e1): undefined reference to `gdtr'
The code looks like:
 * kernel.c - version 0.0.1
 * This script is under the license of the distributed package, this license
 * can be found in the package itself
 * Script coded by Cristian Simón for the CKA Proyect
 * ----
 * License: GNU GPL v3
 * Coder: Cristian Simón
 * Proyect: CKA 
/* Output defines */
#define BLACK_BGROUND 0X07 /* black background */
#define WHITE_TXT 0x07 /* light gray on black text */
#define GREEN_TXT 0x02 /* light green on black text */
#define RED_TXT 0x04 /* light red on black text*/
#define CYAN_TXT 0x03 /*light cyan on black text */
#include <stddef.h>
#include <stdint.h>
#include <cpuid.h>
void k_clear_screen();
void k_sleep_3sec();
unsigned int k_printf(char *message, unsigned int line, float color);
void k_malloc(size_t sz);
void k_free(void *mem);
/* k_clear_screen : to clear the entire text screen */
void k_clear_screen()
	char *vidmem = (char *) 0xC00B8000;
	unsigned int i=0;
	while(i < (80*25*2))
		vidmem[i]=' ';

/* k_printf : the message and the line # */
unsigned int k_printf(char *message, unsigned int line, float color)
	char *vidmem = (char *) 0xC00B8000;
	unsigned int i=0;


		if(*message=='\n') /* check for a new line */
		} else {


* k_sleep_3sec : to make a simple delay of aprox 3 sec, since is a nasty sleep, 
* duration will vary
* from system to system
void k_sleep_3sec()
	int c = 1, d = 1;
 	for ( c = 1 ; c <= 20000 ; c++ )
    for ( d = 1 ; d <= 20000 ; d++ )
* Malloc and free functions for this kernel
* Maybe change in the future, sure
static unsigned char our_memory[1024 * 1024]; /* reserve 1 MB for malloc */
static size_t next_index = 0;
int k_malloc_err;
void k_malloc(size_t sz)
	void *mem;
	if(sizeof our_memory - next_index < sz){
    	return NULL;
        k_malloc_err = 1;

    mem = &our_memory[next_index];
    next_index += sz;
    return mem;
void k_free(void *mem)
   /* we cheat, and don't free anything. */
/* Schreduler */
* Our schreduler is a RTC (Run to Completion)
* In the future we will add more schredulers or change the type
* but for now this is what we got
int proc_number_count = 0;
void k_schreduler(char *proc_name, unsigned int proc_prior)
	proc_number_count = proc_number_count + 1;
	int proc_number = proc_number_count;
void k_enter_protected_mode()
    __asm__ volatile ("cli;"          
        "lgdt (gdtr);"  
        "mov %eax, cr0;" 
        "or %al, 1;"    
        "mov cr0, %eax;" 
        "jmp 0x8,PModeMain;"
/*main function*/
void k_main() 
	k_printf(" Wellcome to", 0, WHITE_TXT);
	k_printf(" CKA!", 1, GREEN_TXT);
	k_printf("==============>", 2, WHITE_TXT);
	k_printf(" CKA stands for C Kernel with Assembly", 3, WHITE_TXT);
	k_printf(" Version 0.0.1, => based in the job of Debashis Barman", 4, WHITE_TXT);
	k_printf(" Contact => /", 5, WHITE_TXT);
	k_printf("           or in the github repository page", 6, WHITE_TXT);
	/* here start the magic */
	k_printf(" !===> Starting Checkup <===!", 0, WHITE_TXT);
	k_printf(" =-=-=-=-=-=-=-=-=-=-=-=-=-=-", 1, WHITE_TXT);
	k_printf("[KernelInfo] Woah! No Kernel Panic for now! Well, lets fix that...", 2, CYAN_TXT);
	k_printf("[Proc1] Checking for k_malloc() and k_free() kernel functions", 3, WHITE_TXT);
	if (k_malloc_err == 1){
		k_printf("[F-ERROR] Unable to use k_malloc, do you have enough memory?", 4, RED_TXT);
			int error_stayer = 1;

	} else{ 
		k_printf("[Proc1] k_malloc and k_free found, resuming boot...", 4, GREEN_TXT);
	k_printf("[KernelInfo] Switched to protected mode successfully", 5, CYAN_TXT);

This was kernel.c

   /* The kernel will live at 3GB + 1MB in the virtual
      address space, which will be mapped to 1MB in the
      physical address space. */
   . = 0xC0100000;

   .text : AT(ADDR(.text) - 0xC0000000) {

   .data ALIGN (0x1000) : AT(ADDR(.data) - 0xC0000000) {

   .bss : AT(ADDR(.bss) - 0xC0000000) {
       _sbss = .;
       _ebss = .;
This was the linker.ld
global _loader                          ; Make entry point visible to linker.
extern k_main                           ; _main is defined elsewhere
; setting up the Multiboot header - see GRUB docs for details
MODULEALIGN equ  1<<0             ; align loaded modules on page boundaries
MEMINFO     equ  1<<1             ; provide memory map
FLAGS       equ  MODULEALIGN | MEMINFO  ; this is the Multiboot 'flag' field
MAGIC       equ    0x1BADB002     ; 'magic number' lets bootloader find the header
CHECKSUM    equ -(MAGIC + FLAGS)  ; checksum required
; This is the virtual base address of kernel space. It must be used to convert virtual
; addresses into physical addresses until paging is enabled. Note that this is not
; the virtual address where the kernel image itself is loaded -- just the amount that must
; be subtracted from a virtual address to get a physical address.
KERNEL_VIRTUAL_BASE equ 0xC0000000                  ; 3GB
KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22)  ; Page directory index of kernel's 4MB PTE.
section .data
align 0x1000
    ; This page directory entry identity-maps the first 4MB of the 32-bit physical address space.
    ; All bits are clear except the following:
    ; bit 7: PS The kernel page is 4MB.
    ; bit 1: RW The kernel page is read/write.
    ; bit 0: P  The kernel page is present.
    ; This entry must be here -- otherwise the kernel will crash immediately after paging is
    ; enabled because it can't fetch the next instruction! It's ok to unmap this page later.
    dd 0x00000083
    times (KERNEL_PAGE_NUMBER - 1) dd 0                 ; Pages before kernel space.
    ; This page directory entry defines a 4MB page containing the kernel.
    dd 0x00000083
    times (1024 - KERNEL_PAGE_NUMBER - 1) dd 0  ; Pages after the kernel image.
section .text
align 4
    dd MAGIC
    dd FLAGS
; reserve initial kernel stack space -- that's 16k.
STACKSIZE equ 0x4000
; setting up entry point for linker
loader equ (_loader - 0xC0000000)
global loader
    ; NOTE: Until paging is set up, the code must be position-independent and use physical
    ; addresses, not virtual ones!
    mov ecx, (BootPageDirectory - KERNEL_VIRTUAL_BASE)
    mov cr3, ecx                                        ; Load Page Directory Base Register.
    mov ecx, cr4
    or ecx, 0x00000010                          ; Set PSE bit in CR4 to enable 4MB pages.
    mov cr4, ecx
    mov ecx, cr0
    or ecx, 0x80000000                          ; Set PG bit in CR0 to enable paging.
    mov cr0, ecx
    ; Start fetching instructions in kernel space.
    ; Since eip at this point holds the physical address of this command (approximately 0x00100000)
    ; we need to do a long jump to the correct virtual address of StartInHigherHalf which is
    ; approximately 0xC0100000.
    lea ecx, [StartInHigherHalf]
    jmp ecx                                                     ; NOTE: Must be absolute jump!
    ; Unmap the identity-mapped first 4MB of physical address space. It should not be needed
    ; anymore.
    mov dword [BootPageDirectory], 0
    invlpg [0]
    ; NOTE: From now on, paging should be enabled. The first 4MB of physical address space is
    ; mapped starting at KERNEL_VIRTUAL_BASE. Everything is linked to this address, so no more
    ; position-independent code or funny business with virtual-to-physical address translation
    ; should be necessary. We now have a higher-half kernel.
    mov esp, stack+STACKSIZE           ; set up the stack
    push eax                           ; pass Multiboot magic number
    ; pass Multiboot info structure -- WARNING: This is a physical address and may not be
    ; in the first 4MB!
    push ebx
    call  k_main                 ; call kernel proper
    hlt                          ; halt machine should kernel return
section .bss
align 32
    resb STACKSIZE      ; reserve 16k stack on a uint64_t boundary
This was loader.asm
I tried to solve this transforming the ASM block in an advanced ASM block And parsing gdtr as an argument but I dont understand this last method
How can I solve the error? Thanks in advance!

Last edited by TheStr3ak5; 07-28-2017 at 03:38 AM.
Old 07-28-2017, 12:28 PM   #2
Senior Member
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 3,235

Rep: Reputation: 979Reputation: 979Reputation: 979Reputation: 979Reputation: 979Reputation: 979Reputation: 979Reputation: 979
Maybe it should be %gdtr as it is a register.
Old 07-28-2017, 01:56 PM   #3
Registered: Feb 2016
Location: Zaragoza, Spain
Distribution: Xubuntu, Tails, etc.
Posts: 55

Original Poster
Rep: Reputation: 9
Originally Posted by NevemTeve View Post
Maybe it should be %gdtr as it is a register.
Doing this leaves more errors:
Doing what you sugested will change the block from the original to:
void k_enter_protected_mode()
    __asm__ volatile ("cli;"          
        "lgdt (%gdtr);"  
        "mov %eax, cr0;" 
        "or %al, 1;"    
        "mov cr0, %eax;" 
        "jmp 0x8,PModeMain;"
And at compiling in gcc i get this errors:
kernel.c: Assembler messages:
kernel.c:118: Error: bad expression
kernel.c:118: Error: found 'g', expected: ')'
kernel.c:118: Error: junk `gdtr)' after expression
Old 07-28-2017, 02:35 PM   #4
Senior Member
Registered: Nov 2005
Distribution: Arch
Posts: 3,163

Rep: Reputation: 1370Reputation: 1370Reputation: 1370Reputation: 1370Reputation: 1370Reputation: 1370Reputation: 1370Reputation: 1370Reputation: 1370Reputation: 1370
AFAICT, the argument to lgdt is a memory address, not a register.
To load the GDTR, the instruction LGDT is used:

lgdt [gdtr]
Where gdtr is a pointer to 6 bytes of memory containing the desired GDTR value. Note that to complete the process of loading a new GDT, the segment registers need to be reloaded.
So you need to define gdtr to point to some memory.
Old 08-09-2017, 10:35 AM   #5
Registered: Oct 2016
Posts: 147

Rep: Reputation: 36
That inline asm looks very odd.

The prefixes are mandatory:

/* Note it's %%eax, instead of %eax in C source files. */

(%%eax) is a pointer.
%%eax is a register.
$1 is an immediate value.

At the end of the block you have:

: /* Outputs */
: /* Inputs */
: /* Clobbered registers */

Maybe check the GCC manual.

Last edited by Fat_Elvis; 08-09-2017 at 10:38 AM.
Old 08-09-2017, 12:25 PM   #6
LQ Guru
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 9,557

Rep: Reputation: 2810Reputation: 2810Reputation: 2810Reputation: 2810Reputation: 2810Reputation: 2810Reputation: 2810Reputation: 2810Reputation: 2810Reputation: 2810Reputation: 2810
I cannot compile this kernel.c:
$ gcc -m32 -ffreestanding -c kernel.c -o kc.o
kernel.c: In function ‘k_malloc’:
kernel.c:91:16: warning: ‘return’ with a value, in function returning void
         return NULL;
kernel.c:87:6: note: declared here
 void k_malloc(size_t sz)
kernel.c:97:12: warning: ‘return’ with a value, in function returning void
     return mem;
kernel.c:87:6: note: declared here
 void k_malloc(size_t sz)
kernel.c: Assembler messages:
kernel.c:118: Error: too many memory references for `jmp'
which gcc did you try?

gdtr is not defined at all, so undefined reference is ok.

Last edited by pan64; 08-09-2017 at 12:27 PM.


assembly, compiling, error, gcc, linker

Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
linking of assembly(.s) & c file answerme Programming 2 02-20-2013 08:11 AM
inline asm, 64-bit asm, intercepting segfaults, etc. rainbowsally Programming 0 02-04-2012 05:10 PM
how to insert a comment inside an inline assembly in a c source file? wringer Programming 3 12-06-2010 05:58 AM
gcc inline asm question vv40in Programming 0 04-17-2009 03:37 AM
Problem linking assembly program with C lib. 95se Programming 1 03-08-2005 09:44 PM > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 09:57 AM.

Main Menu
Write for LQ is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration