I'm not relocating. There is no relocation. This is position-independent code. And I'm not using any global addresses (they don't work with the design of my OS) so there's nothing to fix.iansjack wrote:That's fair enough. You just have to add the relocation information to your custom executable format and ensure that your loader does the necessary fixups.
How to compile a flat position-independent binary with GCC?
-
- Member
- Posts: 1146
- Joined: Sat Mar 01, 2014 2:59 pm
Re: How to compile a flat position-independent binary with G
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Re: How to compile a flat position-independent binary with G
I'm confused. I thought you couldn't get the simplest of test programs to compile because of relocation problems with respect to string constants. Have you now solved the problems you were having?onlyonemac wrote:I'm not relocating. There is no relocation. This is position-independent code. And I'm not using any global addresses (they don't work with the design of my OS) so there's nothing to fix.iansjack wrote:That's fair enough. You just have to add the relocation information to your custom executable format and ensure that your loader does the necessary fixups.
-
- Member
- Posts: 1146
- Joined: Sat Mar 01, 2014 2:59 pm
Re: How to compile a flat position-independent binary with G
Yes, I removed the string constants. The final design of my operating system has no need for string constants anyway.iansjack wrote:Have you now solved the problems you were having?
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
-
- Member
- Posts: 1146
- Joined: Sat Mar 01, 2014 2:59 pm
Re: How to compile a flat position-independent binary with G
I'm using this linkscript:This works for code that contains short switch statements, but as soon as I've got a long switch statement, the code crashes as soon as it enters the switch.
Code: Select all
OUTPUT_FORMAT("binary")
OUTPUT_ARCH(i386)
ENTRY(start)
phys = 0x00000000;
SECTIONS
{
.text phys : AT(phys)
{
code = .;
*(.text)
*(.rodata)
. = ALIGN(4096);
}
.got : AT(phys + (_GLOBAL_OFFSET_TABLE_ - code))
{
_GLOBAL_OFFSET_TABLE_ = .;
*(.got)
. = ALIGN(4096);
}
.data : AT(phys + (data - code))
{
data = .;
*(.data)
. = ALIGN(4096);
}
.bss : AT(phys + (bss - code))
{
bss = .;
*(.bss)
. = ALIGN(4096);
}
end = .;
}
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Re: How to compile a flat position-independent binary with G
OUTPUT_FORMAT("binary") with 'ld'
creates a binary which is different from that created by
OUTPUT_FORMAT("elf-i386") with 'ld' and 'objcopy -O binary'
For a sample function containing a long switch statement, the raw binary, created by the latter set of commands (i.e. raw created from elf) had proper values to jump to the correct case.
It may be a similar observation which prompted this comment - "... generating a "binary" file is generally better done using objcopy."
creates a binary which is different from that created by
OUTPUT_FORMAT("elf-i386") with 'ld' and 'objcopy -O binary'
For a sample function containing a long switch statement, the raw binary, created by the latter set of commands (i.e. raw created from elf) had proper values to jump to the correct case.
It may be a similar observation which prompted this comment - "... generating a "binary" file is generally better done using objcopy."
-
- Member
- Posts: 1146
- Joined: Sat Mar 01, 2014 2:59 pm
Re: How to compile a flat position-independent binary with G
Sounds like a bit of a hackish way of generating a raw binary. Does it work for position-independent objects, and does it strip any extra data from the binary beyond the executable code (and global/constant data used by the code)?linuxyne wrote:OUTPUT_FORMAT("binary") with 'ld'
creates a binary which is different from that created by
OUTPUT_FORMAT("elf-i386") with 'ld' and 'objcopy -O binary'
For a sample function containing a long switch statement, the raw binary, created by the latter set of commands (i.e. raw created from elf) had proper values to jump to the correct case.
It may be a similar observation which prompted this comment - "... generating a "binary" file is generally better done using objcopy."
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
-
- Member
- Posts: 1146
- Joined: Sat Mar 01, 2014 2:59 pm
Re: How to compile a flat position-independent binary with G
My ld says target elf-i386 not found.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
-
- Member
- Posts: 1146
- Joined: Sat Mar 01, 2014 2:59 pm
Re: How to compile a flat position-independent binary with G
I tried it with elf32-i386 and objcopy -O binary and it still doesn't work.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Re: How to compile a flat position-independent binary with G
Apologies. I meant elf32-i386, which you correctly guessed later on.onlyonemac wrote:My ld says target elf-i386 not found.
I tested with the commands which I picked from your posts from last year on this thread.onlyonemac wrote:I tried it with elf32-i386 and objcopy -O binary and it still doesn't work.
I did not run the binary, though - only checked the disassembly.
The commands:
Code: Select all
gcc -fPIE -ffreestanding -fno-builtin -nostdlib -nostdinc -m32 -Wl,-Bstatic -Wall -c 1.c -o 1.o
ld -o 1.bin -T 1.ld 1.o
objdump -D -b binary -m i386 1.bin
The source. Please excuse the casting back and forth between int and int *.
Code: Select all
int *process(int a)
{
int s = 0;
switch (a) {
case 0:s = 0;break;
case 11:s = 1;break;
case 22:s = 2;break;
case 33:s = 3;break;
case 44:s = 4;break;
case 55:s = 5;break;
case 66:s = 6;break;
case 77:s = 7;break;
case 88:s = 8;break;
case 99:s = 9;break;
case 101:s = 10;break;
case 112:s = 11;break;
case 123:s = 21;break;
case 134:s = 13;break;
case 145:s = 14;break;
case 156:s = 15;break;
case 167:s = 16;break;
case 178:s = 17;break;
case 189:s = 18;break;
case 190:s = 19;break;
}
return (int *)s;
}
int start(int a)
{
int *s;
s = process(a);
while (1);
return (int)s;
}
Code: Select all
00000000 <.data>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 10 sub $0x10,%esp
6: e8 f5 0f 00 00 call 0x1000
b: 05 5d 20 00 00 add $0x205d,%eax
10: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)
17: 81 7d 08 be 00 00 00 cmpl $0xbe,0x8(%ebp)
1e: 0f 87 d3 00 00 00 ja 0xf7
24: 8b 55 08 mov 0x8(%ebp),%edx
27: c1 e2 02 shl $0x2,%edx
2a: 8b 94 02 b4 e0 ff ff mov -0x1f4c(%edx,%eax,1),%edx
31: 01 d0 add %edx,%eax
33: ff e0 jmp *%eax
35: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)
3c: e9 b6 00 00 00 jmp 0xf7
41: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%ebp)
48: e9 aa 00 00 00 jmp 0xf7
<skip>
148: d9 df (bad)
14a: ff (bad)
14b: ff 8f e0 ff ff 8f decl -0x70000020(%edi)
Code: Select all
00000000 <.data>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 10 sub $0x10,%esp
6: e8 f5 0f 00 00 call 0x1000; returns the return addr. i.e. 0xb
b: 05 5d 20 00 00 add $0x205d,%eax; eax is now 0x2068
10: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp); default return value is 0
17: 81 7d 08 be 00 00 00 cmpl $0xbe,0x8(%ebp); comparison added by the compiler.
1e: 0f 87 d3 00 00 00 ja 0xf7; jump not taken as 11 is less than 0xbe
24: 8b 55 08 mov 0x8(%ebp),%edx; edx becomes 11
27: c1 e2 02 shl $0x2,%edx; edx becomes 44=0x2c
2a: 8b 94 02 b4 e0 ff ff mov -0x1f4c(%edx,%eax,1),%edx;
edx = (0x2c + 0x2068*1 - 0x1f4c)
= (0x148)
= 0xffffdfd9 from the info pasted above.
31: 01 d0 add %edx,%eax;
eax = eax + 0xffffdfd9
= 0x2068 + 0xffffdfd9
= 0x41 after truncation.
33: ff e0 jmp *%eax;
jump to location 0x41, which does return the value 1, as shown in the snippet above.
The disassembly produced by OUTPUT_FORMAT("binary") with 'ld' for the same 1.o is below.
Assuming that process(11) was called,
Code: Select all
00000000 <.data>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 10 sub $0x10,%esp
6: e8 f5 0f 00 00 call 0x1000
b: 05 61 10 00 00 add $0x1061,%eax; eax = 0x1061 + 0xb = 0x106c
10: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)
17: 81 7d 08 be 00 00 00 cmpl $0xbe,0x8(%ebp);
1e: 0f 87 d3 00 00 00 ja 0xf7; jump not taken
24: 8b 55 08 mov 0x8(%ebp),%edx; edx = 11 = 0xb
27: c1 e2 02 shl $0x2,%edx; edx = 0x2c
2a: 8b 94 02 1c 01 00 00 mov 0x11c(%edx,%eax,1),%edx;
edx = (0x2c + 0x106c*1 + 0x11c)
= (0x11b4)
= the address 0x11b4 is outside the binary's size, but since one knows that we need to ultimately jump to 0x41,
(0x11b4) should be
= 0x41 - eax
= 0x41 - 0x106c
= 0xffffefd5, but searching the binary shows no location (such as 0x148 in the previous binary) which
stores 0xffffefd5. Someone more experienced should be able to provide a reason for such a situation.
31: 01 d0 add %edx,%eax
33: ff e0 jmp *%eax
35: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)
3c: e9 b6 00 00 00 jmp 0xf7
41: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%ebp)
48: e9 aa 00 00 00 jmp 0xf7
I think that looking at the disassembly should provide some clues about the cause of your crash.
I did try with constant strings and with global integers, and the difference, in the respective disassembly, between OUTPUT_FORMAT("elf32-i386") with objcopy and OUTPUT_FORMAT("binary") was similar to the one described above for the long switch statement. The plain, raw binary, for some reason, contained code which would not work in fetching the correct string or the correct global variable, though I have not yet spent time finding out the reason that occurs or if I made some error (missing a cmdline arg like -pie, for instance), while the objcopied binary had sensible code, which was already correctly formed when the binary was in its elf32 form.onlyonemac wrote:Sounds like a bit of a hackish way of generating a raw binary. Does it work for position-independent objects, and does it strip any extra data from the binary beyond the executable code (and global/constant data used by the code)?
-
- Member
- Posts: 95
- Joined: Thu Jan 29, 2009 9:13 am
Re: How to compile a flat position-independent binary with G
I don't know what this process function is supposed to do, but that switch statement only covers 1/11 of every input. 11 = 1 , 12 = 0 , 13 = 0 ... 21 = 0 , 22 = 2. If that's desired ignore this part. But far more important is returning a pointer to an automatic variable beyond stack scope is undefined behaviour.linuxyne wrote:Code: Select all
int *process(int a) { int s = 0; switch (a) { case 0:s = 0;break; case 11:s = 1;break; case 22:s = 2;break; case 33:s = 3;break; case 44:s = 4;break; case 55:s = 5;break; case 66:s = 6;break; case 77:s = 7;break; case 88:s = 8;break; case 99:s = 9;break; case 101:s = 10;break; case 112:s = 11;break; case 123:s = 21;break; case 134:s = 13;break; case 145:s = 14;break; case 156:s = 15;break; case 167:s = 16;break; case 178:s = 17;break; case 189:s = 18;break; case 190:s = 19;break; } return (int *)s; } int start(int a) { int *s; s = process(a); while (1); return (int)s; }
Code: Select all
int process(int a)
{
int s = 0;
switch (a) {
case 0:s = 0;break;
case 11:s = 1;break;
case 22:s = 2;break;
case 33:s = 3;break;
case 44:s = 4;break;
case 55:s = 5;break;
case 66:s = 6;break;
case 77:s = 7;break;
case 88:s = 8;break;
case 99:s = 9;break;
case 101:s = 10;break;
case 112:s = 11;break;
case 123:s = 21;break;
case 134:s = 13;break;
case 145:s = 14;break;
case 156:s = 15;break;
case 167:s = 16;break;
case 178:s = 17;break;
case 189:s = 18;break;
case 190:s = 19;break;
}
return s;
}
int start(int a)
{
int s = process(a);
while (1);
return s;
}
Re: How to compile a flat position-independent binary with G
The code is not returning a pointer to an automatic variable.Merlin wrote: But far more important is returning a pointer to an automatic variable beyond stack scope is undefined behaviour.
There is a difference between
Code: Select all
return (int *)s;
Code: Select all
return (int *)&s;
Edit0: Added the difference.
Also, pointers are not messy, and there's no undefined behaviour being invoked, AFAICS.
-
- Member
- Posts: 95
- Joined: Thu Jan 29, 2009 9:13 am
Re: How to compile a flat position-independent binary with G
you are correct, and I apologise. I shall take this as a sign that staying up until 2 does not leave me in the brightest of mind for programming. Time to hit the hay.linuxyne wrote: The code is not returning a pointer to an automatic variable.
Re: How to compile a flat position-independent binary with G
It's for similar reasons I did not want to change (the change you pointed out is the simpler, production-ready version, that is true) what I already had with me - much simpler to copy paste the work already done than to redo it at an hour not suitable for such endeavours.Merlin wrote: I shall take this as a sign that staying up until 2 does not leave me in the brightest of mind for programming. Time to hit the hay.
-
- Member
- Posts: 1146
- Joined: Sat Mar 01, 2014 2:59 pm
Re: How to compile a flat position-independent binary with G
It is now working with objcopy -O binary. I'm not sure why it didn't work earlier.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
-
- Member
- Posts: 1146
- Joined: Sat Mar 01, 2014 2:59 pm
Re: How to compile a flat position-independent binary with G
I'm a bit confused about the linkscript though. Would this linkscript reserve space in the final binary for the global offset table, or would the global offset table "run over" the end of the binary into unallocated memory?
Code: Select all
OUTPUT_FORMAT("elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(start)
SECTIONS
{
. = 0x00000000;
.text : { *(.text) }
.rodata : { *(.rodata) }
. = ALIGN(4096);
.data : { *(.data) }
. = ALIGN(4096);
.bss : { *(.bss) }
. = ALIGN(4096);
_GLOBAL_OFFSET_TABLE_ = .;
. = ALIGN(4096);
}
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing