All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tony Ambardar <tony.ambardar@gmail.com>
To: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: bpf@vger.kernel.org, linux-kselftest@vger.kernel.org,
	Andrii Nakryiko <andrii@kernel.org>,
	Eduard Zingerman <eddyz87@gmail.com>,
	Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Martin KaFai Lau <martin.lau@linux.dev>,
	Song Liu <song@kernel.org>,
	Yonghong Song <yonghong.song@linux.dev>,
	John Fastabend <john.fastabend@gmail.com>,
	KP Singh <kpsingh@kernel.org>,
	Stanislav Fomichev <sdf@fomichev.me>, Hao Luo <haoluo@google.com>,
	Jiri Olsa <jolsa@kernel.org>, Mykola Lysenko <mykolal@fb.com>,
	Shuah Khan <shuah@kernel.org>,
	Ilya Leoshkevich <iii@linux.ibm.com>,
	Quentin Monnet <qmo@kernel.org>
Subject: Re: [PATCH bpf-next v2 6/8] libbpf: Support linking bpf objects of either endianness
Date: Mon, 26 Aug 2024 03:56:50 -0700	[thread overview]
Message-ID: <Zsxfcibtf40Ja6mt@kodidev-ubuntu> (raw)
In-Reply-To: <CAEf4BzZ8Dh3oFm_EeU3btQ4B+WCkaoxwc7iD3CskthTMX0rh9g@mail.gmail.com>

