ASM call instruction linking to wrong address.

Programming, for all ages and all languages.
Post Reply
greyOne
Member
Member
Posts: 58
Joined: Sun Feb 03, 2013 10:38 pm
Location: Canada

ASM call instruction linking to wrong address.

Post by greyOne »

I've run into a strange problem in my recent project, with call assembly instructions getting linked to the wrong address. For example, the code:

Code: Select all

.global _isr0
_isr0:
	call testIsr
	iret
Gets turned into the following once compiled and linked,

Code: Select all

c0100ac8 <_isr0>:
c0100ac8:	e8 e8 fe ff ff       	call   c01009b5 <testIsr+0x5>
c0100acd:	cf                   	iret   
c0100ace:	90                   	nop
c0100acf:	90                   	nop
For some reason, the call is being made to an address just past where it's supposed to be going, resulting in a fault. I've run into similar problem throughout my project, including in my kernel bootstrap code calling kmain, with

Code: Select all

	pushl %ebx
	pushl %eax
	call kmain
Turning into

Code: Select all

c0100042:	53                   	push   %ebx
c0100043:	50                   	push   %eax
c0100044:	e8 1c 00 00 00       	call   c0100065 <kmain+0x15>
I haven't been able to find anything that might be causing this, although, I have been able to get around it by making a relative call. This isn't really much of a solution, and doesn't address the underlying problem.

Code: Select all

	leal (kmain), %ecx
	call *%ecx
I'm wondering if anyone has run into a similar issue, or might know what could be causing this. I've tried searching for the problem, but I haven't managed to find any useful results. Of note is that this only happens when using assembly directly; calls made in C code work correctly.
User avatar
Roman
Member
Member
Posts: 568
Joined: Thu Mar 27, 2014 3:57 am
Location: Moscow, Russia
Contact:

Re: ASM call instruction linking to wrong address.

Post by Roman »

Did you use statements like extern? Check if the names are right, maybe GCC renames your functions or something.
"If you don't fail at least 90 percent of the time, you're not aiming high enough."
- Alan Kay
Icee
Member
Member
Posts: 100
Joined: Wed Jan 08, 2014 8:41 am
Location: Moscow, Russia

Re: ASM call instruction linking to wrong address.

Post by Icee »

What are you objdumping here -- individual object files or the resulting executable? In any case, add the -r switch to examine relocations; and also show the actual command lines used to assemble, compile and link.

EDIT: I see now that you mention that the dump is of a linked file, so my first question is invalid. Still, the command lines could be relevant. It would also be nice if you posted a minimal complete example that reproduces the issue.
greyOne
Member
Member
Posts: 58
Joined: Sun Feb 03, 2013 10:38 pm
Location: Canada

Re: ASM call instruction linking to wrong address.

Post by greyOne »

Icee wrote:What are you objdumping here -- individual object files or the resulting executable? In any case, add the -r switch to examine relocations; and also show the actual command lines used to assemble, compile and link.

EDIT: I see now that you mention that the dump is of a linked file, so my first question is invalid. Still, the command lines could be relevant. It would also be nice if you posted a minimal complete example that reproduces the issue.
The complete source for the project is available at https://github.com/Mihail-K/Sptifire-Kernel. It's currently quite small, and the only problem areas have been in kisrs.asm and kstart.asm. I'm also wondering if it might be related to my link script (I'm creating an additional text section, for loading the kernel into the higher half), but that wouldn't make sense as C code links correctly.
Roman wrote:Did you use statements like extern? Check if the names are right, maybe GCC renames your functions or something.
And, I've checked the symbol names that GCC generates, and they appear to be correct. Again, indirect calls do work correctly, so it's somehow related specifically to something that GCC does with the call instruction.

As an aside, I'm currently assembling with GAS. However, I also tried assembling with YASM, and the problem went away, so it is somehow related to something done by GAS itself. Unfortunately, YASM segfaults when assembling my kernel bootstrap (kstart.asm).

Generated by GAS:

Code: Select all

c0100ac8 <_isr0>:
c0100ac8:	e8 e8 fe ff ff       	call   c01009b5 <testIsr+0x5>
c0100acd:	cf                   	iret   
c0100ace:	90                   	nop
c0100acf:	90                   	nop
Generated by YASM:

Code: Select all

c0100ad0 <_isr0>:
c0100ad0:	e8 db fe ff ff       	call   c01009b0 <testIsr>
c0100ad5:	cf                   	iret   
Icee
Member
Member
Posts: 100
Joined: Wed Jan 08, 2014 8:41 am
Location: Moscow, Russia

Re: ASM call instruction linking to wrong address.

Post by Icee »

I cannot reproduce your issue. Having built with "XCC=i686-elf-gcc XINC=. make", and having fixed a compilation error in kgdt.c (in gdtCommit(), though the code is still wrong, inline assembly is not done like that), and having replaced the leal/call indirect pairs with direct calls, I get this result:
objdump -d bin/kernel.bin wrote:

Code: Select all

c0000000 <_start>:
c0000000:       bc c0 3f 00 c0          mov    $0xc0003fc0,%esp
        ...
c0000010:       e8 0b 00 00 00          call   c0000020 <kmain>

c0000015 <_kHang>:
c0000015:       f4                      hlt
c0000016:       eb fd                   jmp    c0000015 <_kHang>
        ...

c0000020 <kmain>:
c0000020:       55                      push   %ebp
c0000021:       89 e5                   mov    %esp,%ebp
        ...
greyOne
Member
Member
Posts: 58
Joined: Sun Feb 03, 2013 10:38 pm
Location: Canada

Re: ASM call instruction linking to wrong address.

Post by greyOne »

Icee wrote:I cannot reproduce your issue. Having built with "XCC=i686-elf-gcc XINC=. make", and having fixed a compilation error in kgdt.c (in gdtCommit(), though the code is still wrong, inline assembly is not done like that), and having replaced the leal/call indirect pairs with direct calls, I get this result:
objdump -d bin/kernel.bin wrote:

Code: Select all

c0000000 <_start>:
c0000000:       bc c0 3f 00 c0          mov    $0xc0003fc0,%esp
        ...
c0000010:       e8 0b 00 00 00          call   c0000020 <kmain>

c0000015 <_kHang>:
c0000015:       f4                      hlt
c0000016:       eb fd                   jmp    c0000015 <_kHang>
        ...

c0000020 <kmain>:
c0000020:       55                      push   %ebp
c0000021:       89 e5                   mov    %esp,%ebp
        ...
Hrm. I feel like this might be an issue with GAS on my system. I'll try to rebuild a newer version and see if that solves the issue.
Also, I had no issues with the inline assembly code I use to setup my GDT and IDT. They both functioned correctly, beyond the issues I had with the call instruction.
Icee
Member
Member
Posts: 100
Joined: Wed Jan 08, 2014 8:41 am
Location: Moscow, Russia

Re: ASM call instruction linking to wrong address.

Post by Icee »

greyOne wrote:Also, I had no issues with the inline assembly code I use to setup my GDT and IDT. They both functioned correctly, beyond the issues I had with the call instruction.
The compilation issue was on an older GCC 4.4.3 (I had nothing newer compiled for i686-elf at my workplace), the symbol gdt_commit_end was though to be declared twice. I fixed that by replacing it with a local label 1. This issue also does not reproduce on newer GCC (4.8.2), and on this newer GCC I also cannot reproduce your original bug.

The real problem about gdtCommit() is that you use non-volatile individual __asm__ statements without constraints. The compiler is free to reorder them and/or insert additional operations in between. Something functioning correctly now does not mean it can break later if language rules are ignored.
Post Reply