OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Apr 18, 2024 5:40 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 14 posts ] 
Author Message
 Post subject: Problem with passing a pointer to function.
PostPosted: Tue Mar 05, 2019 4:20 pm 
Offline
Member
Member

Joined: Wed Feb 13, 2019 3:07 pm
Posts: 28
I try to pass char* to function.
Code:
void start() {
   init_memory();
   char* str = "Hello world";
   print_s(str);   
}

void print_s(char*s)
{
   put_c(s[0]);
}

put_c just prints a char on screen.

When i execute code, instead of printing 'H' i get nothing on screen.

dump of obj
Code:
Disassembly of section .text:

00000000 <start>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   83 ec 28                sub    $0x28,%esp
   6:   e8 fc ff ff ff          call   7 <start+0x7>
         7: R_386_PC32   init_memory
   b:   c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%ebp)
         e: R_386_32   .rodata
  12:   8b 45 f4                mov    -0xc(%ebp),%eax
  15:   89 04 24                mov    %eax,(%esp)
  18:   e8 fc ff ff ff          call   19 <start+0x19>
         19: R_386_PC32   print_s
  1d:   c9                      leave 
  1e:   c3                      ret   

Disassembly of section .rodata:

00000000 <.rodata>:
   0:   48                      dec    %eax
   1:   65 6c                   gs insb (%dx),%es:(%edi)
   3:   6c                      insb   (%dx),%es:(%edi)
   4:   6f                      outsl  %ds:(%esi),(%dx)
   5:   20 77 6f                and    %dh,0x6f(%edi)
   8:   72 6c                   jb     76 <start+0x76>
   a:   64                      fs
   ...


How to fix if?

UPD: with
Code:
char str[] = "Hello world"
it works correctly, but i don't know why with
Code:
char*
i got a fault.


Last edited by Shvets04 on Tue Mar 05, 2019 5:04 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Problem with passing a pointer to function.
PostPosted: Tue Mar 05, 2019 4:25 pm 
Offline
Member
Member

Joined: Mon Feb 02, 2015 7:11 pm
Posts: 898
The problem might well be in put_c(), but we don't get to see that function.

_________________
https://github.com/kiznit/rainbow-os


Top
 Profile  
 
 Post subject: Re: Problem with passing a pointer to function.
PostPosted: Tue Mar 05, 2019 4:29 pm 
Offline
Member
Member

Joined: Wed Feb 13, 2019 3:07 pm
Posts: 28
kzinti wrote:
The problem might well be in put_c(), but we don't get to see that function.

No, when i pass char directly to put_c() it works correctly.


Top
 Profile  
 
 Post subject: Re: Problem with passing a pointer to function.
PostPosted: Tue Mar 05, 2019 4:43 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
Shvets04 wrote:
Code:
   char* str = "Hello world";

How to fix if?

Depending on the compiler, the code you have assigns the pointer 'str' to a const string of "Hello world" that probably is in a different "segment" than your DS points to. i.e.: The compiler may treat the following
Code:
   char* str = "Hello world";

a bit different than:
Code:
   char str[] = "Hello world";

The first may place a pointer relative to the BSS section (or CONST or whatever section) where the second may place a pointer relative to the current stack pointer and use the SS segment.

Unless you know what compiler you are using and what it will do with it, it is not wise to use:
Code:
   char* str = "Hello world";

in OS/firmware/driver/etc development.

Could it be that your DS != SS or the compiler placed the string at the end of your code?

Ben
- http://www.fysnet.net/osdesign_book_series.htm


Top
 Profile  
 
 Post subject: Re: Problem with passing a pointer to function.
PostPosted: Tue Mar 05, 2019 4:55 pm 
Offline
Member
Member

Joined: Wed Feb 13, 2019 3:07 pm
Posts: 28
BenLunt wrote:
Shvets04 wrote:
Code:
   char* str = "Hello world";

How to fix if?

Depending on the compiler, the code you have assigns the pointer 'str' to a const string of "Hello world" that probably is in a different "segment" than your DS points to. i.e.: The compiler may treat the following
Code:
   char* str = "Hello world";

a bit different than:
Code:
   char str[] = "Hello world";

The first may place a pointer relative to the BSS section (or CONST or whatever section) where the second may place a pointer relative to the current stack pointer and use the SS segment.

Unless you know what compiler you are using and what it will do with it, it is not wise to use:
Code:
   char* str = "Hello world";

in OS/firmware/driver/etc development.

Could it be that your DS != SS or the compiler placed the string at the end of your code?

Ben
- http://www.fysnet.net/osdesign_book_series.htm

