Pointer values C not interpreted correctly?

Programming, for all ages and all languages.
scippie
Member
Member
Posts: 40
Joined: Wed Jun 27, 2012 3:57 am

Pointer values C not interpreted correctly?

Post by scippie »

Ok, this is really strange. I'm a good C and C++ programmer, so I really don't get this and I must be overlooking something very VERY stupid.

This is the code (64-bit kernel code started from my own bootloader in asm):

Code: Select all

unsigned long long dx = 0xdeadcafebabebeaf;

void printhex(unsigned long long v);

void main(void)
{
	printhex((unsigned long long)&dx);
	__asm__("hlt");
}

void printhex(unsigned long long v)
{
	char buf[16];
	for (int i = 0; i < 16; ++i)
	{
		int r = v & 0xf;
		if (r < 10)
			buf[15 - i] = '0' + r;
		else
			buf[15 - i] = 'A' + r - 10;
		v >>= 4;
	}
	char *video = (char*)0xB8000;
	bool showzeroes = false;
	for (int i = 0; i < 16; ++i)
	{
		if (showzeroes || buf[i] != '0')
		{
			*video++ = buf[i];
			*video++ = 0x07;
			showzeroes = true;
		}
	}
}
Linker script:

Code: Select all

ENTRY(_start); 
SECTIONS {
	_start = 0x1a00 ;
	.text : ALIGN(0x1a00) {
		_TEXT_START_ = .;
		*(.text)
		_TEXT_END_ = .;
	}
	.data : ALIGN(0x1a00) {
		_DATA_START_ = .;
		*(.data)
		_DATA_END_ = .;
	}
	.bss : ALIGN(0x1a00) {
		_BSS_START_ = .;
		*(.bss)
		_BSS_END_ = .;
	}
}
Code is started correctly, variable dx is located at address 0x2600 (checked in the resulting disk image file). Although I think the linker should put the data directly after the code, this is acceptable.

In my opinion, the output of this on screen should be something like: 3400
But the output is: DEADCAFEBABEBEAF !!! which is the value in the variable...

I would expect that to be the result when the code would be:

Code: Select all

printhex(dx);
But when I execute that code, I get an exception!??

This is so weird... Am I doing something so completely wrong here?
Must be something stupid of course, but I can't see it...
I'm so confused!
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Pointer values C not interpreted correctly?

Post by Combuster »

64-bit kernel code started from my own bootloader in asm
What could possibly go wrong?

I can see there's already two things missing from your linker script (a missing section, output format) that make it fail sanity checks, a bunch of arbitrary-looking magic numbers, and there are possibly more specific error causes to point out in all the material that hasn't been posted.

My crystal ball says that it's not the instructions from main() that get executed, but something close...
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
scippie
Member
Member
Posts: 40
Joined: Wed Jun 27, 2012 3:57 am

Re: Pointer values C not interpreted correctly?

Post by scippie »

Combuster wrote:
64-bit kernel code started from my own bootloader in asm
What could possibly go wrong?

I can see there's already two things missing from your linker script (a missing section, output format) that make it fail sanity checks, a bunch of arbitrary-looking magic numbers, and there are possibly more specific error causes to point out in all the material that hasn't been posted.

My crystal ball says that it's not the instructions from main() that get executed, but something close...
Ah, but my previous test-code without global variables executed perfectly. But you are probably right, this looks like it indeed.

Output format and stuff like that are set in the make file:

Code: Select all

AS=/usr/local/cross/bin/fasm -m 265536
CC=/usr/local/cross/bin/x86_64-elf-gcc

CFLAGS=-Wall -m64 -fomit-frame-pointer -fno-builtin -ffreestanding -fPIC -std=c99 -c -save-temps

all: disk.bin

boot.bin:
	$(AS) boot.asm

flatmode.bin:
	$(AS) flatmode.asm

longmode.bin:
	$(AS) longmode.asm

kernel.bin:
	$(CC) $(CFLAGS) kernel.c -o kernel.o
	$(LD) --format elf64-x86-64 --oformat binary --warn-constructors --warn-common -static -Bsymbolic -T os.lds kernel.o -o kernel.bin

disk.bin: boot.bin flatmode.bin longmode.bin kernel.bin
	$(AS) disk.asm

clean:
	rm *.bin
The generated assembler code on the &dx is:

Code: Select all

        .file   "kernel.c"
        .globl  dx
        .data
        .align 8
        .type   dx, @object
        .size   dx, 8
dx:
        .quad   -2401039830915039569
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        subq    $8, %rsp
        .cfi_def_cfa_offset 16
        movq    dx@GOTPCREL(%rip), %rax
        movq    %rax, %rdi
        call    printhex@PLT
/APP
# 31 "kernel.c" 1
        hlt
# 0 "" 2
...
So what does your crystal ball say now?
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Pointer values C not interpreted correctly?

Post by bluemoon »

I see no fatal problem on the posted code, but as Combuster pointed out, make sure the main is actually get executed, not by the generated assembly but check with the dis-assembly code from the real binary, and furthermore with debugger.

by the way, unsigned long long is terrible term by Microsoft compilers, if you need 64-bit integer you can use uint64_t or its family.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Pointer values C not interpreted correctly?

Post by Combuster »

