How to Make Gcc Compile the .Text Section as Writable in an Elf Binary

Make text segment writable, ELF

For the answer below, I'm going to use this test program:

#include <stdio.h>
#include <stdlib.h>

int
main (int argc, char **argv)
{
printf ("Hello world\n");
void *m = main;
*((char *) m) = 0;
exit (0);
}

Compile with:

$ gcc -g -o test test.c

As expected:

$ gdb test
...
(gdb) run
Starting program: /home/amb/so/test
Hello world

Program received signal SIGSEGV, Segmentation fault.
0x00000000004005a2 in main (argc=1, argv=0x7fffffffe628) at test.c:9
9 *((char *)m) = 0;
(gdb)

The obvious route here is to use the -Wl flag to gcc to pass -N or (aka --omagic) to the linker, i.e. gcc ... -Wl,--omagic ..., though this may have other undesirable results (e.g. disabling shared libraries). From the man page:

   -N
--omagic
Set the text and data sections to be readable and writable. Also, do not page-align the
data segment, and disable linking against shared libraries. If the output format
supports Unix style magic numbers, mark the output as "OMAGIC". Note: Although a
writable text section is allowed for PE-COFF targets, it does not conform to the format
specification published by Microsoft.

Let's give that a go:

$ gcc --static -g -Wl,--omagic -o test test.c
$ ./test
Hello world
$

That works fine, but you've lost dynamic library support.

To keep dynamic library support, and retain a writable text segment, you should be able to use:

objcopy --writable-text ...

From the man page:

   --writable-text
Mark the output text as writable. This option isn't meaningful for all object file
formats.

This ought to work, but doesn't, as objdump will verify. So here's a solution that gets a bit further than --writable-text which as OP has stated in the comments does not appear to do what it says on the tin^Wmanpage.

Let's see how the sections are marked:

$ gcc -g -o test test.
$ objdump -h test | fgrep -A1 .text
12 .text 00000192 0000000000400490 0000000000400490 00000490 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE

Now let's get rid of that READONLY flag:

$ objcopy --set-section-flags .text=contents,alloc,load,code test test1
$ objdump -h test1 | fgrep -A1 .text
12 .text 00000192 0000000000400490 0000000000400490 00000490 2**4
CONTENTS, ALLOC, LOAD, CODE

and now READONLY has gone, as requested.

But:

 $ gdb test1
...
(gdb) run
Starting program: /home/amb/so/test1
Hello world

Program received signal SIGSEGV, Segmentation fault.
0x00000000004005a2 in main (argc=1, argv=0x7fffffffe628) at test.c:9
9 *((char *)m) = 0;
(gdb)

I suspect the issue here is that something else other than the ELF section name is making the section read-only when actually loaded. Which is probably why people are suggesting you use mprotect. Sorry not to have been more help.

Objcopy --writable-text not making elf binary text section writable?

On going through the objcopy man pages for this particular option is is mentioned that the option is not meaningful for all the binary formats. (Is this the reason I am not able to do so ?).

Yes.

At this rather detailed description of special sections of the ELF format, you see that .text has the SHF_ALLOC + SHF_EXECINSTR attributes (has space allocated for it and the space has executable code in it), but not SHF_WRITE (space can be written to). What you are asking objcopy to do simply isn't valid for ELF .text sections.

Allocate writable memory in the .text section

If you want to allocate memory at runtime, reserve some space on the stack with sub rsp, 4096 or something. Or run an mmap system call or call malloc from libc, if you linked against libc.


If you want to test shellcode / self-modifying code,

or have some other reason for have a writeable .text:

Link with ld --omagic or gcc -Wl,--omagic. From the ld(1) man page:

-N

--omagic

Set the text and data sections to be readable and writable. Also, do not page-align the data segment, and disable linking against shared
libraries. If the output format supports Unix style magic numbers, mark the output as "OMAGIC".

See also How can I make GCC compile the .text section as writable in an ELF binary?


Or probably you can use a linker script. It might also be possible to use NASM section attribute stuff to declare a custom section that has read, write, exec permission.

There's normally (outside of shellcode testing) no reason to do any of this, just put your static storage in .data or .bss, and your static read-only data in .rodata like a normal person.

Putting read/write data near code is actively bad for performance: possible pipeline nukes from the hardware that detects self-modifying-code, and it at least pollutes the iTLB with data and the dTLB with code, if you have a page that includes some of both instead of being full of one or the other.

How to write informations needed in an executable file

Here is a quick solution.String literals in a c/c++ program, are usually put into the read-only segment of the ELF file.

Assuming that your comment follows a pattern:

My_Comment: .... 

you could add some string definitions in your program:

#include <stdio.h>

void main() {

char* a = "My Comment: ...";
}

compile:

$ gcc test.c

and then search for your comment pattern in the executable:

$ strings a.out | grep Comment
My Comment: ...

may I ask what is the use case of embedding comments into an executable?

Follow up:

If you are compiling with the -O3 flag, this unused string is optimized out, so it is not stored at all in the ro data. Based on the same idea, you could fool gcc by:

#include <stdio.h>

void main() {

FILE* comment = fopen("/dev/null", "w");
fprintf(comment, "My Comment:");
}

Then search for your comment. You get the overhead of 2 or 3 system calls of course, but hopefully you can live with it.

Let me know if this works!

Modifying Linker Script to make the .text section writable, errors

In Linux, you can use mprotect() to enable/disable text section write protection from the runtime code; see the Notes section in man 2 mprotect.

Here is a real-world example. First, however, a caveat:

I consider this just a proof of concept implementation, and not something I'd ever use in a real world application. It may look enticing for use in a high-performance library of some sort, but in my experience, changing the API (or the paradigm/approach) of the library usually yields much better results -- and fewer hard-to-debug bugs.

Consider the following six files:


foo1.c:

int foo1(const int a, const int b) { return a*a - 2*a*b + b*b; }

foo2.c:

int foo2(const int a, const int b) { return a*a + b*b; }

foo.h.header:

#ifndef   FOO_H
#define FOO_H

extern int foo1(const int a, const int b);

extern int foo2(const int a, const int b);

foo.h.footer:

#endif /* FOO_H */

main.c:

#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>

#include <string.h>
#include <stdio.h>
#include "foo.h"

int text_copy(const void *const target,
const void *const source,
const size_t length)
{
const long page = sysconf(_SC_PAGESIZE);
void *start = (char *)target - ((long)target % page);
size_t bytes = length + (size_t)((long)target % page);

/* Verify sane page size. */
if (page < 1L)
return errno = ENOTSUP;

/* Although length should not need to be a multiple of page size,
* adjust it up if need be. */
if (bytes % (size_t)page)
bytes = bytes + (size_t)page - (bytes % (size_t)page);

/* Disable write protect on target pages. */
if (mprotect(start, bytes, PROT_READ | PROT_WRITE | PROT_EXEC))
return errno;

/* Copy code.
* Note: if the target code is being executed, we're in trouble;
* this offers no atomicity guarantees, so other threads may
* end up executing some combination of old/new code.
*/
memcpy((void *)target, (const void *)source, length);

/* Re-enable write protect on target pages. */
if (mprotect(start, bytes, PROT_READ | PROT_EXEC))
return errno;

/* Success. */
return 0;
}

int main(void)
{
printf("foo1(): %d bytes at %p\n", foo1_SIZE, foo1_ADDR);
printf("foo2(): %d bytes at %p\n", foo2_SIZE, foo2_ADDR);

printf("foo1(3, 5): %d\n", foo1(3, 5));
printf("foo2(3, 5): %d\n", foo2(3, 5));

if (foo2_SIZE < foo1_SIZE) {
printf("Replacing foo1() with foo2(): ");
if (text_copy(foo1_ADDR, foo2_ADDR, foo2_SIZE)) {
printf("%s.\n", strerror(errno));
return 1;
}
printf("Done.\n");
} else {
printf("Replacing foo2() with foo1(): ");
if (text_copy(foo2_ADDR, foo1_ADDR, foo1_SIZE)) {
printf("%s.\n", strerror(errno));
return 1;
}
printf("Done.\n");
}

printf("foo1(3, 5): %d\n", foo1(3, 5));
printf("foo2(3, 5): %d\n", foo2(3, 5));

return 0;
}

function-info.bash:

#!/bin/bash

addr_prefix=""
addr_suffix="_ADDR"

size_prefix=""
size_suffix="_SIZE"

export LANG=C
export LC_ALL=C