On Fri, Aug 23, 2024 at 12:47:52PM -0700, Andrii Nakryiko wrote:
> On Thu, Aug 22, 2024 at 2:25 AM Tony Ambardar <tony.ambardar@gmail.com> wrote:
> >
> > From: Tony Ambardar <tony.ambardar@gmail.com>
> >
> > Allow static linking object files of either endianness, checking that input
> > files have consistent byte-order, and setting output endianness from input.
> >
> > Linking requires in-memory processing of programs, relocations, sections,
> > etc. in native endianness, and output conversion to target byte-order. This
> > is enabled by built-in ELF translation and recent BTF/BTF.ext endianness
> > functions. Further add local functions for swapping byte-order of sections
> > containing BPF insns.
> >
> > Signed-off-by: Tony Ambardar <tony.ambardar@gmail.com>
> > ---
> >  tools/lib/bpf/linker.c | 106 ++++++++++++++++++++++++++++++++++-------
> >  1 file changed, 90 insertions(+), 16 deletions(-)
> >
> 
> Mostly just stylistic and code organization nits, the change overall looks good.
> 
> > diff --git a/tools/lib/bpf/linker.c b/tools/lib/bpf/linker.c
> > index 7489306cd6f7..9bf218db443e 100644
> > --- a/tools/lib/bpf/linker.c
> > +++ b/tools/lib/bpf/linker.c
> > @@ -135,6 +135,7 @@ struct bpf_linker {
> >         int fd;
> >         Elf *elf;
> >         Elf64_Ehdr *elf_hdr;
> > +       bool swapped_endian;
> >
> >         /* Output sections metadata */
> >         struct dst_sec *secs;
> > @@ -324,13 +325,8 @@ static int init_output_elf(struct bpf_linker *linker, const char *file)
> >
> >         linker->elf_hdr->e_machine = EM_BPF;
> >         linker->elf_hdr->e_type = ET_REL;
> > -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
> > -       linker->elf_hdr->e_ident[EI_DATA] = ELFDATA2LSB;
> > -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
> > -       linker->elf_hdr->e_ident[EI_DATA] = ELFDATA2MSB;
> > -#else
> > -#error "Unknown __BYTE_ORDER__"
> > -#endif
> > +       /* Set unknown ELF endianness, assign later from input files */
> > +       linker->elf_hdr->e_ident[EI_DATA] = ELFDATANONE;
> >
> >         /* STRTAB */
> >         /* initialize strset with an empty string to conform to ELF */
> > @@ -541,19 +537,21 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
> >                                 const struct bpf_linker_file_opts *opts,
> >                                 struct src_obj *obj)
> >  {
> > -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
> > -       const int host_endianness = ELFDATA2LSB;
> > -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
> > -       const int host_endianness = ELFDATA2MSB;
> > -#else
> > -#error "Unknown __BYTE_ORDER__"
> > -#endif
> >         int err = 0;
> >         Elf_Scn *scn;
> >         Elf_Data *data;
> >         Elf64_Ehdr *ehdr;
> >         Elf64_Shdr *shdr;
> >         struct src_sec *sec;
> > +       unsigned char obj_byteorder;
> > +       unsigned char *link_byteorder = &linker->elf_hdr->e_ident[EI_DATA];
> 
> nit: not a fan of pointer into e_ident, just read local value of byte
> order, and then assign it directly below (it's only in one of the
> branches, no duplication, really)

Yes, it's awkward. Fixed.

> 
> > +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
> > +       const unsigned char host_byteorder = ELFDATA2LSB;
> > +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
> > +       const unsigned char host_byteorder = ELFDATA2MSB;
> > +#else
> > +#error "Unknown __BYTE_ORDER__"
> > +#endif
> >
> >         pr_debug("linker: adding object file '%s'...\n", filename);
> >
> > @@ -579,11 +577,25 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
> >                 pr_warn_elf("failed to get ELF header for %s", filename);
> >                 return err;
> >         }
> > -       if (ehdr->e_ident[EI_DATA] != host_endianness) {
> > +
> > +       /* Linker output endianness set by first input object */
> > +       obj_byteorder = ehdr->e_ident[EI_DATA];
> > +       if (obj_byteorder != ELFDATA2LSB && obj_byteorder != ELFDATA2MSB) {
> >                 err = -EOPNOTSUPP;
> > -               pr_warn_elf("unsupported byte order of ELF file %s", filename);
> > +               pr_warn("linker: unknown byte order of ELF file %s\n", filename);
> >                 return err;
> >         }
> > +       if (*link_byteorder == ELFDATANONE) {
> > +               *link_byteorder = obj_byteorder;
> 
> see above, I'd prefer:
> 
> linker->elf_hdr->e_ident[EI_DATA] = obj_byteorder;
> 

Done.

> > +               linker->swapped_endian = obj_byteorder != host_byteorder;
> > +               pr_debug("linker: set %s-endian output byte order\n",
> > +                        obj_byteorder == ELFDATA2MSB ? "big" : "little");
> > +       } else if (*link_byteorder != obj_byteorder) {
> > +               err = -EOPNOTSUPP;
> > +               pr_warn("linker: byte order mismatch with ELF file %s\n", filename);
> > +               return err;
> > +       }
> > +
> >         if (ehdr->e_type != ET_REL
> >             || ehdr->e_machine != EM_BPF
> >             || ehdr->e_ident[EI_CLASS] != ELFCLASS64) {
> > @@ -1111,6 +1123,27 @@ static bool sec_content_is_same(struct dst_sec *dst_sec, struct src_sec *src_sec
> >         return true;
> >  }
> >
> > +static bool is_exec_sec(struct dst_sec *sec)
> > +{
> > +       if (!sec || sec->ephemeral)
> > +               return false;
> > +       return (sec->shdr->sh_type == SHT_PROGBITS) &&
> > +              (sec->shdr->sh_flags & SHF_EXECINSTR);
> > +}
> > +
> > +static int exec_sec_bswap(void *raw_data, int size)
> > +{
> > +       const int insn_cnt = size / sizeof(struct bpf_insn);
> > +       struct bpf_insn *insn = raw_data;
> > +       int i;
> > +
> > +       if (size % sizeof(struct bpf_insn))
> > +               return -EINVAL;
> > +       for (i = 0; i < insn_cnt; i++, insn++)
> > +               bpf_insn_bswap(insn);
> > +       return 0;
> > +}
> > +
> >  static int extend_sec(struct bpf_linker *linker, struct dst_sec *dst, struct src_sec *src)
> >  {
> >         void *tmp;
> > @@ -1170,6 +1203,16 @@ static int extend_sec(struct bpf_linker *linker, struct dst_sec *dst, struct src
> >                 memset(dst->raw_data + dst->sec_sz, 0, dst_align_sz - dst->sec_sz);
> >                 /* now copy src data at a properly aligned offset */
> >                 memcpy(dst->raw_data + dst_align_sz, src->data->d_buf, src->shdr->sh_size);
> > +
> > +               /* convert added bpf insns to native byte-order */
> > +               if (linker->swapped_endian && is_exec_sec(dst)) {
> > +                       err = exec_sec_bswap(dst->raw_data + dst_align_sz,
> > +                                            src->shdr->sh_size);
> 
> nit: I think exec_sec_bswap() shouldn't ever fail, so given we have
> is_exec_sec() now, let's do the size alignment check early on (and
> regardless of swapped_endian), and then just proceed with byte swap
> that can't fail

Looking more closely, I see we already have this size check from:
32fa058398 ("libbpf: Add pr_warn() for EINVAL cases in linker_sanity_check_elf")

So can just drop the error-handling.
> 
> > +                       if (err) {
> > +                               pr_warn("%s: error changing insns endianness\n", __func__);
> > +                               return err;
> > +                       }
> > +               }
> >         }
> >
> >         dst->sec_sz = dst_final_sz;
> > @@ -2630,6 +2673,14 @@ int bpf_linker__finalize(struct bpf_linker *linker)
> >                 if (!sec->scn)
> >                         continue;
> >
> > +               /* restore sections with bpf insns to target byte-order */
> > +               if (linker->swapped_endian && is_exec_sec(sec)) {
> > +                       err = exec_sec_bswap(sec->raw_data, sec->sec_sz);
> 
> and here we'll know that size is validly aligned anyways, so no checks required
> 
> > +                       if (err) {
> > +                               pr_warn("error finalizing insns endianness\n");
> > +                               return libbpf_err(err);
> > +                       }
> > +               }
> >                 sec->data->d_buf = sec->raw_data;
> >         }
> >
> > @@ -2696,6 +2747,13 @@ static int emit_elf_data_sec(struct bpf_linker *linker, const char *sec_name,
> >         return 0;
> >  }
> >
> > +static enum btf_endianness
> > +linker_btf_endianness(const struct bpf_linker *linker)
> > +{
> > +       unsigned char byteorder = linker->elf_hdr->e_ident[EI_DATA];
> 
> empty line between variable declaration and the rest of the code
> 
> > +       return byteorder == ELFDATA2MSB ? BTF_BIG_ENDIAN : BTF_LITTLE_ENDIAN;
> > +}
> > +
> 
> but actually, this whole helper function seems unnecessary, just do
> everything inside finalize_btf, it's a pretty trivial piece of logic

OK, merged as it's not complicated.

> 
> >  static int finalize_btf(struct bpf_linker *linker)
> >  {
> >         LIBBPF_OPTS(btf_dedup_opts, opts);
> > @@ -2742,6 +2800,22 @@ static int finalize_btf(struct bpf_linker *linker)
> >                 return err;
> >         }
> >
> > +       /* Set .BTF and .BTF.ext output byte order */
> > +       err = btf__set_endianness(linker->btf,
> > +                                 linker_btf_endianness(linker));
> > +       if (err) {
> > +               pr_warn("failed to set .BTF output endianness: %d\n", err);
> 
> nit: you used "linker: " prefix for messages like this, stay consistent?

Right, original code used extra "linker:" detail only for "debug" messages
and not "warn" level. Changed to do the same. Thanks!

> 
> 
> > +               return err;
> > +       }
> > +       if (linker->btf_ext) {
> > +               err = btf_ext__set_endianness(linker->btf_ext,
> > +                                             linker_btf_endianness(linker));
> > +               if (err) {
> > +                       pr_warn("failed to set .BTF.ext output endianness: %d\n", err);
> > +                       return err;
> > +               }
> > +       }
> > +
> >         /* Emit .BTF section */
> >         raw_data = btf__raw_data(linker->btf, &raw_sz);
> >         if (!raw_data)
> > --
> > 2.34.1
> >

  reply	other threads:[~2024-08-26 10:56 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-08-22  9:24 [PATCH bpf-next v2 0/8] libbpf, selftests/bpf: Support cross-endian usage Tony Ambardar
2024-08-22  9:24 ` [PATCH bpf-next v2 1/8] libbpf: Improve log message formatting Tony Ambardar
2024-08-22 23:36   ` Andrii Nakryiko
2024-08-26 10:51     ` Tony Ambardar
2024-08-22  9:24 ` [PATCH bpf-next v2 2/8] libbpf: Fix header comment typos for BTF.ext Tony Ambardar
2024-08-22  9:24 ` [PATCH bpf-next v2 3/8] libbpf: Fix output .symtab byte-order during linking Tony Ambardar
2024-08-22  9:24 ` [PATCH bpf-next v2 4/8] libbpf: Support BTF.ext loading and output in either endianness Tony Ambardar
2024-08-22 23:36   ` Andrii Nakryiko
2024-08-23 19:47     ` Andrii Nakryiko
2024-08-22  9:24 ` [PATCH bpf-next v2 5/8] libbpf: Support opening bpf objects of " Tony Ambardar
2024-08-23 19:47   ` Andrii Nakryiko
2024-08-26 10:53     ` Tony Ambardar
2024-08-26 21:28       ` Andrii Nakryiko
2024-08-27  8:40         ` Tony Ambardar
2024-08-22  9:24 ` [PATCH bpf-next v2 6/8] libbpf: Support linking " Tony Ambardar
2024-08-23 19:47   ` Andrii Nakryiko
2024-08-26 10:56     ` Tony Ambardar [this message]
2024-08-22  9:24 ` [PATCH bpf-next v2 7/8] libbpf: Support creating light skeleton " Tony Ambardar
2024-08-23 19:47   ` Andrii Nakryiko
2024-08-26 10:58     ` Tony Ambardar
2024-08-26 21:25       ` Andrii Nakryiko
2024-08-27  8:42         ` Tony Ambardar
2024-08-22  9:24 ` [PATCH bpf-next v2 8/8] selftests/bpf: Support cross-endian building Tony Ambardar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Zsxfcibtf40Ja6mt@kodidev-ubuntu \
    --to=tony.ambardar@gmail.com \
    --cc=andrii.nakryiko@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=haoluo@google.com \
    --cc=iii@linux.ibm.com \
    --cc=john.fastabend@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=kpsingh@kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=martin.lau@linux.dev \
    --cc=mykolal@fb.com \
    --cc=qmo@kernel.org \
    --cc=sdf@fomichev.me \
    --cc=shuah@kernel.org \
    --cc=song@kernel.org \
    --cc=yonghong.song@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.