0

I need to generate some simple obj/o file that would contain my binary procedure body (I need to write some very simple partial assembler)

I need to generate such obj binary that i could use with some linker to link and run this my procedure. I wonder 1) what would be the easiest obj format (I need something that i could link finaly with gcc but if somethink is easier there are as far as i know some tools to convert one obj format to another so i could use thic converter) 2) I wonder what this code generating this obj context would look like - assume that i have binary asm contents to flush into but i need only make the obj "envelope" around it

I even not necessarely need to flush more procedures than one (only one would suffice, in such case i could generate seperate obj for each procedure) but i would like also some code to embedd my exported procedure symbol name and also to embedd names of imported symbols (though it is maybe also not so critical, as i could pass them by arguments_ I m mainly interested for extremal simplicity that would allow me to run this

assume that i have say such data to flush

const int procedure_binary_body_max = 130;

char procedure_binary_body[procedure_binary_body_max]; //130 bytes of procedure body
char* procedure_symbol_name = "sse_dot";

and i need some code to make and save this as an obj file to disk that i could link it with gcc

could someone help with that? very much tnx

3
  • wouldn't be a way to write a translator instead of a partial assembler? The translator would simply translate your input to assembly source which is then conventionally assembled to linkable object file. Commented Jul 7, 2014 at 12:25
  • no, need obj generation, but could be as simple as possible - it shouldnt be too hard but some official documentations scares me, would need some more helpfull hint /snippet or something Commented Jul 7, 2014 at 12:42
  • the assembler can generate object from your translated source Commented Jul 15, 2014 at 21:06

1 Answer 1

0

Note: the following is for linux on amd64, but the same principle would work on i386.

If you don't have a problem with calling external tools (in this case gcc and nasm), you can do it like this:

main.c:

#include <stdio.h>
#include <unistd.h>

void make_obj (const char *filename,
               const char *data,
               size_t length,
               const char *entry_point)
{
    const char *filename_s = "tmp.s";
    const char *filename_bin = "tmp.bin";

    FILE *f;
    char buf[1000];

    // create bin file
    f = fopen (filename_bin, "wb");
    fwrite (data, 1, length, f);
    fclose (f);

    // create assembly wrapper
    f = fopen (filename_s, "w");
    fprintf (f,
             "\t\tsection .text\n"
             "\t\tglobal %s\n"
             "%s:\n"
             "\t\tincbin \"%s\"\n",
             entry_point, entry_point, filename_bin);
    fclose (f);

    // call nasm to convert it to object file
    snprintf (buf, 1000, "nasm -f elf64 -o %s %s", filename, filename_s);
    system (buf);

    unlink (filename_bin);
    unlink (filename_s);
}

void test_add (const char *filename_o, const char *entry_point)
{
    const char *filename_c = "test.c";
    const char *filename_exe = "test";

    FILE *f;
    char buf[1000];

    f = fopen (filename_c, "w");
    fprintf (f,
             "#include <stdio.h>\n"
             "\n"
             "extern int %s (int a, int b);\n"
             "\n"
             "int main () {\n"
             "\tconst int a = 2;\n"
             "\tconst int b = 3;\n"
             "\n"
             "\tint c = %s (a, b);\n"
             "\n"
             "\tprintf (\"%%d + %%d = %%d\\n\", a, b, c);\n"
             "\n"
             "\treturn 0;\n"
             "}\n",
             entry_point, entry_point);
    fclose (f);

    snprintf (buf, 1000, "gcc -o %s %s %s",
              filename_exe, filename_c, filename_o);
    system (buf);

    snprintf (buf, 1000, "./%s", filename_exe);
    system (buf);

    unlink (filename_c);
    unlink (filename_exe);
}

int main ()
{
    const char code[] = {
        0x48, 0x89, 0xF8,            // mov rax,rdi
        0x48, 0x01, 0xF0,            // add rax,rsi
        0xC3                         // ret
    };

    const char *filename_o = "tmp.o";
    const char *entry_point = "add";

    make_obj (filename_o, code, sizeof(code), entry_point);
    test_add (filename_o, entry_point);
    unlink (filename_o);

    return 0;
}

Test it with:

cc -o main main.c
./main

If everything goes well main should generate an object file incorporating the machine code for an integer add function, a C file calling the machine code routine, compile the C file, and run it.

Result should be:

2 + 3 = 5

Comment out the unlink() calls to preserve the intermediate files.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.