(ninja'd by bluemoon)
scippie wrote:So what does your crystal ball say now?
"Clouded by one subject, the mind is. Looking elsewhere, it has not." :wink:


@bluemoon: where'd the typedef for uint64_t go? (and in particular, on x86-32 :twisted:)
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Pointer values C not interpreted correctly?

Post by bluemoon »

On gcc, you can use uint64_t even on 32-bit compiler, just include from stdint.h
It however require linking to libgcc.a for 64-bit arithmetic to work.
scippie
Member
Member
Posts: 40
Joined: Wed Jun 27, 2012 3:57 am

Re: Pointer values C not interpreted correctly?

Post by scippie »

bluemoon wrote:I see no fatal problem on the posted code, but as Combuster pointed out, make sure the main is actually get executed, not by the generated assembly but check with the dis-assembly code from the real binary, and furthermore with debugger.
Can you tell me how I can disassemble a flat binary? I can't get it to work...
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Pointer values C not interpreted correctly?

Post by bluemoon »

I never used flat binary for anything except some crappy designed plugin for DOS program ten years ago, so I can't answer you.
I suggest you switch to ELF, having tons of tools and reference it will make your life much easier.
User avatar
Griwes
Member
Member
Posts: 374
Joined: Sat Jul 30, 2011 10:07 am
Libera.chat IRC: Griwes
Location: Wrocław/Racibórz, Poland
Contact:

Re: Pointer values C not interpreted correctly?

Post by Griwes »

bluemoon wrote:I see no fatal problem on the posted code, but as Combuster pointed out, make sure the main is actually get executed, not by the generated assembly but check with the dis-assembly code from the real binary, and furthermore with debugger.

by the way, unsigned long long is terrible term by Microsoft compilers, if you need 64-bit integer you can use uint64_t or its family.
`unsigned long long` and `long long` are standard C99 and C++11 types, defined to be at least 64-bit (that is, it is always safe to do `typedef long long int_least64_t;`.

(I do agree that one should use fixed length typedefs; I just don't get what you had in mind by saying long long is "terrible term by Microsoft compilers". It standard since 14 years in C, 2 years in C++, and since a long time as a GCC extension - dunno about MS compilers here, but it is, by no means, a term by MS compilers).
Reaver Project :: Repository :: Ohloh project page
<klange> This is a horror story about what happens when you need a hammer and all you have is the skulls of the damned.
<drake1> as long as the lock is read and modified by atomic operations
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Pointer values C not interpreted correctly?

Post by Combuster »

scippie wrote:Can you tell me how I can disassemble a flat binary? I can't get it to work...
The method you need to know right now is the "u <address>" command in bochs' debugger. Although it already prints the next instruction whenever it pauses from emulating so you might not even need that.


For the flat answer... you know...
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
dozniak
Member
Member
Posts: 723
Joined: Thu Jul 12, 2012 7:29 am
Location: Tallinn, Estonia

Re: Pointer values C not interpreted correctly?

Post by dozniak »

scippie wrote:

Code: Select all

bool showzeroes = false;
	for (int i = 0; i < 16; ++i)
	{
		if (showzeroes || buf[i] != '0')
		{
			*video++ = buf[i];
			*video++ = 0x07;
			showzeroes = true;
Just a side note: if you try to print value of v 0, it will print nothing at all.
Learn to read.
scippie
Member
Member
Posts: 40
Joined: Wed Jun 27, 2012 3:57 am

Re: Pointer values C not interpreted correctly?

Post by scippie »

Combuster wrote:For the flat answer... you know...
Really... google is so new to me. So googling was what I had done a couple of days ago and I found the same result and it did not work for me:
$ objdump -b binary --adjust-vma=0x1a00 -D kernel.bin

kernel.bin: file format binary

/usr/local/cross/x86_64-elf/bin/objdump: can't disassemble for architecture UNKNOWN!

So I tried passing the architecture but that didn't help either.
dozniak wrote:Just a side note: if you try to print value of v 0, it will print nothing at all.
I know.

Bochs, ELF, all things I don't use and actually want to prevent using. Using C and actually using linux (or anything else) for creating this code is against what I want to achieve, but ok, one does need something to get started. Also I don't care if I use uint64_t or unsigned long long. I would actually prefer qword anyway.

But all of these are not really related to my question. I have debugged a bit further and I discovered that even with the global variable in place, the code still seems to be called at the correct address! When I put this line of code at the beginning: *((int*)0xb8000 + 320) = 124323656; it actually works. This means IMHO that main is still started at the correct address and thus there is still some kind of misunderstanding of my C code which is of course not possible, I know that too.

But I believe this must be a problem that starts earlier, so I will continue my debugging and I hope I will find out what it is. Once I get started with C, I can continue creating the greatest OS ever.
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Pointer values C not interpreted correctly?

Post by bluemoon »

Just make sure you're not trying to prevent using things for the wrong reason, I've seen too many of these. I assume you have some good reasons.

Note) One common mistake is that thinking something is inconvenient or complex to deal with, and trying to avoid them, while not aware that such thing could ease the life afterward.

By the way, while not directly solving the problem, people (include myself) point out other potential issue (print 0) or useful stuff (debugger, bochs, elf, the way to tackle the problem) and you could appreciated them as a bonus, instead of I don't care.
User avatar
iansjack
Member
Member
Posts: 4686
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Pointer values C not interpreted correctly?

Post by iansjack »

Run your code in qemu with debugging enabled. Use gdb and single-step throught the code. The problem should then reveal itself.
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Pointer values C not interpreted correctly?

Post by bluemoon »

scippie wrote:I have debugged a bit further and I discovered that even with the global variable in place, the code still seems to be called at the correct address! When I put this line of code at the beginning: *((int*)0xb8000 + 320) = 124323656; it actually works. This means IMHO that main is still started at the correct address and thus there is still some kind of misunderstanding of my C code which is of course not possible, I know that too
No. Another possibility is that there is misalignment(or disagreement) of the location of code for compiler and the running machine. By padding code you may get different executing path and thus generating such observable result. But I won't bet on guessing, have you actually see what's executing on the debugger?
Post Reply