[gandalf@winds.org: Trying to figure out a change in latest binutils for linux]

H. J. Lu hjl@lucon.org
Tue Oct 22 14:43:00 GMT 2002


Alan, Any ideas?

Thanks.


H.J.
----- Forwarded message from Byron Stanoszek <gandalf@winds.org> -----

Delivered-To: hjl@localhost.lucon.org
Date: Tue, 22 Oct 2002 16:38:51 -0400 (EDT)
From: Byron Stanoszek <gandalf@winds.org>
To: hjl@lucon.org
Subject: Trying to figure out a change in latest binutils for linux

Hi.. I'm sure you can give me quick info on how to get around this.. so here's
my problem:

I've recently upgraded to the latest binutils - 2.13.90.0.10.

I'm compiling etherboot-2.0.6 (start32.S file included) and 'as' is having a
problem calculating offsets between sections (start32.s assembly file used with
as, included):

---

root@lnxsvr2:.../etherboot-5.0.6/src> as start32.s -o start32.o
start32.s: Assembler messages:
start32.s:147: Warning: indirect ljmp without `*'
start32.s:51: Error: can't resolve `.rodata' {.rodata section} - `_start' {.text section}

---

This worked on an older version of binutils, at least 4 months ago. Any idea?

Thanks!

 -Byron

-- 
Byron Stanoszek                         Ph: (330) 644-3059
Systems Programmer                      Fax: (330) 644-8110
Commercial Timesharing Inc.             Email: byron@comtime.com

-------------- next part --------------
/* #defines because ljmp wants a number, probably gas bug */
/*	.equ	KERN_CODE_SEG,_pmcs-_gdt	*/
#define	KERN_CODE_SEG	0x08
	.equ	KERN_DATA_SEG,_pmds-_gdt
/*	.equ	REAL_CODE_SEG,_rmcs-_gdt	*/
#define	REAL_CODE_SEG	0x18
	.equ	REAL_DATA_SEG,_rmds-_gdt
	.equ	CR0_PE,1

#ifdef	GAS291
#define DATA32 data32;
#define ADDR32 addr32;
#define	LJMPI(x)	ljmp	x
#else
#define DATA32 data32
#define ADDR32 addr32
/* newer GAS295 require #define	LJMPI(x)	ljmp	*x */
#define	LJMPI(x)	ljmp	x
#endif

/*
 * NOTE: if you write a subroutine that is called from C code (gcc/egcs),
 * then you only have to take care of %ebx, %esi, %edi and %ebp.  These
 * registers must not be altered under any circumstance.  All other registers
 * may be clobbered without any negative side effects.  If you don't follow
 * this rule then you'll run into strange effects that only occur on some
 * gcc versions (because the register allocator may use different registers).
 *
 * All the data32 prefixes for the ljmp instructions are necessary, because
 * the assembler emits code with a relocation address of 0.  This means that
 * all destinations are initially negative, which the assembler doesn't grok,
 * because for some reason negative numbers don't fit into 16 bits. The addr32
 * prefixes are there for the same reasons, because otherwise the memory
 * references are only 16 bit wide.  Theoretically they are all superfluous.
 * One last note about prefixes: the data32 prefixes on all call _real_to_prot
 * instructions could be removed if the _real_to_prot function is changed to
 * deal correctly with 16 bit return addresses.  I tried it, but failed.
 */

/**************************************************************************
START - Where all the fun begins....
**************************************************************************/
/* this must be the first thing in the file because we enter from the top */
	.global	_start
_start:
#ifdef PCBIOS
	.global entry16
entry16:
	.code16
	pushw	%ax			/* Save ax */
	pushf				/* Save flags */
/**************************************************************************
This CPU checking code is taken from syslinux. - Ken
Check that no moron is trying to boot Etherboot/32 on a 286 or so.  According
to Intel, the way to check is to see if the high 4 bits of the FLAGS register
are either all stuck at 1 (8086/8088) or all stuck at 0 (286 in real mode), if
not it is a 386 or higher.  A 186/188 behaves like a 8086/8088 in this check.
**************************************************************************/
	pushf				/* Get flags */
	popw	%ax
	andw	$0x0fff,%ax		/* Clear top 4 bits */
	pushw	%ax			/* Load into FLAGS */
	popf
	pushf				/* And load back */
	popw	%ax
	andw	$0xf000,%ax		/* Get top 4 bits */
	cmpw	$0xf000,%ax		/* If set -> 8086/8088 */
	je	not_386
test_286:
	pushf				/* Get flags */
	popw	%ax
	orw	$0xf000,%ax		/* Set top 4 bits */
	pushw	%ax
	popf
	pushf
	popw	%ax
	andw	$0xf000,%ax		/* Get top 4 bits */
	jnz	is_386			/* If not clear -> 386 */