nm -S "$@" | while read addr size kind name dummy ; do
[ -n "$addr" ] || continue
[ -n "$size" ] || continue
[ -z "$dummy" ] || continue
[ "$kind" = "T" ] || continue
[ "$name" != "${name#[A-Za-z]}" ] || continue
printf '#define %s ((void *)0x%sL)\n' "$addr_prefix$name$addr_suffix" "$addr"
printf '#define %s %d\n' "$size_prefix$name$size_suffix" "0x$size"
done || exit $?

Remember to make it executable using chmod u+x ./function-info.bash


First, compile the sources using valid sizes but invalid addresses:

gcc -W -Wall -O3 -c foo1.c
gcc -W -Wall -O3 -c foo2.c
( cat foo.h.header ; ./function-info.bash foo1.o foo2.o ; cat foo.h.footer) > foo.h
gcc -W -Wall -O3 -c main.c

The sizes are correct but the addresses are not, because the code is yet to be linked. Relative to the final binary, the object file contents are usually relocated at link time. So, link the sources to get example executable, example:

gcc -W -Wall -O3 main.o foo1.o foo2.o -o example

Extract the correct (sizes and) addresses:

( cat foo.h.header ; ./function-info.bash example ; cat foo.h.footer) > foo.h

Recompile and link,

gcc -W -Wall -O3 -c main.c
gcc -W -Wall -O3 foo1.o foo2.o main.o -o example

and verify that the constants now do match:

mv -f foo.h foo.h.used
( cat foo.h.header ; ./function-info.bash example ; cat foo.h.footer) > foo.h
cmp -s foo.h foo.h.used && echo "Done." || echo "Recompile and relink."

Due to high optimization (-O3) the code that utilizes the constants may change size, requiring a yet another recompile-relink. If the last line outputs "Recompile and relink", just repeat the last two steps, i.e. five lines.

(Note that since foo1.c and foo2.c do not use the constants in foo.h, they obviously do not need to be recompiled.)

On x86_64 (GCC-4.6.3-1ubuntu5), running ./example outputs

foo1(): 21 bytes at 0x400820
foo2(): 10 bytes at 0x400840
foo1(3, 5): 4
foo2(3, 5): 34
Replacing foo1() with foo2(): Done.
foo1(3, 5): 34
foo2(3, 5): 34

which shows that the foo1() function indeed was replaced. Note that the longer function is always replaced with the shorter one, because we must not overwrite any code outside the two functions.

You can modify the two functions to verify this; just remember to repeat the entire procedure (so that you use the correct _SIZE and _ADDR constants in main()).

Just for giggles, here is the generated foo.h for the above:

#ifndef   FOO_H
#define FOO_H

extern int foo1(const int a, const int b);

extern int foo2(const int a, const int b);
#define foo1_ADDR ((void *)0x0000000000400820L)
#define foo1_SIZE 21
#define foo2_ADDR ((void *)0x0000000000400840L)
#define foo2_SIZE 10
#define main_ADDR ((void *)0x0000000000400610L)
#define main_SIZE 291
#define text_copy_ADDR ((void *)0x0000000000400850L)
#define text_copy_SIZE 226
#endif /* FOO_H */

You might wish to use a smarter scriptlet, say an awk one that uses nm -S to obtain all function names, addresses, and sizes, and in the header file replaces only the values of existing definitions, to generate your header file. I'd use a Makefile and some helper scripts.

