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.