"Hello world" is located in rodata
Code:
Contents of section .text:
0000 5589e583 ec28e8fc ffffffc7 45f40000  U....(......E...
0010 00008b45 f4890424 e8fcffff ffc9c3    ...E...$.......
Contents of section .rodata:
0000 48656c6c 6f20776f 726c6400           Hello world.   
Contents of section .comment:
0000 00474343 3a202847 4e552920 342e382e  .GCC: (GNU) 4.8.
0010 35203230 31353036 32332028 52656420  5 20150623 (Red
0020 48617420 342e382e 352d3336 2900      Hat 4.8.5-36). 
Contents of section .eh_frame:
0000 14000000 00000000 017a5200 017c0801  .........zR..|..
0010 1b0c0404 88010000 1c000000 1c000000  ................
0020 00000000 1f000000 00410e08 8502420d  .........A....B.
0030 055bc50c 04040000                    .[......       



UPD: Flags that i use with gcc: -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs


Top
 Profile  
 
 Post subject: Re: Problem with passing a pointer to function.
PostPosted: Tue Mar 05, 2019 7:21 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
I'd bet that you have a custom bootloader that isn't reading enough sectors (your kernel) into memory and the string you want to print is not physically loaded into memory. It would work for stack based string because the string is likely placed directly on the stack programmatically by the compiler (the actual method used is compiler/compiler option dependent).

I'm making this guess (without even seeing how the kernel was loaded) based on the fact I have seen very similar questions with nearly the identical behaviour.


Top
 Profile  
 
 Post subject: Re: Problem with passing a pointer to function.
PostPosted: Wed Mar 06, 2019 7:44 am 
Offline
Member
Member

Joined: Wed Feb 13, 2019 3:07 pm
Posts: 28
MichaelPetch wrote:
I'd bet that you have a custom bootloader that isn't reading enough sectors (your kernel) into memory and the string you want to print is not physically loaded into memory. It would work for stack based string because the string is likely placed directly on the stack programmatically by the compiler (the actual method used is compiler/compiler option dependent).

I'm making this guess (without even seeing how the kernel was loaded) based on the fact I have seen very similar questions with nearly the identical behaviour.


The bootloader loads enough sectors into memory.

Problem is that the code generated by compiler doesn't try pass any a pointer to function.
Code:
  b:   c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%ebp)
         e: R_386_32   .rodata
  12:   8b 45 f4                mov    -0xc(%ebp),%eax
  15:   89 04 24                mov    %eax,(%esp)
  18:   e8 fc ff ff ff          call   19 <start+0x19>
         19: R_386_PC32   print_s



Top
 Profile  
 
 Post subject: Re: Problem with passing a pointer to function.
PostPosted: Wed Mar 06, 2019 8:02 am 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
Shvets04 wrote:
Problem is that the code generated by compiler doesn't try pass any a pointer to function.
Code:
  b:   c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%ebp)
         e: R_386_32   .rodata
  12:   8b 45 f4                mov    -0xc(%ebp),%eax
  15:   89 04 24                mov    %eax,(%esp)
  18:   e8 fc ff ff ff          call   19 <start+0x19>
         19: R_386_PC32   print_s


Yes it does. It just so happens that the data is the first data in the rodata section, so it has an offset of 0x00000000.
Code:
  b:   c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%ebp)

Code:
Contents of section .rodata:
0000 48656c6c 6f20776f 726c6400           Hello world.   

Here is the code:
Code:
  // char* str = "Hello world";
  b:   c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%ebp)

The compiler reserved a pointer-sized variable at [ebp-12] (which is on the stack) and placed the offset from the .rodata section to the string. It then retrieves this value, pushing it onto the stack and calling the print_s routine:
Code:
  12:   8b 45 f4                mov    -0xc(%ebp),%eax
  15:   89 04 24                mov    %eax,(%esp)
  18:   e8 fc ff ff ff          call   19 <start+0x19>

The above could be see as (in Intel syntax), though the above code eliminates the need for the stack clean up:
Code:
  12:  mov  eax,[ebp-12]
  15:  push eax
  16:  call  print_s

You will need to find out where your rodata section is, related to the text section and make an adjustment. For example, if your rodata section is 0x100 bytes from the "start of the file", then you will need.
Code:
  12:  mov  eax,[ebp-12]
  15:  add  eax,rodata_section_adjustment
  xx:  push eax
  xx:  call print_s

However, this isn't really the correct way to do it either.

My suggestion, to make it all must easier, is to only have one section. However, this gets difficult the larger the code base.

I don't use GCC so someone else is going to have to tell you how to get it to create only one section, or tell you how to output the correct binary file.

I use a standard Windows PE file with, what would be considered, a single section, so that SS == DS == ES, etc.

Ben
- http://www.fysnet.net/osdesign_book_series.htm


Top
 Profile  
 
 Post subject: Re: Problem with passing a pointer to function.