not_386:
	movw	$err_not386_end-err_not386,%cx	/* length of string */
	movw	$err_not386-_start,%si
	movw	$0x0007,%bx		/* page 0, attribute 7 (normal) */
	movb	$0x0e,%ah		/* write char, tty mode */
err_prloop:
	lodsb
	int	$0x10
	loop	err_prloop
	popf				/* Restore flags */
	popw	%ax			/* Restore ax */
	lret
is_386:
	popf				/* Restore flags */
	popw	%ax			/* Restore ax */

/*
 *	Paul Robertson of Locsoft found that if the top half of %esp
 *	contains garbage, it can affect some BIOSes
 */
	andl	$0xffff,%esp
	DATA32 call	_real_to_prot
	.code32
	call	start32
	call	_prot_to_real
	.code16
	lret
#endif
	.globl start32
start32:
	.code32
	cli
/*
 * Save the initial register contents
 */
	movl	%eax, initial_regs+0
	movl	%ebx, initial_regs+4
	movl	%ecx, initial_regs+8
	movl	%edx, initial_regs+12
	movl	%esi, initial_regs+16
	movl	%edi, initial_regs+20
	movl	%esp, initial_regs+24
	movl	%ebp, initial_regs+28

#ifdef LINUXBIOS
	movl	$_estack, %esp
#endif

	/* Load the global descriptor table */
	cs
	lgdt	gdtarg
	/* reload cs */
	ljmp	$KERN_CODE_SEG, $1f
1:
	/* reload other segment registers */
	movl	$KERN_DATA_SEG, %eax
	movl	%eax,%ds
	movl	%eax,%es
	movl	%eax,%ss
	movl	%eax,%fs
	movl	%eax,%gs

	call	main
	/* fall through */

	.globl	exit
exit:
	/* We reset esp to the location just before entering main
	 * instead of relying on the return from main because exit
	 * could have been called from anywhere 
	 */
	movl	initial_regs+24, %esp
	ret
	
	.code32

/**************************************************************************
XSTART - Transfer control to the kernel just loaded
**************************************************************************/
	.globl	xstart
xstart:
	pushl	%ebp
	movl	%esp,%ebp
	pushl	%ebx
	pushl	%esi
	pushl	%edi
	movl	8(%ebp),%eax
	movl	%eax,_execaddr
	movl	12(%ebp),%ebx
	movl	16(%ebp),%ecx	/* bootp record (32bit pointer) */
	shll	$12,%ecx	/* convert to segment:offset form */
	shrw	$12,%cx
	call	_prot_to_real
	.code16
	pushl	%ecx		/* bootp record */
	pushl	%ebx		/* file header */
	movl	$((RELOC<<12)+(1f-RELOC)),%eax
	pushl	%eax
	ADDR32	LJMPI(_execaddr-_start)
1:
	addw	$8,%sp		/* XXX or is this 10 in case of a 16bit "ret" */
	DATA32 call	_real_to_prot
	.code32
	popl	%edi
	popl	%esi
	popl	%ebx
	popl	%ebp
	ret

_execaddr:
	.long	0

#ifdef	IMAGE_MULTIBOOT
/**************************************************************************
XEND - Restart Etherboot from the beginning (from protected mode)
**************************************************************************/
	.globl	xend
xend:
	movl	initial_regs+0,  %eax
	movl	initial_regs+4,  %ebx
	movl	initial_regs+8,  %ecx
	movl	initial_regs+12, %edx
	movl	initial_regs+16, %esi
	movl	initial_regs+20, %edi
	movl	initial_regs+24, %esp
	movl	initial_regs+28, %ebp
	jmp	start32
#endif	/* IMAGE_MULTIBOOT */

/**************************************************************************
SETJMP - Save stack context for non-local goto
**************************************************************************/
	.globl	setjmp
setjmp:
	movl	4(%esp),%ecx
	movl	0(%esp),%edx
	movl	%edx,0(%ecx)
	movl	%ebx,4(%ecx)
	movl	%esp,8(%ecx)
	movl	%ebp,12(%ecx)
	movl	%esi,16(%ecx)
	movl	%edi,20(%ecx)
	movl	%eax,24(%ecx)
	movl	$0,%eax
	ret

/**************************************************************************
LONGJMP - Non-local jump to a saved stack context
**************************************************************************/
	.globl	longjmp
longjmp:
	movl	4(%esp),%edx
	movl	8(%esp),%eax
	movl	0(%edx),%ecx
	movl	4(%edx),%ebx
	movl	8(%edx),%esp
	movl	12(%edx),%ebp
	movl	16(%edx),%esi
	movl	20(%edx),%edi
	cmpl	$0,%eax
	jne	1f
	movl	$1,%eax
1:	movl	%ecx,0(%esp)
	ret

/**************************************************************************
_REAL_TO_PROT - Go from REAL mode to Protected Mode
**************************************************************************/
	.globl	_real_to_prot