Further notes:

  • The function code is copied as-is, no relocation etc. is done. (This means that if the machine code of the replacement function contains absolute jumps, the execution continues in the original code. These example functions were chosen, because they're unlikely to have absolute jumps in them. Run objdump -d foo1.o foo2.o to verify from the assembly.)

    That is irrelevant if you use the example just to investigate how to modify executable code within the running process. However, if you build runtime-function-replacing schemes on top of this example, you may need to use position independent code for the replaced code (see the GCC manual for relevant options for your architecture) or do your own relocation.

  • If another thread or signal handler executes the code being modified, you're in serious trouble. You get undefined results. Unfortunately, some libraries start extra threads, which may not block all possible signals, so be extra careful when modifying code that might be run by a signal handler.

  • Do not assume the compiler compiles the code in a specific way or uses a specific organization. My example uses separate compilation units, to avoid the cases where the compiler might share code between similar functions.

    Also, it examines the final executable binary directly, to obtain the sizes and addresses to be modified to modify an entire function implementation. All verifications should be done on the object files or final executable, and disassembly, instead of just looking at the C code.

  • Putting any code that relies on the address and size constants into a separate compilation unit makes it easier and faster to recompile and relink the binary. (You only need to recompile the code that uses the constants directly, and you can even use less optimization for that code, to eliminate extra recompile-relink cycles, without impacting the overall code quality.)

  • In my main.c, both the address and length supplied to mprotect() are page-aligned (based on the user parameters). The documents say only the address has to be. Since protections are page-granular, making sure the length is a multiple of the page size does not hurt.

  • You can read and parse /proc/self/maps (which is a kernel-generated pseudofile; see man 5 proc, /proc/[pid]/maps section, for further info) to obtain the existing mappings and their protections for the current process.

In any case, if you have any questions, I'd be happy to try and clarify the above.


Addendum:

It turns out that using the GNU extension dl_iterate_phdr() you can enable/disable write protection on all text sections trivially:

#define  _GNU_SOURCE
#include <unistd.h>
#include <dlfcn.h>
#include <sys/mman.h>
#include <link.h>

static int do_write_protect_text(struct dl_phdr_info *info, size_t size, void *data)
{
const int protect = (data) ? PROT_READ | PROT_EXEC : PROT_READ | PROT_WRITE | PROT_EXEC;
size_t page;
size_t i;

page = sysconf(_SC_PAGESIZE);

if (size < sizeof (struct dl_phdr_info))
return ENOTSUP;

/* Ignore libraries. */
if (info->dlpi_name && info->dlpi_name[0] != '\0')
return 0;

/* Loop over each header. */
for (i = 0; i < (size_t)info->dlpi_phnum; i++)
if ((info->dlpi_phdr[i].p_flags & PF_X)) {
size_t ptr = (size_t)info->dlpi_phdr[i].p_vaddr;
size_t len = (size_t)info->dlpi_phdr[i].p_memsz;

/* Start at the beginning of the relevant page, */
if (ptr % page) {
len += ptr % page;
ptr -= ptr % page;
}

/* and use full pages. */
if (len % page)
len += page - (len % page);

/* Change protections. Ignore unmapped sections. */
if (mprotect((void *)ptr, len, protect))
if (errno != ENOMEM)
return errno;
}

return 0;
}

int write_protect_text(int protect)
{
int result;

result = dl_iterate_phdr(do_write_protect_text, (void *)(long)protect);

if (result)
errno = result;
return result;
}

Here is an example program you can use to test the above write_protect_text() function:

#define  _POSIX_C_SOURCE 200809L

int dump_smaps(void)
{
FILE *in;
char *line = NULL;
size_t size = 0;

in = fopen("/proc/self/smaps", "r");
if (!in)
return errno;

while (getline(&line, &size, in) > (ssize_t)0)
if ((line[0] >= '0' && line[0] <= '9') ||
(line[0] >= 'a' && line[0] <= 'f'))
fputs(line, stdout);

free(line);

if (!feof(in) || ferror(in)) {
fclose(in);
return errno = EIO;
}

if (fclose(in))
return errno = EIO;

return 0;
}

int main(void)
{
printf("Initial mappings:\n");
dump_smaps();

if (write_protect_text(0)) {
fprintf(stderr, "Cannot disable write protection on text sections: %s.\n", strerror(errno));
return EXIT_FAILURE;
}

printf("\nMappings with write protect disabled:\n");
dump_smaps();

if (write_protect_text(1)) {
fprintf(stderr, "Cannot enable write protection on text sections: %s.\n", strerror(errno));
return EXIT_FAILURE;
}

printf("\nMappings with write protect enabled:\n");
dump_smaps();

return EXIT_SUCCESS;
}

The example program dumps /proc/self/smaps before and after changing the text section write protection, showing that it indeed does enable/disable write protectio on all text sections (program code). It does not try to alter write protect on dynamically-loaded libraries. This was tested to work on x86-64 using Ubuntu 3.8.0-35-generic kernel.

How to map the section to the segment from an ELF output file?

Two serious issues cause most of the problems are:

  • You load the second sector of the disk to 0x0000:0x8000 when all of the code expect the kernel to be loaded after the bootloader at 0x0000:0x7e00
  • You compile your kernel.c straight to an executable name kernel.o. You should compile it to a proper object file so it can go through the expected linking phase when you run ld.

To fix the problem with the kernel being loaded into memory at the wrong memory location, change:

mov bx, 0x8000           ; load into es:bx segment :offset of buffer

to:

mov bx, 0x7e00           ; load into es:bx segment :offset of buffer

To fix the issue of compiling kernel.cto an executable ELF file named kernel.o remove the -e kernel_main -Ttext 0x0 and replace it with -c. -c option forces GCC to produce an object file that can be properly linked with LD. Change:

/home/rakesh/Desktop/cross-compiler/i686-elf-4.9.1-Linux-x86_64/bin/i686-elf-gcc -m32 kernel.c -o kernel.o -e kernel_main -Ttext 0x0 -nostdlib -ffreestanding -std=gnu99 -mno-red-zone -fno-exceptions -nostdlib  -Wall -Wextra

to:

/home/rakesh/Desktop/cross-compiler/i686-elf-4.9.1-Linux-x86_64/bin/i686-elf-gcc -m32 -c kernel.c -o kernel.o -nostdlib -ffreestanding -std=gnu99 -mno-red-zone -fno-exceptions -Wall -Wextra

Reason for Failure with Longer Strings

The reason the string with less than 64 bytes worked is because the compiler generated code in a position independent way by initializing the array on the stack with immediate values. When the size reached 64 bytes the compiler placed the string into the .rodata section and then initialized the array on the stack by copying it from the .rodata. This made your code position dependent. Your code was loaded at the wrong offsets and had incorrect origin points yielding code referencing incorrect addresses, so it failed.


Other Observations

  • You should initialize your BSS (.bss) section to 0 before calling kernel_main. This can be done in assembly by iterating through all the bytes from offset _bss_start to offset _bss_end.
  • The .comment section will be emitted into your binary file wasting bytes as a result. You should put it in the /DISCARD/ section.
  • You should place the BSS section in your linker script after all the others so it doesn't take up space in kernel.bin
  • In boot.asm you should set SS:SP (stack pointer) near the beginning before reading disk sectors. It should be set to a place that won't interfere with your code. This is especially important when reading data into memory from disk since you don't know where the BIOS placed the current stack. You don't want to read on top of the current stack area. Setting it just below the bootloader at 0x0000:0x7c00 should work.
  • Before calling into C code you should clear the direction flag to ensure string instructions use forward movement. You can do this by using the CLD instruction.
  • In boot.asmyou can make your code more generic by using the boot drive number passed by the BIOS in the DL register rather than hard coding it to the value 0x80 (0x80 being the first hard drive)
  • You might consider turning on optimization with -O3, or using optimization level -Os to optimize for code size.
  • Your linker script doesn't quite work the way you expect although it produces the correct results. You never declared .boot section in your NASM file so nothing actually gets placed in the .boot1 output section in the linker script. It works because it gets included in the .text section in the .kernel output section.
  • It is preferable to remove the padding and boot signature from the assembly file and move it to the linker script
  • Instead of having your linker script output a binary file directly, it is more useful to output to the default ELF executable format. You can then use OBJCOPY to convert the ELF file to a binary file. This allows you to build with debug information which will appear as part of the ELF executable. The ELF executable can be used to symbolically debug your binary kernel in QEMU.
  • Rather than use LD directly for linking, use GCC. This has the advantage that the libgcc library can be added without specifying the full path to the library. libgcc is a set of routines that may be needed for C code generation with GCC

Revised source code, linker script and build commands with the observations above taken into account:

boot.asm:

bits 16

section .boot

extern kernel_main
extern _bss_start
extern _bss_len

global boot

jmp 0x0000:boot
boot:
; Place realmode stack pointer below bootloader where it doesn't
; get in our way
xor ax, ax
mov ss, ax
mov sp, 0x7c00

mov ah, 0x02 ; load second stage to memory
mov al, 1 ; numbers of sectors to read into memory

; Remove this, DL is already set by BIOS to current boot drive number
; mov dl, 0x80 ; sector read from fixed/usb disk ;0 for floppy; 0x80 for hd
mov ch, 0 ; cylinder number
mov dh, 0 ; head number
mov cl, 2 ; sector number
mov bx, 0x7e00 ; load into es:bx segment :offset of buffer
int 0x13 ; disk I/O interrupt

mov ax, 0x2401
int 0x15 ; enable A20 bit
mov ax, 0x3
int 0x10 ; set vga text mode 3

cli

lgdt [gdt_pointer] ; load the gdt table
mov eax, cr0
or eax,0x1 ; set the protected mode bit on special CPU reg cr0
mov cr0, eax
jmp CODE_SEG:boot2 ; long jump to the code segment

gdt_start:
dq 0x0
gdt_code:
dw 0xFFFF
dw 0x0
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xFFFF
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:

gdt_pointer:
dw gdt_end - gdt_start
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start

bits 32
boot2:
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax

; Zero out the BSS area
cld
mov edi, _bss_start
mov ecx, _bss_len
xor eax, eax
rep stosb

mov esp,kernel_stack_top
call kernel_main

cli
hlt

section .bss
align 4
kernel_stack_bottom: equ $
resb 16384 ; 16 KB
kernel_stack_top:

kernel.c:

void kernel_main(void){
const char string[] = "01234567890123456789012345678901234567890123456789012345678901234";
volatile unsigned char* vid_mem = (unsigned char*) 0xb8000;
int j=0;
while(string[j]!='\0'){

*vid_mem++ = (unsigned char) string[j++];
*vid_mem++ = 0x09;
}

for(;;);

}

linker3.ld:

ENTRY(boot)

SECTIONS{
. = 0x7c00;

.boot1 : {
*(.boot);
}

.sig : AT(0x7dfe){
SHORT(0xaa55);
}

. = 0x7e00;
.kernel : AT(0x7e00){
*(.text);
*(.rodata*);
*(.data);
_bss_start = .;
*(.bss);
*(COMMON);
_bss_end = .;
_bss_len = _bss_end - _bss_start;
}
/DISCARD/ : {
*(.eh_frame);
*(.comment);
}

}

Commands to build this bootloader and kernel:

nasm -g -F dwarf -f elf32 boot.asm -o boot.o
i686-elf-gcc -g -O3 -m32 kernel.c -c -o kernel.o -ffreestanding -std=gnu99 \
-mno-red-zone -fno-exceptions -Wall -Wextra
i686-elf-gcc -nostdlib -Wl,--build-id=none -T linker3.ld boot.o kernel.o \
-lgcc -o kernel.elf
objcopy -O binary kernel.elf kernel.bin

To symbolically debug the 32-bit kernel with QEMU you can launch QEMU this way:

qemu-system-i386 -fda kernel.bin -S -s &
gdb kernel.elf \
-ex 'target remote localhost:1234' \
-ex 'break *kernel_main' \
-ex 'layout src' \
-ex 'continue'

This will start up your kernel.bin file in QEMU and then remotely connect the GDB debugger. The layout should show the source code and break on kernel_main.

Does gcc have any options to add version info in ELF binary file?

You can emit your version info into a text file, then turn that text file into an object file which you then statically link into your executable.

The first step is simple but you have to write some code: a script or something to write your version info in any format you like as a plain text file. Then write a makefile rule to produce say version.o from version.txt, using objcopy. Now you'll have an object file with two useful symbols defined in it: the beginning and end of the textual version info. Add that generated object to your executable, and you'll be able to access the version two ways: by running strings on the binary, or by writing code in the application to print the version string (you'll need to declare the start and end symbols as variables in some header file).

How do I add contents of text file as a section in an ELF file?

This is possible and most easily done using OBJCOPY found in BINUTILS. You effectively take the data file as binary input and then output it to an object file format that can be linked to your program.

OBJCOPY will even produce a start and end symbol as well as the size of the data area so that you can reference them in your code. The basic idea is that you will want to tell it your input file is binary (even if it is text); that you will be targeting an x86-64 object file; specify the input file name and the output file name.

Assume we have an input file called myfile.txt with the contents:

the
quick
brown
fox
jumps
over
the
lazy
dog

Something like this would be a starting point:

objcopy --input binary \
--output elf64-x86-64 \
--binary-architecture i386:x86-64 \
myfile.txt myfile.o

If you wanted to generate 32-bit objects you could use:

objcopy --input binary \
--output elf32-i386 \
--binary-architecture i386 \
myfile.txt myfile.o


Related Topics



Leave a reply



Submit