Page 5 of 6

Re: How to compile a flat position-independent binary with G

Posted: Wed Nov 11, 2015 8:28 am
by onlyonemac
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.
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.

Re: How to compile a flat position-independent binary with G

Posted: Wed Nov 11, 2015 8:58 am
by iansjack
onlyonemac wrote:
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.
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.
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?

Re: How to compile a flat position-independent binary with G

Posted: Wed Nov 11, 2015 9:02 am
by onlyonemac
iansjack wrote:Have you now solved the problems you were having?
Yes, I removed the string constants. The final design of my operating system has no need for string constants anyway.

Re: How to compile a flat position-independent binary with G

Posted: Mon Jul 18, 2016 6:28 am
by onlyonemac
I'm using this linkscript:

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 = .;
}
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.

Re: How to compile a flat position-independent binary with G

Posted: Mon Jul 18, 2016 11:07 am
by linuxyne
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."

Re: How to compile a flat position-independent binary with G

Posted: Mon Jul 18, 2016 2:05 pm
by onlyonemac
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."
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)?

Re: How to compile a flat position-independent binary with G

Posted: Mon Jul 18, 2016 2:09 pm
by onlyonemac
My ld says target elf-i386 not found.

Re: How to compile a flat position-independent binary with G

Posted: Mon Jul 18, 2016 2:38 pm
by onlyonemac
I tried it with elf32-i386 and objcopy -O binary and it still doesn't work.

Re: How to compile a flat position-independent binary with G

Posted: Mon Jul 18, 2016 11:36 pm
by linuxyne
onlyonemac wrote:My ld says target elf-i386 not found.
Apologies. I meant elf32-i386, which you correctly guessed later on.
onlyonemac wrote:I tried it with elf32-i386 and objcopy -O binary and it still doesn't work.
I tested with the commands which I picked from your posts from last year on this thread.
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
I did try a sample with -pie given to the linker, but that did not show any difference for that sample.

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;
}
The disassembly produced by OUTPUT_FORMAT("elf32-i386") with 'ld' and 'objcopy -O binary'

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)
If process(int a) were to receive a=11 decimal, below showed that the above binary would have correctly returned 1.

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.
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)?
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.

Re: How to compile a flat position-independent binary with G

Posted: Tue Jul 19, 2016 12:32 am
by AndrewBuckley
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;
}
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.

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;
}
accomplishes the same thing, without undefined behaviour, or messy pointers

Re: How to compile a flat position-independent binary with G

Posted: Tue Jul 19, 2016 12:35 am
by linuxyne
Merlin wrote: But far more important is returning a pointer to an automatic variable beyond stack scope is undefined behaviour.
The code is not returning a pointer to an automatic variable.

There is a difference between

Code: Select all

return (int *)s;
and

Code: Select all

return (int *)&s;

Edit0: Added the difference.
Also, pointers are not messy, and there's no undefined behaviour being invoked, AFAICS.

Re: How to compile a flat position-independent binary with G

Posted: Tue Jul 19, 2016 12:41 am
by AndrewBuckley
linuxyne wrote: The code is not returning a pointer to an automatic variable.
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.

Re: How to compile a flat position-independent binary with G

Posted: Tue Jul 19, 2016 12:46 am
by linuxyne
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.
:) 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.

Re: How to compile a flat position-independent binary with G

Posted: Tue Jul 19, 2016 2:13 am
by onlyonemac
It is now working with objcopy -O binary. I'm not sure why it didn't work earlier.

Re: How to compile a flat position-independent binary with G

Posted: Tue Jul 19, 2016 3:31 am
by onlyonemac
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);
}