_real_to_prot:
	.code16
	cli
	cs
	ADDR32 lgdt	gdtarg-_start
	movl	%cr0,%eax
	orl	$CR0_PE,%eax
	movl	%eax,%cr0		/* turn on protected mode */

	/* flush prefetch queue, and reload %cs:%eip */
	DATA32 ljmp	$KERN_CODE_SEG,$1f
1:
	.code32
	/* reload other segment registers */
	movl	$KERN_DATA_SEG,%eax
	movl	%eax,%ds
	movl	%eax,%es
	movl	%eax,%ss
	addl	$RELOC,%esp		/* Fix up stack pointer */
	xorl	%eax,%eax
	movl	%eax,%fs
	movl	%eax,%gs
	popl	%eax			/* Fix up return address */
	addl	$RELOC,%eax
	pushl	%eax
	ret

/**************************************************************************
_PROT_TO_REAL - Go from Protected Mode to REAL Mode
**************************************************************************/
	.globl	_prot_to_real
_prot_to_real:
	.code32
	popl	%eax
	subl	$RELOC,%eax		/* Adjust return address */
	pushl	%eax
	subl	$RELOC,%esp		/* Adjust stack pointer */
#ifdef	GAS291
	ljmp	$REAL_CODE_SEG,$1f-RELOC	/* jump to a 16 bit segment */
#else
	ljmp	$REAL_CODE_SEG,$1f-_start	/* jump to a 16 bit segment */
#endif	/* GAS291 */
1:
	.code16
	movw	$REAL_DATA_SEG,%ax
	movw	%ax,%ds
	movw	%ax,%ss
	movw	%ax,%es
	movw	%ax,%fs
	movw	%ax,%gs

	/* clear the PE bit of CR0 */
	movl	%cr0,%eax
	andl	$0!CR0_PE,%eax
	movl	%eax,%cr0

	/* make intersegment jmp to flush the processor pipeline
	 * and reload %cs:%eip (to clear upper 16 bits of %eip).
	 */
	DATA32 ljmp	$(RELOC)>>4,$2f-_start
2:
	/* we are in real mode now
	 * set up the real mode segment registers : %ds, $ss, %es
	 */
	movw	%cs,%ax
	movw	%ax,%ds
	movw	%ax,%es
	movw	%ax,%ss
	sti
	DATA32 ret	/* There is a 32 bit return address on the stack */
	.code32

/**************************************************************************
GLOBAL DESCRIPTOR TABLE
**************************************************************************/
	.align	4

_gdt:
gdtarg:
	.word	0x27			/* limit */
	.long	_gdt			/* addr */
	.word	0

_pmcs:
	/* 32 bit protected mode code segment */
	.word	0xffff,0
	.byte	0,0x9f,0xcf,0

_pmds:
	/* 32 bit protected mode data segment */
	.word	0xffff,0
	.byte	0,0x93,0xcf,0

_rmcs:
	/* 16 bit real mode code segment */
	.word	0xffff,(RELOC&0xffff)
	.byte	(RELOC>>16),0x9b,0x00,(RELOC>>24)

_rmds:
	/* 16 bit real mode data segment */
	.word	0xffff,(RELOC&0xffff)
	.byte	(RELOC>>16),0x93,0x00,(RELOC>>24)

	/* The initial register contents */
	.balign 4
initial_regs:
	.fill 8, 4, 0

	.align	4

#ifdef PCBIOS
	.section ".rodata"
err_not386:
	.ascii	"Etherboot/32 requires 386+"
	.byte	0x0d, 0x0a
err_not386_end:
#endif

#ifdef LINUXBIOS
	.section ".bss"
	.p2align 3
	/* allocate a 4K stack in the bss segment */
_stack:
	.space 4096
_estack:
#endif
	
-------------- next part --------------
# 1 "start32.S"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "start32.S"



        .equ KERN_DATA_SEG,_pmds-_gdt


        .equ REAL_DATA_SEG,_rmds-_gdt
        .equ CR0_PE,1
# 44 "start32.S"
        .global _start
_start:

        .global entry16
entry16:
        .code16
        pushw %ax
        pushf







        pushf
        popw %ax
        andw $0x0fff,%ax
        pushw %ax
        popf
        pushf
        popw %ax
        andw $0xf000,%ax
        cmpw $0xf000,%ax
        je not_386
test_286:
        pushf
        popw %ax
        orw $0xf000,%ax
        pushw %ax
        popf
        pushf
        popw %ax
        andw $0xf000,%ax
        jnz is_386
not_386:
        movw $err_not386_end-err_not386,%cx
        movw $err_not386-_start,%si
        movw $0x0007,%bx
        movb $0x0e,%ah
err_prloop:
        lodsb
        int $0x10
        loop err_prloop
        popf
        popw %ax
        lret