PostPosted: Wed Mar 06, 2019 8:20 am 
Offline
Member
Member

Joined: Wed Feb 13, 2019 3:07 pm
Posts: 28
BenLunt wrote:
Shvets04 wrote:
Problem is that the code generated by compiler doesn't try pass any a pointer to function.
Code:
  b:   c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%ebp)
         e: R_386_32   .rodata
  12:   8b 45 f4                mov    -0xc(%ebp),%eax
  15:   89 04 24                mov    %eax,(%esp)
  18:   e8 fc ff ff ff          call   19 <start+0x19>
         19: R_386_PC32   print_s


Yes it does. It just so happens that the data is the first data in the rodata section, so it has an offset of 0x00000000.
Code:
  b:   c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%ebp)

Code:
Contents of section .rodata:
0000 48656c6c 6f20776f 726c6400           Hello world.   

Here is the code:
Code:
  // char* str = "Hello world";
  b:   c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%ebp)

The compiler reserved a pointer-sized variable at [ebp-12] (which is on the stack) and placed the offset from the .rodata section to the string. It then retrieves this value, pushing it onto the stack and calling the print_s routine:
Code:
  12:   8b 45 f4                mov    -0xc(%ebp),%eax
  15:   89 04 24                mov    %eax,(%esp)
  18:   e8 fc ff ff ff          call   19 <start+0x19>

The above could be see as (in Intel syntax), though the above code eliminates the need for the stack clean up:
Code:
  12:  mov  eax,[ebp-12]
  15:  push eax
  16:  call  print_s

You will need to find out where your rodata section is, related to the text section and make an adjustment. For example, if your rodata section is 0x100 bytes from the "start of the file", then you will need.
Code:
  12:  mov  eax,[ebp-12]
  15:  add  eax,rodata_section_adjustment
  xx:  push eax
  xx:  call print_s

However, this isn't really the correct way to do it either.

My suggestion, to make it all must easier, is to only have one section. However, this gets difficult the larger the code base.

I don't use GCC so someone else is going to have to tell you how to get it to create only one section, or tell you how to output the correct binary file.

I use a standard Windows PE file with, what would be considered, a single section, so that SS == DS == ES, etc.

Ben
- http://www.fysnet.net/osdesign_book_series.htm



How to fix it?
+ i give my link.ld - https://pastebin.com/Z7ftgcwV
and make file - https://pastebin.com/VgDnxfCW


Top
 Profile  
 
 Post subject: Re: Problem with passing a pointer to function.
PostPosted: Wed Mar 06, 2019 8:45 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
You keep dumping the output of the object files. I'm curious, are you converting object files directly to binary and putting that on your disk? I hope not. You need to link to an executable and have that output to binary. If you showed us the commands you use to compile/assemble and link (and any linker script) we might get a better understanding of what is going on. It seems like your kernel isn't using fully resolved addresses and the only way I can see that happening is if you aren't properly linking to a fully resolved binary executable and you are writing binary forms of object files directly instead.


Top
 Profile  
 
 Post subject: Re: Problem with passing a pointer to function.
PostPosted: Wed Mar 06, 2019 9:30 am 
Offline
Member
Member

Joined: Wed Feb 13, 2019 3:07 pm
Posts: 28
MichaelPetch wrote:
You keep dumping the output of the object files. I'm curious, are you converting object files directly to binary and putting that on your disk? I hope not. You need to link to an executable and have that output to binary. If you showed us the commands you use to compile/assemble and link (and any linker script) we might get a better understanding of what is going on. It seems like your kernel isn't using fully resolved addresses and the only way I can see that happening is if you aren't properly linking to a fully resolved binary executable and you are writing binary forms of object files directly instead.


It's happening(not passing a pointer), because i compile with -c flag, without -c occur linking with data from .rodata and a pointer is passed, but with it a comliper try linking with CRT that isn't needed.

p.s i left links to link.ld and Makefile files above.


Top
 Profile  
 
 Post subject: Re: Problem with passing a pointer to function.
PostPosted: Wed Mar 06, 2019 10:29 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
Well I see issues in your make file and possibly your linker script. What I first need to know is... where is your bootloader loading the kernel into memory at? Your make file suggests that it may be at 0x1000 in memory but the linker script you are using specifies 0x100000.


Top
 Profile  
 
 Post subject: Re: Problem with passing a pointer to function.
PostPosted: Wed Mar 06, 2019 10:38 am 
Offline
Member
Member

Joined: Wed Feb 13, 2019 3:07 pm
Posts: 28
MichaelPetch wrote:
Well I see issues in your make file and possibly your linker script. What I first need to know is... where is your bootloader loading the kernel into memory at? Your make file suggests that it may be at 0x1000 in memory but the linker script you are using specifies 0x100000.


0x1000, i fixed link.ld.

UPD. it already works :D Thank everybody.


Top
 Profile  
 
 Post subject: Re: Problem with passing a pointer to function.
PostPosted: Wed Mar 06, 2019 11:28 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
Although you say you got it working, I'll present the minimum changes I would have made. In the linker script the origin point initial VMA should be 0x1000. I'd also use the linker script to force the text section of kernel/kernel.o to always be the first file (then you can drop the explicit use of it from the make rule that generates the ELF file). In the make file I'm inclined to convert the kernel.elf to kernel.bin with OBJCOPY. kernel.bin should be built from kernel.elf not kernel.o. If you aren't using a cross compiler (and I highly recommend you use a cross compiler) I'd seriously consider compiling with the option -fno-PIC to avoid generating the global offset table and position independent code that relies on it. I changed Makefile to:
Code:
C_SOURCES = $(wildcard kernel/*.c drivers/*.c)
HEADERS = $(wildcard kernel/*.h drivers/*.h)
# Nice syntax for file extension replacement
OBJ = ${C_SOURCES:.c=.o}

# Change this if your cross-compiler is somewhere else
CC = gcc
GDB = /usr/local/i386elfgcc/bin/i386-elf-gdb
# -g: Use debugging symbols in gcc
CFLAGS = -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs -fno-PIC -std=gnu99
# First rule is run by default
os-image.bin: boot/boot.bin kernel.bin
        cat $^ > os-image.bin

# objcopy with -O binary will convert kernel.elf to kernel.bin. All symbolic info will
# be stripped
kernel.bin: kernel.elf
        objcopy -O binary $^ $@

# Used for debugging purposes
kernel.elf: ${OBJ}
        ld -melf_i386 -o $@ -Tlink.ld $^

run: os-image.bin
        qemu-system-i386 -fda os-image.bin

# Open the connection to qemu and load our kernel-object file with symbols
debug: os-image.bin kernel.elf
        qemu-system-i386 -s -fda os-image.bin &
        ${GDB} -ex "target remote localhost:1234" -ex "symbol-file kernel.elf"

# Generic rules for wildcards
# To make an object, always compile from its .c
%.o: %.c ${HEADERS}
        ${CC} ${CFLAGS} -ffreestanding -c $< -o $@

%.o: %.asm
        nasm $< -f elf -o $@

%.bin: %.asm
        nasm $< -f bin -o $@

clean:
        rm -rf *.bin *.dis  os-image.bin *.elf
        rm -rf  boot/*.bin drivers/*.o boot/*.o
and link.ld to:
Code:
OUTPUT_FORMAT(elf32-i386)
ENTRY(start)


SECTIONS {
    . = 0x00001000;          /* the code should be loaded at 1 MB */

    .text :
    {
        kernel/kernel.o(.text.*) /* Ensure text section of kernel.o is first thing */
        *(.text*)             /* all text sections from all files */
    }

    .rodata :
    {
        *(.rodata*)          /* all read-only data sections from all files */
    }

    .data :
    {
        *(.data)             /* all data sections from all files */
    }

    .bss :
    {
        *(COMMON)            /* all COMMON sections from all files */
        *(.bss)              /* all bss sections from all files */
    }
}
It should be noted that your kernel.c should contain only a single function - your kernel entry point. Placing any other functions in that file could have any one of the functions become the entry point. You can avoid all this by placing the kernel entry point function into its own special section (like .text.entry) and ensure that section comes before all others (in the linker script). If you did it this way link.ld could look like:
Code:
OUTPUT_FORMAT(elf32-i386)
ENTRY(start)


SECTIONS {
    . = 0x00001000;          /* the code should be loaded at 1 MB */

    .text :
    {
        *(.text.entry)       /* Ensure .text.entry section is first thing */
        *(.text*)             /* all text sections from all files */
    }

    .rodata :
    {
        *(.rodata*)          /* all read-only data sections from all files */
    }

    .data :
    {
        *(.data)             /* all data sections from all files */
    }

    .bss :
    {
        *(COMMON)            /* all COMMON sections from all files */
        *(.bss)              /* all bss sections from all files */
    }
}
In kernel.c you can now have any number of functions, but your kernel entry point (I'm using kernel_main as an example) could look like:
Code:
void  __attribute__ ((section (".text.entry"))) kernel_main()
{
    /* Place main kernel code here */

    /* End with infinite hlt loop */
    while(1) ("hlt");
}
__attribute__ ((section (".text.entry"))) places the kernel_main function into the section .text.entry . The linker script ensures .text.entry section is placed in the output file first. Doing it this way also means that kernel.o doesn't have to be the first object listed when building kernel.elf, nor does it require kernel.o being referenced in the linker script. Your kernel entry point must be the only thing in section .text.entry


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 14 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot] and 161 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group