[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