is_386:
        popf
        popw %ax





        andl $0xffff,%esp
        data32 call _real_to_prot
        .code32
        call start32
        call _prot_to_real
        .code16
        lret

        .globl start32
start32:
        .code32
        cli



        movl %eax, initial_regs+0
        movl %ebx, initial_regs+4
        movl %ecx, initial_regs+8
        movl %edx, initial_regs+12
        movl %esi, initial_regs+16
        movl %edi, initial_regs+20
        movl %esp, initial_regs+24
        movl %ebp, initial_regs+28






        cs
        lgdt gdtarg

        ljmp $0x08, $1f
1:

        movl $KERN_DATA_SEG, %eax
        movl %eax,%ds
        movl %eax,%es
        movl %eax,%ss
        movl %eax,%fs
        movl %eax,%gs

        call main


        .globl exit
exit:




        movl initial_regs+24, %esp
        ret

        .code32




        .globl xstart
xstart:
        pushl %ebp
        movl %esp,%ebp
        pushl %ebx
        pushl %esi
        pushl %edi
        movl 8(%ebp),%eax
        movl %eax,_execaddr
        movl 12(%ebp),%ebx
        movl 16(%ebp),%ecx
        shll $12,%ecx
        shrw $12,%cx
        call _prot_to_real
        .code16
        pushl %ecx
        pushl %ebx
        movl $((0x94000<<12)+(1f-0x94000)),%eax
        pushl %eax
        addr32 ljmp _execaddr-_start
1:
        addw $8,%sp
        data32 call _real_to_prot
        .code32
        popl %edi
        popl %esi
        popl %ebx
        popl %ebp
        ret

_execaddr:
        .long 0
# 211 "start32.S"
        .globl setjmp
setjmp:
        movl 4(%esp),%ecx
        movl 0(%esp),%edx
        movl %edx,0(%ecx)
        movl %ebx,4(%ecx)
        movl %esp,8(%ecx)
        movl %ebp,12(%ecx)
        movl %esi,16(%ecx)
        movl %edi,20(%ecx)
        movl %eax,24(%ecx)
        movl $0,%eax
        ret




        .globl longjmp
longjmp:
        movl 4(%esp),%edx
        movl 8(%esp),%eax
        movl 0(%edx),%ecx
        movl 4(%edx),%ebx
        movl 8(%edx),%esp
        movl 12(%edx),%ebp
        movl 16(%edx),%esi
        movl 20(%edx),%edi
        cmpl $0,%eax
        jne 1f
        movl $1,%eax
1: movl %ecx,0(%esp)
        ret




        .globl _real_to_prot
_real_to_prot:
        .code16
        cli
        cs
        addr32 lgdt gdtarg-_start
        movl %cr0,%eax
        orl $CR0_PE,%eax
        movl %eax,%cr0


        data32 ljmp $0x08,$1f
1:
        .code32

        movl $KERN_DATA_SEG,%eax
        movl %eax,%ds
        movl %eax,%es
        movl %eax,%ss
        addl $0x94000,%esp
        xorl %eax,%eax
        movl %eax,%fs
        movl %eax,%gs
        popl %eax
        addl $0x94000,%eax
        pushl %eax
        ret




        .globl _prot_to_real
_prot_to_real:
        .code32
        popl %eax
        subl $0x94000,%eax
        pushl %eax
        subl $0x94000,%esp



        ljmp $0x18,$1f-_start

1:
        .code16
        movw $REAL_DATA_SEG,%ax
        movw %ax,%ds
        movw %ax,%ss
        movw %ax,%es
        movw %ax,%fs
        movw %ax,%gs


        movl %cr0,%eax
        andl $0!CR0_PE,%eax
        movl %eax,%cr0




        data32 ljmp $(0x94000)>>4,$2f-_start
2:



        movw %cs,%ax
        movw %ax,%ds
        movw %ax,%es
        movw %ax,%ss
        sti
        data32 ret
        .code32




        .align 4

_gdt:
gdtarg:
        .word 0x27
        .long _gdt
        .word 0

_pmcs:

        .word 0xffff,0
        .byte 0,0x9f,0xcf,0

_pmds:

        .word 0xffff,0
        .byte 0,0x93,0xcf,0

_rmcs:

        .word 0xffff,(0x94000&0xffff)
        .byte (0x94000>>16),0x9b,0x00,(0x94000>>24)

_rmds:

        .word 0xffff,(0x94000&0xffff)
        .byte (0x94000>>16),0x93,0x00,(0x94000>>24)


        .balign 4
initial_regs:
        .fill 8, 4, 0

        .align 4


        .section ".rodata"
err_not386:
        .ascii "Etherboot/32 requires 386+"
        .byte 0x0d, 0x0a
err_not386_end:


More information about the Binutils mailing list